8 votes

Comment recadrer une UIImageView dans une nouvelle UIImage en mode "aspect fit" ?

enter image description here

Je voudrais créer une nouvelle UIImage en recadrant l'image dans une UIImageView. Par exemple, dans l'image ci-dessus, je veux une nouvelle UIImage de la zone délimitée en vert. J'ai trouvé du code pour faire cela, normalement cela ressemble à quelque chose comme ceci (comme une catégorie d'UIImage) :

- (UIImage *)croppedImage:(CGRect)bounds {
    CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], bounds);
    UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);
    return croppedImage;
}

C'est parfaitement logique. CEPENDANT, mon UIImageView est en contentMode "aspect fit". Il semble que cela complique les calculs CGRect pour CGImageCreateWithImageInRect et je n'ai pas réussi à trouver la bonne solution.

Je suppose que je dois appliquer au rectangle vert les mêmes transformations que celles effectuées sur l'image ?

AUSSI : J'ai trouvé cette autre question ici ( Comment connaître la taille de l'image après avoir appliqué l'ajustement de l'aspect de l'image dans une UIImageView ? ), qui semble montrer une façon brute d'obtenir la taille, mais je ne suis toujours pas sûr de la façon dont cela s'intègre dans une situation de recadrage.

Des idées ?

EDIT : Dans mon cas, j'ai littéralement un carré comme indiqué ci-dessus dessiné dans une vue superposée sur l'UIImageView. Donc, tout en sachant que je recadre l'UIImage (à l'intérieur de la UIImageView), je dois d'une manière ou d'une autre modifier le CGRect vert de façon à ce qu'il " corresponde " à la transformation effectuée lorsque " aspect fit " est appliqué. Par exemple, si je laisse mon UIImageView en mode " supérieur gauche ", tout fonctionne bien, car il existe une correspondance 1:1 entre l'UIImage sous-jacente et l'UIImageView. Le problème du mode " haut gauche " est que l'image entière ne s'affiche pas toujours, car elle peut être plus grande que mon UIImageView.

10voto

phix23 Points 24407

Sur la base de mon autre réponse à une question similaire, j'ai écrit cette méthode pour une catégorie UIImageView :

-(CGRect) cropRectForFrame:(CGRect)frame
{
    NSAssert(self.contentMode == UIViewContentModeScaleAspectFit, @"content mode must be aspect fit");

    CGFloat widthScale = self.bounds.size.width / self.image.size.width;
    CGFloat heightScale = self.bounds.size.height / self.image.size.height;

    float x, y, w, h, offset;
    if (widthScale<heightScale) {
        offset = (self.bounds.size.height - (self.image.size.height*widthScale))/2;
        x = frame.origin.x / widthScale;
        y = (frame.origin.y-offset) / widthScale;
        w = frame.size.width / widthScale;
        h = frame.size.height / widthScale;
    } else {
        offset = (self.bounds.size.width - (self.image.size.width*heightScale))/2;
        x = (frame.origin.x-offset) / heightScale;
        y = frame.origin.y / heightScale;
        w = frame.size.width / heightScale;
        h = frame.size.height / heightScale;
    }
    return CGRectMake(x, y, w, h);
}

Vous pouvez transmettre le cadre de votre rectangle vert (en supposant qu'il s'agit d'une vue secondaire de la vue de l'image) et récupérer le rectangle de coupe pour recadrer l'UIImage. Notez que cela ne fonctionne que pour le mode 'aspect fit' ! Je ne l'ai pas encore testé. Alors, dites-moi si ça marche !

4voto

DNRN Points 617

Je sais que la réponse a déjà été donnée, mais j'ai eu quelques problèmes pour obtenir la solution ci-dessus, alors j'ai voulu poster ma solution aussi.

Le problème est que l'image est mise à l'échelle avec un ajustement d'aspect, mais nous connaissons le facteur d'échelle pour la largeur et la hauteur. Nous pouvons alors calculer le bon rectangle de recadrage assez facilement :

-(UIImage*)crop:(CGRect)frame
{
    // Find the scalefactors  UIImageView's widht and height / UIImage width and height
    CGFloat widthScale = self.bounds.size.width / self.image.size.width;
    CGFloat heightScale = self.bounds.size.height / self.image.size.height;

    // Calculate the right crop rectangle 
    frame.origin.x = frame.origin.x * (1 / widthScale);
    frame.origin.y = frame.origin.y * (1 / heightScale);
    frame.size.width = frame.size.width * (1 / widthScale);
    frame.size.height = frame.size.height * (1 / heightScale);

    // Create a new UIImage
    CGImageRef imageRef = CGImageCreateWithImageInRect(self.image.CGImage, frame);
    UIImage *croppedImage = [UIImage imageWithCGImage:imageRef];
    CGImageRelease(imageRef);

    return croppedImage;
}

1voto

phix23 Points 24407

Je pense que vous ne comprenez pas ce que vous faites. Vous ne pouvez pas "rogner" une UIImageView - seulement des UIImages. Ainsi, votre méthode croppedImage devrait être dans une catégorie UIImage et non pas dans une catégorie UIImageView. Le rectangle de délimitation que vous passez à la méthode de recadrage doit être en relation avec la taille de l'image, et non avec les limites de l'imageview. Peu importe le ContentMode de la vue de l'image, le recadrage de l'image fonctionnera toujours de la même manière. Commencez par récupérer l'image dans la vue de l'image. Ensuite, créez une nouvelle image recadrée à partir de celle-ci et, enfin, définissez l'image recadrée pour la vue de l'image. Cela peut être fait en une seule ligne de code :

imageView.image = [imageView.image croppedImage:rect];

Puisque votre contentMode est "aspect fit", la nouvelle image s'étire automatiquement pour s'adapter au cadre d'affichage. Vous pouvez également essayer de modifier le cadre d'affichage en fonction de la taille de l'image pour éviter les effets de pixellisation.

0voto

user5176302 Points 21

J'utilise la méthode ci-dessous.

-(UIImage *)getNeedImageFrom:(UIImage*)image cropRect:(CGRect)rect
{
   CGSize cropSize = rect.size;
   CGFloat widthScale =  
   image.size.width/self.imageViewOriginal.bounds.size.width;
   CGFloat heightScale = 
   image.size.height/self.imageViewOriginal.bounds.size.height;
   cropSize = CGSizeMake(rect.size.width*widthScale,  
   rect.size.height*heightScale);
   CGPoint  pointCrop = CGPointMake(rect.origin.x*widthScale, 
   rect.origin.y*heightScale);
   rect = CGRectMake(pointCrop.x, pointCrop.y, cropSize.width, 
   cropSize.height);
   CGImageRef subImage = CGImageCreateWithImageInRect(image.CGImage, rect);
   UIImage *croppedImage = [UIImage imageWithCGImage:subImage];
   CGImageRelease(subImage);
   return croppedImage;

   }

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X