Comment recadrer l’UIImage?

Je développe une application dans laquelle je traite l’image en utilisant ses pixels mais dans ce traitement d’image, cela prend beaucoup de temps. Par conséquent, je veux recadrer UIImage (seule partie centrale de l’image, c’est-à-dire supprimer / recadrer la partie bordée de l’image).

- (NSInteger) processImage1: (UIImage*) image { CGFloat width = image.size.width; CGFloat height = image.size.height; struct pixel* pixels = (struct pixel*) calloc(1, image.size.width * image.size.height * sizeof(struct pixel)); if (pixels != nil) { // Create a new bitmap CGContextRef context = CGBitmapContextCreate( (void*) pixels, image.size.width, image.size.height, 8, image.size.width * 4, CGImageGetColorSpace(image.CGImage), kCGImageAlphaPremultipliedLast ); if (context != NULL) { // Draw the image in the bitmap CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, image.size.width, image.size.height), image.CGImage); NSUInteger numberOfPixels = image.size.width * image.size.height; NSMutableArray *numberOfPixelsArray = [[[NSMutableArray alloc] initWithCapacity:numberOfPixelsArray] autorelease]; } 

Comment je prends (en dehors de la bordure) la partie centrale de UIImage ?????????

Essayez quelque chose comme ça:

 CGImageRef imageRef = CGImageCreateWithImageInRect([largeImage CGImage], cropRect); image = [UIImage imageWithCGImage:imageRef]; CGImageRelease(imageRef); 

Remarque: cropRect est un rectangle plus petit avec la partie centrale de l’image …

Je cherchais un moyen d’obtenir un recadrage rectangular arbitraire (par exemple, une sous-image) d’un UIImage.

La plupart des solutions que j’ai essayées ne fonctionnent pas si l’orientation de l’image est autre chose que UIImageOrientationUp.

Par exemple:

http://www.hive05.com/2008/11/crop-an-image-using-the-iphone-sdk/

Généralement, si vous utilisez votre appareil photo iPhone, vous aurez d’autres orientations comme UIImageOrientationLeft, et vous ne pourrez pas obtenir un recadrage correct avec ce qui précède. Cela est dû à l’utilisation de CGImageRef / CGContextDrawImage qui diffèrent dans le système de coordonnées par rapport à UIImage.

Le code ci-dessous utilise les méthodes d’interface utilisateur * (pas de CGImageRef) et je l’ai testé avec des images orientées haut / bas / gauche / droite et cela semble fonctionner correctement.

 // get sub image - (UIImage*) getSubImageFrom: (UIImage*) img WithRect: (CGRect) rect { UIGraphicsBeginImageContext(rect.size); CGContextRef context = UIGraphicsGetCurrentContext(); // translated rectangle for drawing sub image CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, img.size.width, img.size.height); // clip to the bounds of the image context // not ssortingctly necessary as it will get clipped anyway? CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height)); // draw image [img drawInRect:drawRect]; // grab image UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return subImage; }
// get sub image - (UIImage*) getSubImageFrom: (UIImage*) img WithRect: (CGRect) rect { UIGraphicsBeginImageContext(rect.size); CGContextRef context = UIGraphicsGetCurrentContext(); // translated rectangle for drawing sub image CGRect drawRect = CGRectMake(-rect.origin.x, -rect.origin.y, img.size.width, img.size.height); // clip to the bounds of the image context // not ssortingctly necessary as it will get clipped anyway? CGContextClipToRect(context, CGRectMake(0, 0, rect.size.width, rect.size.height)); // draw image [img drawInRect:drawRect]; // grab image UIImage* subImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return subImage; } 

Il serait finalement plus rapide, avec beaucoup moins de création d’images à partir d’atlas sprites, si vous pouviez définir non seulement l’image pour un UIImageView, mais aussi le décalage en haut à gauche à afficher dans cet UIImage. Peut-être que c’est possible. Cela éliminerait certainement beaucoup d’efforts!

Pendant ce temps, j’ai créé ces fonctions utiles dans une classe d’utilitaires que j’utilise dans mes applications. Il crée un UIImage à partir d’une partie d’un autre UIImage, avec des options de rotation, de mise à l’échelle et de retournement à l’aide des valeurs UIImageOrientation standard à spécifier. La mise à l’échelle des pixels est préservée de l’image d’origine.

Mon application crée beaucoup d’images UII pendant l’initialisation, et cela prend nécessairement du temps. Mais certaines images ne sont pas nécessaires jusqu’à ce qu’un certain onglet soit sélectionné. Pour donner l’impression d’une charge plus rapide, je pourrais les créer dans un thread séparé généré au démarrage, puis attendre que cela soit fait lorsque cet onglet est sélectionné.

Ce code est également publié sur le moyen le plus efficace de dessiner une partie d’une image dans iOS

 + (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture { return [ChordCalcController imageByCropping:imageToCrop toRect:aperture withOrientation:UIImageOrientationUp]; } // Draw a full image into a crop-sized area and offset to produce a cropped, rotated image + (UIImage*)imageByCropping:(UIImage *)imageToCrop toRect:(CGRect)aperture withOrientation:(UIImageOrientation)orientation { // convert y coordinate to origin bottom-left CGFloat orgY = aperture.origin.y + aperture.size.height - imageToCrop.size.height, orgX = -aperture.origin.x, scaleX = 1.0, scaleY = 1.0, rot = 0.0; CGSize size; switch (orientation) { case UIImageOrientationRight: case UIImageOrientationRightMirrored: case UIImageOrientationLeft: case UIImageOrientationLeftMirrored: size = CGSizeMake(aperture.size.height, aperture.size.width); break; case UIImageOrientationDown: case UIImageOrientationDownMirrored: case UIImageOrientationUp: case UIImageOrientationUpMirrored: size = aperture.size; break; default: assert(NO); return nil; } switch (orientation) { case UIImageOrientationRight: rot = 1.0 * M_PI / 2.0; orgY -= aperture.size.height; break; case UIImageOrientationRightMirrored: rot = 1.0 * M_PI / 2.0; scaleY = -1.0; break; case UIImageOrientationDown: scaleX = scaleY = -1.0; orgX -= aperture.size.width; orgY -= aperture.size.height; break; case UIImageOrientationDownMirrored: orgY -= aperture.size.height; scaleY = -1.0; break; case UIImageOrientationLeft: rot = 3.0 * M_PI / 2.0; orgX -= aperture.size.height; break; case UIImageOrientationLeftMirrored: rot = 3.0 * M_PI / 2.0; orgY -= aperture.size.height; orgX -= aperture.size.width; scaleY = -1.0; break; case UIImageOrientationUp: break; case UIImageOrientationUpMirrored: orgX -= aperture.size.width; scaleX = -1.0; break; } // set the draw rect to pan the image to the right spot CGRect drawRect = CGRectMake(orgX, orgY, imageToCrop.size.width, imageToCrop.size.height); // create a context for the new image UIGraphicsBeginImageContextWithOptions(size, NO, imageToCrop.scale); CGContextRef gc = UIGraphicsGetCurrentContext(); // apply rotation and scaling CGContextRotateCTM(gc, rot); CGContextScaleCTM(gc, scaleX, scaleY); // draw the image to our clipped context using the offset rect CGContextDrawImage(gc, drawRect, imageToCrop.CGImage); // pull the image from our cropped context UIImage *cropped = UIGraphicsGetImageFromCurrentImageContext(); // pop the context to get back to the default UIGraphicsEndImageContext(); // Note: this is autoreleased return cropped; } 

Parce que j’en avais besoin tout à l’heure, voici le code de MV dans Swift 4:

 func imageWithImage(image: UIImage, croppedTo rect: CGRect) -> UIImage { UIGraphicsBeginImageContext(rect.size) let context = UIGraphicsGetCurrentContext() let drawRect = CGRect(x: -rect.origin.x, y: -rect.origin.y, width: image.size.width, height: image.size.height) context?.clip(to: CGRect(x: 0, y: 0, width: rect.size.width, height: rect.size.height)) image.draw(in: drawRect) let subImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return subImage! } 

Si vous voulez un portrait, recentrez le centre de chaque photo.

Utilisez la solution @MV et remplacez cropRect.

 CGFloat height = imageTaken.size.height; CGFloat width = imageTaken.size.width; CGFloat newWidth = height * 9 / 16; CGFloat newX = abs((width - newWidth)) / 2; CGRect cropRect = CGRectMake(newX,0, newWidth ,height); 

Je voulais pouvoir recadrer à partir d’une région basée sur un rapport d’aspect et évoluer vers une taille basée sur une étendue externe. Voici ma variation:

 import AVFoundation import ImageIO class Image { class func crop(image:UIImage, source:CGRect, aspect:CGSize, outputExtent:CGSize) -> UIImage { let sourceRect = AVMakeRectWithAspectRatioInsideRect(aspect, source) let targetRect = AVMakeRectWithAspectRatioInsideRect(aspect, CGRect(origin: CGPointZero, size: outputExtent)) let opaque = true, deviceScale:CGFloat = 0.0 // use scale of device's main screen UIGraphicsBeginImageContextWithOptions(targetRect.size, opaque, deviceScale) let scale = max( targetRect.size.width / sourceRect.size.width, targetRect.size.height / sourceRect.size.height) let drawRect = CGRect(origin: -sourceRect.origin * scale, size: image.size * scale) image.drawInRect(drawRect) let scaledImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return scaledImage } } 

Il y a un certain nombre de choses que j’ai trouvées confuses, les préoccupations distinctes du recadrage et du redimensionnement. Le rognage est géré avec l’origine du rect que vous transmettez à drawInRect et la mise à l’échelle est gérée par la partie taille. Dans mon cas, je devais relier la taille du rectangle de rectification à la source, à mon rectangle de sortie du même rapport d’aspect. Le facteur d’échelle est alors en sortie / entrée, et cela doit être appliqué à drawRect (passé à drawInRect).

Une mise en garde est que cette approche suppose effectivement que l’image que vous dessinez est plus grande que le contexte de l’image. Je n’ai pas testé cela, mais je pense que vous pouvez utiliser ce code pour gérer le recadrage / zoom, mais en définissant explicitement le paramètre d’échelle comme étant le paramètre d’échelle susmentionné. Par défaut, UIKit applique un multiplicateur basé sur la résolution de l’écran.

Enfin, il convient de noter que cette approche UIKit est de niveau supérieur aux approches CoreGraphics / Quartz et Core Image, et semble traiter les problèmes d’orientation de l’image. Il est également intéressant de noter que c’est très rapide, deuxième à ImageIO, selon ce post ici: http://nshipster.com/image-resizing/

Utiliser la fonction

 CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height)); 

Voici un exemple de code, utilisé dans un but différent mais des clips ok.

 - (UIImage *)aspectFillToSize:(CGSize)size { CGFloat imgAspect = self.size.width / self.size.height; CGFloat sizeAspect = size.width/size.height; CGSize scaledSize; if (sizeAspect > imgAspect) { // increase width, crop height scaledSize = CGSizeMake(size.width, size.width / imgAspect); } else { // increase height, crop width scaledSize = CGSizeMake(size.height * imgAspect, size.height); } UIGraphicsBeginImageContextWithOptions(size, NO, 0.0f); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextClipToRect(context, CGRectMake(0, 0, size.width, size.height)); [self drawInRect:CGRectMake(0.0f, 0.0f, scaledSize.width, scaledSize.height)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; }