Cómo rotar un UIImage 90 grados?

Tengo un UIImage que es UIImageOrientationUp (retrato) que quisiera rotar 90 grados hacia la izquierda (hacia el paisaje). No quiero usar un CGAffineTransform . Quiero que los píxeles del UIImage cambien realmente la position. Estoy usando un bloque de código (que se muestra a continuación) originalmente destinado a cambiar el tamaño de un UIImage para hacer esto. Puse un tamaño de destino como el tamaño actual del UIImage pero recibí un error:

(Error): CGBitmapContextCreate: bytes / fila de datos inválidos: debe ser al less 1708 para 8 bits / componente de integers, 3 componentes, kCGImageAlphaPremultipliedLast.

(No obtengo un error cada vez que proporciono un tamaño MÁS PEQUEÑO como el tamaño de destino BTW). ¿Cómo puedo GIRAR mi UIImage 90 grados CCW usando solo funciones básicas de charts mientras conservo el tamaño actual?

 -(UIImage*)reverseImageByScalingToSize:(CGSize)targetSize:(UIImage*)anImage { UIImage* sourceImage = anImage; CGFloat targetWidth = targetSize.height; CGFloat targetHeight = targetSize.width; CGImageRef imageRef = [sourceImage CGImage]; CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); CGColorSpaceRef colorSpaceInfo = CGImageGetColorSpace(imageRef); if (bitmapInfo == kCGImageAlphaNone) { bitmapInfo = kCGImageAlphaNoneSkipLast; } CGContextRef bitmap; if (sourceImage.imageOrientation == UIImageOrientationUp || sourceImage.imageOrientation == UIImageOrientationDown) { bitmap = CGBitmapContextCreate(NULL, targetHeight, targetWidth, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo); } else { bitmap = CGBitmapContextCreate(NULL, targetWidth, targetHeight, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, bitmapInfo); } if (sourceImage.imageOrientation == UIImageOrientationRight) { CGContextRotateCTM (bitmap, radians(90)); CGContextTranslateCTM (bitmap, 0, -targetHeight); } else if (sourceImage.imageOrientation == UIImageOrientationLeft) { CGContextRotateCTM (bitmap, radians(-90)); CGContextTranslateCTM (bitmap, -targetWidth, 0); } else if (sourceImage.imageOrientation == UIImageOrientationDown) { // NOTHING } else if (sourceImage.imageOrientation == UIImageOrientationUp) { CGContextRotateCTM (bitmap, radians(90)); CGContextTranslateCTM (bitmap, 0, -targetHeight); } CGContextDrawImage(bitmap, CGRectMake(0, 0, targetWidth, targetHeight), imageRef); CGImageRef ref = CGBitmapContextCreateImage(bitmap); UIImage* newImage = [UIImage imageWithCGImage:ref]; CGContextRelease(bitmap); CGImageRelease(ref); return newImage; } 

¿Qué pasa con algo así como:

 static inline double radians (double degrees) {return degrees * M_PI/180;} UIImage* rotate(UIImage* src, UIImageOrientation orientation) { UIGraphicsBeginImageContext(src.size); CGContextRef context = UIGraphicsGetCurrentContext(); if (orientation == UIImageOrientationRight) { CGContextRotateCTM (context, radians(90)); } else if (orientation == UIImageOrientationLeft) { CGContextRotateCTM (context, radians(-90)); } else if (orientation == UIImageOrientationDown) { // NOTHING } else if (orientation == UIImageOrientationUp) { CGContextRotateCTM (context, radians(90)); } [src drawAtPoint:CGPointMake(0, 0)]; UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return image; } 

Creo que la forma más fácil (y también segura de subprocesss) es hacer:

 //assume that the image is loaded in landscape mode from disk UIImage * landscapeImage = [UIImage imageNamed:imgname]; UIImage * portraitImage = [[UIImage alloc] initWithCGImage: landscapeImage.CGImage scale: 1.0 orientation: UIImageOrientationRight]; 

Nota: como Brainware dijo que esto solo modifica los datos de orientación de la image: los datos de los píxeles no se han tocado. Para algunas aplicaciones, esto puede no ser suficiente.

O en Swift:

 let portraitImage : UIImage = UIImage(CGImage: landscapeImage.CGImage , scale: 1.0 , orientation: UIImageOrientation.Right) 

Echa un vistazo al código simple e impresionante de Hardy Macia en: cutting-scaling-and-rotating-uiimages

Solo llama

 UIImage *rotatedImage = [originalImage imageRotatedByDegrees:90.0]; 

Gracias Hardy Macia!

Encabezamiento:

  • (UIImage *) imageAtRect: (CGRect) rect;
  • (UIImage *) imageByScalingProportionallyToMinimumSize: (CGSize) targetSize;
  • (UIImage *) imageByScalingProportionallyToSize: (CGSize) targetSize;
  • (UIImage *) imageByScalingToSize: (CGSize) targetSize;
  • (UIImage *) imageRotatedByRadians: (CGFloat) radians;
  • (UIImage *) imageRotatedByDegrees: (CGFloat) degrees;

Dado que el enlace puede morir, aquí está el código completo

 // // UIImage-Extensions.h // // Created by Hardy Macia on 7/1/09. // Copyright 2009 Catamount Software. All rights reserved. // #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface UIImage (CS_Extensions) - (UIImage *)imageAtRect:(CGRect)rect; - (UIImage *)imageByScalingProportionallyToMinimumSize:(CGSize)targetSize; - (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize; - (UIImage *)imageByScalingToSize:(CGSize)targetSize; - (UIImage *)imageRotatedByRadians:(CGFloat)radians; - (UIImage *)imageRotatedByDegrees:(CGFloat)degrees; @end; // // UIImage-Extensions.m // // Created by Hardy Macia on 7/1/09. // Copyright 2009 Catamount Software. All rights reserved. // #import "UIImage-Extensions.h" CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;}; CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/M_PI;}; @implementation UIImage (CS_Extensions) -(UIImage *)imageAtRect:(CGRect)rect { CGImageRef imageRef = CGImageCreateWithImageInRect([self CGImage], rect); UIImage* subImage = [UIImage imageWithCGImage: imageRef]; CGImageRelease(imageRef); return subImage; } - (UIImage *)imageByScalingProportionallyToMinimumSize:(CGSize)targetSize { UIImage *sourceImage = self; UIImage *newImage = nil; CGSize imageSize = sourceImage.size; CGFloat width = imageSize.width; CGFloat height = imageSize.height; CGFloat targetWidth = targetSize.width; CGFloat targetHeight = targetSize.height; CGFloat scaleFactor = 0.0; CGFloat scaledWidth = targetWidth; CGFloat scaledHeight = targetHeight; CGPoint thumbnailPoint = CGPointMake(0.0,0.0); if (CGSizeEqualToSize(imageSize, targetSize) == NO) { CGFloat widthFactor = targetWidth / width; CGFloat heightFactor = targetHeight / height; if (widthFactor > heightFactor) scaleFactor = widthFactor; else scaleFactor = heightFactor; scaledWidth = width * scaleFactor; scaledHeight = height * scaleFactor; // center the image if (widthFactor > heightFactor) { thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; } else if (widthFactor < heightFactor) { thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; } } // this is actually the interesting part: UIGraphicsBeginImageContext(targetSize); CGRect thumbnailRect = CGRectZero; thumbnailRect.origin = thumbnailPoint; thumbnailRect.size.width = scaledWidth; thumbnailRect.size.height = scaledHeight; [sourceImage drawInRect:thumbnailRect]; newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if(newImage == nil) NSLog(@"could not scale image"); return newImage ; } - (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize { UIImage *sourceImage = self; UIImage *newImage = nil; CGSize imageSize = sourceImage.size; CGFloat width = imageSize.width; CGFloat height = imageSize.height; CGFloat targetWidth = targetSize.width; CGFloat targetHeight = targetSize.height; CGFloat scaleFactor = 0.0; CGFloat scaledWidth = targetWidth; CGFloat scaledHeight = targetHeight; CGPoint thumbnailPoint = CGPointMake(0.0,0.0); if (CGSizeEqualToSize(imageSize, targetSize) == NO) { CGFloat widthFactor = targetWidth / width; CGFloat heightFactor = targetHeight / height; if (widthFactor < heightFactor) scaleFactor = widthFactor; else scaleFactor = heightFactor; scaledWidth = width * scaleFactor; scaledHeight = height * scaleFactor; // center the image if (widthFactor < heightFactor) { thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; } else if (widthFactor > heightFactor) { thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; } } // this is actually the interesting part: UIGraphicsBeginImageContext(targetSize); CGRect thumbnailRect = CGRectZero; thumbnailRect.origin = thumbnailPoint; thumbnailRect.size.width = scaledWidth; thumbnailRect.size.height = scaledHeight; [sourceImage drawInRect:thumbnailRect]; newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if(newImage == nil) NSLog(@"could not scale image"); return newImage ; } - (UIImage *)imageByScalingToSize:(CGSize)targetSize { UIImage *sourceImage = self; UIImage *newImage = nil; // CGSize imageSize = sourceImage.size; // CGFloat width = imageSize.width; // CGFloat height = imageSize.height; CGFloat targetWidth = targetSize.width; CGFloat targetHeight = targetSize.height; // CGFloat scaleFactor = 0.0; CGFloat scaledWidth = targetWidth; CGFloat scaledHeight = targetHeight; CGPoint thumbnailPoint = CGPointMake(0.0,0.0); // this is actually the interesting part: UIGraphicsBeginImageContext(targetSize); CGRect thumbnailRect = CGRectZero; thumbnailRect.origin = thumbnailPoint; thumbnailRect.size.width = scaledWidth; thumbnailRect.size.height = scaledHeight; [sourceImage drawInRect:thumbnailRect]; newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); if(newImage == nil) NSLog(@"could not scale image"); return newImage ; } - (UIImage *)imageRotatedByRadians:(CGFloat)radians { return [self imageRotatedByDegrees:RadiansToDegrees(radians)]; } - (UIImage *)imageRotatedByDegrees:(CGFloat)degrees { // calculate the size of the rotated view's containing box for our drawing space UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,self.size.width, self.size.height)]; CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees)); rotatedViewBox.transform = t; CGSize rotatedSize = rotatedViewBox.frame.size; [rotatedViewBox release]; // Create the bitmap context UIGraphicsBeginImageContext(rotatedSize); CGContextRef bitmap = UIGraphicsGetCurrentContext(); // Move the origin to the middle of the image so we will rotate and scale around the center. CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2); // // Rotate the image context CGContextRotateCTM(bitmap, DegreesToRadians(degrees)); // Now, draw the rotated/scaled image into the context CGContextScaleCTM(bitmap, 1.0, -1.0); CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]); UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } @end; 

Aunque parezca extraño, el siguiente código resolvió el problema:

 + (UIImage*)unrotateImage:(UIImage*)image { CGSize size = image.size; UIGraphicsBeginImageContext(size); [image drawInRect:CGRectMake(0,0,size.width ,size.height)]; UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

Una function de rotation segura de subprocesss es la siguiente (funciona mucho mejor):

 -(UIImage*)imageByRotatingImage:(UIImage*)initImage fromImageOrientation:(UIImageOrientation)orientation { CGImageRef imgRef = initImage.CGImage; CGFloat width = CGImageGetWidth(imgRef); CGFloat height = CGImageGetHeight(imgRef); CGAffineTransform transform = CGAffineTransformIdentity; CGRect bounds = CGRectMake(0, 0, width, height); CGSize imageSize = CGSizeMake(CGImageGetWidth(imgRef), CGImageGetHeight(imgRef)); CGFloat boundHeight; UIImageOrientation orient = orientation; switch(orient) { case UIImageOrientationUp: //EXIF = 1 return initImage; break; case UIImageOrientationUpMirronetworking: //EXIF = 2 transform = CGAffineTransformMakeTranslation(imageSize.width, 0.0); transform = CGAffineTransformScale(transform, -1.0, 1.0); break; case UIImageOrientationDown: //EXIF = 3 transform = CGAffineTransformMakeTranslation(imageSize.width, imageSize.height); transform = CGAffineTransformRotate(transform, M_PI); break; case UIImageOrientationDownMirronetworking: //EXIF = 4 transform = CGAffineTransformMakeTranslation(0.0, imageSize.height); transform = CGAffineTransformScale(transform, 1.0, -1.0); break; case UIImageOrientationLeftMirronetworking: //EXIF = 5 boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeTranslation(imageSize.height, imageSize.width); transform = CGAffineTransformScale(transform, -1.0, 1.0); transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); break; case UIImageOrientationLeft: //EXIF = 6 boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeTranslation(0.0, imageSize.width); transform = CGAffineTransformRotate(transform, 3.0 * M_PI / 2.0); break; case UIImageOrientationRightMirronetworking: //EXIF = 7 boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeScale(-1.0, 1.0); transform = CGAffineTransformRotate(transform, M_PI / 2.0); break; case UIImageOrientationRight: //EXIF = 8 boundHeight = bounds.size.height; bounds.size.height = bounds.size.width; bounds.size.width = boundHeight; transform = CGAffineTransformMakeTranslation(imageSize.height, 0.0); transform = CGAffineTransformRotate(transform, M_PI / 2.0); break; default: [NSException raise:NSInternalInconsistencyException format:@"Invalid image orientation"]; } // Create the bitmap context CGContextRef context = NULL; void * bitmapData; int bitmapByteCount; int bitmapBytesPerRow; // Declare the number of bytes per row. Each pixel in the bitmap in this // example is represented by 4 bytes; 8 bits each of networking, green, blue, and // alpha. bitmapBytesPerRow = (bounds.size.width * 4); bitmapByteCount = (bitmapBytesPerRow * bounds.size.height); bitmapData = malloc( bitmapByteCount ); if (bitmapData == NULL) { return nil; } // Create the bitmap context. We want pre-multiplied ARGB, 8-bits // per component. Regardless of what the source image format is // (CMYK, Grayscale, and so on) it will be converted over to the format // specified here by CGBitmapContextCreate. CGColorSpaceRef colorspace = CGImageGetColorSpace(imgRef); context = CGBitmapContextCreate (bitmapData,bounds.size.width,bounds.size.height,8,bitmapBytesPerRow, colorspace, kCGBitmapAlphaInfoMask & kCGImageAlphaPremultipliedLast); if (context == NULL) // error creating context return nil; CGContextScaleCTM(context, -1.0, -1.0); CGContextTranslateCTM(context, -bounds.size.width, -bounds.size.height); CGContextConcatCTM(context, transform); // Draw the image to the bitmap context. Once we draw, the memory // allocated for the context for rendering will then contain the // raw image data in the specified color space. CGContextDrawImage(context, CGRectMake(0,0,width, height), imgRef); CGImageRef imgRef2 = CGBitmapContextCreateImage(context); CGContextRelease(context); free(bitmapData); UIImage * image = [UIImage imageWithCGImage:imgRef2 scale:initImage.scale orientation:UIImageOrientationUp]; CGImageRelease(imgRef2); return image; } 

Tuve problemas con todo lo anterior, incluida la respuesta aprobada. Convertí la categoría de Hardy en un método, ya que todo lo que quería era rotar una image. Aquí está el código y el uso:

 - (UIImage *)imageRotatedByDegrees:(UIImage*)oldImage deg:(CGFloat)degrees{ // calculate the size of the rotated view's containing box for our drawing space UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,oldImage.size.width, oldImage.size.height)]; CGAffineTransform t = CGAffineTransformMakeRotation(degrees * M_PI / 180); rotatedViewBox.transform = t; CGSize rotatedSize = rotatedViewBox.frame.size; // Create the bitmap context UIGraphicsBeginImageContext(rotatedSize); CGContextRef bitmap = UIGraphicsGetCurrentContext(); // Move the origin to the middle of the image so we will rotate and scale around the center. CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2); // // Rotate the image context CGContextRotateCTM(bitmap, (degrees * M_PI / 180)); // Now, draw the rotated/scaled image into the context CGContextScaleCTM(bitmap, 1.0, -1.0); CGContextDrawImage(bitmap, CGRectMake(-oldImage.size.width / 2, -oldImage.size.height / 2, oldImage.size.width, oldImage.size.height), [oldImage CGImage]); UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

Y el uso:

 UIImage *image2 = [self imageRotatedByDegrees:image deg:90]; 

Gracias Hardy!

Gire la image 90 grados (en sentido horario / antihorario)

Llamada de function:

  UIImage *rotatedImage = [self rotateImage:originalImage clockwise:YES]; 

Implementación:

 - (UIImage*)rotateImage:(UIImage*)sourceImage clockwise:(BOOL)clockwise { CGSize size = sourceImage.size; UIGraphicsBeginImageContext(CGSizeMake(size.height, size.width)); [[UIImage imageWithCGImage:[sourceImage CGImage] scale:1.0 orientation:clockwise ? UIImageOrientationRight : UIImageOrientationLeft] drawInRect:CGRectMake(0,0,size.height ,size.width)]; UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

Si desea agregar un button de girar fotos que seguirá girando la foto en incrementos de 90 grados, aquí tienes. ( finalImage es un UIImage que ya se ha creado en otro lugar).

 - (void)rotatePhoto { UIImage *rotatedImage; if (finalImage.imageOrientation == UIImageOrientationRight) rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage scale: 1.0 orientation: UIImageOrientationDown]; else if (finalImage.imageOrientation == UIImageOrientationDown) rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage scale: 1.0 orientation: UIImageOrientationLeft]; else if (finalImage.imageOrientation == UIImageOrientationLeft) rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage scale: 1.0 orientation: UIImageOrientationUp]; else rotatedImage = [[UIImage alloc] initWithCGImage: finalImage.CGImage scale: 1.0 orientation: UIImageOrientationRight]; finalImage = rotatedImage; } 

Sencillo. Simplemente cambie el indicador de orientación de image.

 UIImage *oldImage = [UIImage imageNamed:@"whatever.jpg"]; UIImageOrientation newOrientation; switch (oldImage.imageOrientation) { case UIImageOrientationUp: newOrientation = UIImageOrientationLandscapeLeft; break; case UIImageOrientationLandscapeLeft: newOrientation = UIImageOrientationDown; break; case UIImageOrientationDown: newOrientation = UIImageOrientationLandscapeRight; break; case UIImageOrientationLandscapeRight: newOrientation = UIImageOrientationUp; break; // you can also handle mirronetworking orientations similarly ... } UIImage *rotatedImage = [UIImage imageWithCGImage:oldImage.CGImage scale:1.0f orientation:newOrientation]; 

Aquí hay una extensión Swift a UIImage que gira la image por cualquier ángulo arbitrario. Utilícelo así: let rotatedImage = image.rotated(byDegrees: degree) . Utilicé el código Objective-C en una de las otras respuestas y eliminé unas pocas líneas que incorrectas (rotated box stuff) y la convertí en una extensión para UIImage.

 extension UIImage { func rotate(byDegrees degree: Double) -> UIImage { let radians = CGFloat(degree*M_PI)/180.0 as CGFloat let rotatedSize = self.size let scale = UIScreen.mainScreen().scale UIGraphicsBeginImageContextWithOptions(rotatedSize, false, scale) let bitmap = UIGraphicsGetCurrentContext() CGContextTranslateCTM(bitmap, rotatedSize.width / 2, rotatedSize.height / 2); CGContextRotateCTM(bitmap, radians); CGContextScaleCTM(bitmap, 1.0, -1.0); CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2 , self.size.width, self.size.height), self.CGImage ); let newImage = UIGraphicsGetImageFromCurrentImageContext() return newImage } } 

Me gusta la simple elegancia de la respuesta de Peter Sarnowski , pero puede causar problemas cuando no puede confiar en los metadatos EXIF y similares. En situaciones en las que necesita rotar los datos de image reales , recomendaría algo como esto:

 - (UIImage *)rotateImage:(UIImage *) img { CGSize imgSize = [img size]; UIGraphicsBeginImageContext(imgSize); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextRotateCTM(context, M_PI_2); CGContextTranslateCTM(context, 0, -640); [img drawInRect:CGRectMake(0, 0, imgSize.height, imgSize.width)]; UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

El código anterior toma una image cuya orientación es Landscape (no se puede recordar si es Landscape Left o Landscape Right ) y lo gira a Portrait . Es un ejemplo que se puede modificar para sus necesidades.

Los arguments key con los que tendría que jugar son CGContextRotateCTM(context, M_PI_2) donde decide cuánto desea rotar, pero luego debe asegurarse de que la image aún se dibuja en la pantalla usando CGContextTranslateCTM(context, 0, -640) Esta última parte es muy importante para asegurarse de ver la image y no una pantalla en blanco.

Para get más información, consulte la fuente .

Intento este código, funciona, y tomé de http://www.catamount.com/blog/1015/uiimage-extensions-for-cutting-scaling-and-rotating-uiimages/

 + (UIImage *)rotateImage:(UIImage*)src byRadian:(CGFloat)radian { // calculate the size of the rotated view's containing box for our drawing space UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0, src.size.width, src.size.height)]; CGAffineTransform t = CGAffineTransformMakeRotation(radian); rotatedViewBox.transform = t; CGSize rotatedSize = rotatedViewBox.frame.size; // Create the bitmap context UIGraphicsBeginImageContext(rotatedSize); CGContextRef bitmap = UIGraphicsGetCurrentContext(); // Move the origin to the middle of the image so we will rotate and scale around the center. CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2); // // Rotate the image context CGContextRotateCTM(bitmap, radian); // Now, draw the rotated/scaled image into the context CGContextScaleCTM(bitmap, 1.0, -1.0); CGContextDrawImage(bitmap, CGRectMake(-src.size.width / 2, -src.size.height / 2, src.size.width, src.size.height), [src CGImage]); UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

Swift 3 UIImage:

 func fixOrientation() -> UIImage { // No-op if the orientation is already correct if ( self.imageOrientation == .up ) { return self; } // We need to calculate the proper transformation to make the image upright. // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if Mirronetworking. var transform: CGAffineTransform = .identity if ( self.imageOrientation == .down || self.imageOrientation == .downMirronetworking ) { transform = transform.translatedBy(x: self.size.width, y: self.size.height) transform = transform.rotated(by: .pi) } if ( self.imageOrientation == .left || self.imageOrientation == .leftMirronetworking ) { transform = transform.translatedBy(x: self.size.width, y: 0) transform = transform.rotated(by: .pi/2) } if ( self.imageOrientation == .right || self.imageOrientation == .rightMirronetworking ) { transform = transform.translatedBy(x: 0, y: self.size.height); transform = transform.rotated(by: -.pi/2); } if ( self.imageOrientation == .upMirronetworking || self.imageOrientation == .downMirronetworking ) { transform = transform.translatedBy(x: self.size.width, y: 0) transform = transform.scaledBy(x: -1, y: 1) } if ( self.imageOrientation == .leftMirronetworking || self.imageOrientation == .rightMirronetworking ) { transform = transform.translatedBy(x: self.size.height, y: 0); transform = transform.scaledBy(x: -1, y: 1); } // Now we draw the underlying CGImage into a new context, applying the transform // calculated above. let ctx: CGContext = CGContext(data: nil, width: Int(self.size.width), height: Int(self.size.height), bitsPerComponent: self.cgImage!.bitsPerComponent, bytesPerRow: 0, space: self.cgImage!.colorSpace!, bitmapInfo: self.cgImage!.bitmapInfo.rawValue)!; ctx.concatenate(transform) if ( self.imageOrientation == .left || self.imageOrientation == .leftMirronetworking || self.imageOrientation == .right || self.imageOrientation == .rightMirronetworking ) { ctx.draw(self.cgImage!, in: CGRect(x: 0.0,y: 0.0,width: self.size.height,height: self.size.width)) } else { ctx.draw(self.cgImage!, in: CGRect(x: 0.0,y: 0.0,width: self.size.width,height: self.size.height)) } // And now we just create a new UIImage from the drawing context and return it return UIImage(cgImage: ctx.makeImage()!) } 

Cambio menor a las otras respuestas que se basan en el código de Hardy Macia. No es necesario crear un object UIView completo simplemente para calcular el rectángulo delimitador de la image girada. Simplemente aplique una transformada de rotation al rectángulo de image usando CGRectApplyAffineTransform .

 static CGFloat DegreesToRadians(CGFloat degrees) {return degrees * M_PI / 180;} static CGFloat RadiansToDegrees(CGFloat radians) {return radians * 180/M_PI;} - (CGSize)rotatedImageSize:(CGFloat)degrees { CGAffineTransform t = CGAffineTransformMakeRotation(DegreesToRadians(degrees)); CGRect originalImageRect = CGRectMake(0, 0, self.size.width, self.size.height); CGRect rotatedImageRect = CGRectApplyAffineTransform(originalImageRect, t); CGSize rotatedSize = rotatedImageRect.size; return rotatedSize; } - (UIImage*)imageRotatedByDegrees:(CGFloat)degrees { // calculate the size of the rotated view's containing box for our drawing space CGSize rotatedSize = [self rotatedImageSize:degrees]; // Create the bitmap context UIGraphicsBeginImageContext(rotatedSize); CGContextRef bitmap = UIGraphicsGetCurrentContext(); // Move the origin to the middle of the image so we will rotate and scale around the center. CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2); // // Rotate the image context CGContextRotateCTM(bitmap, DegreesToRadians(degrees)); // Now, draw the rotated/scaled image into the context CGContextScaleCTM(bitmap, 1.0, -1.0); CGContextDrawImage(bitmap, CGRectMake(-self.size.width / 2, -self.size.height / 2, self.size.width, self.size.height), [self CGImage]); UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; } 

"tint uiimage grayscale" parece ser el Google-Fu apropiado para este

enseguida recibo:

https://discussions.apple.com/message/8104516?messageID=8104516&#8104516

https://discussions.apple.com/thread/2751445?start=0&tstart=0

¿Cómo tinturaría una image mediante progtwigción en el iPhone?

resize-a-uiimage-the-right-way explica algunos de los problemas que tienen muchas muestras de código para hacer esto, y tiene algunos fragments de código para ayudar a lidiar con UIImages: el método de ayudante privado en UIImage + resize.m acepta una transformación para permitir rotation, por lo que solo debería exponerlo como una interfaz pública.

 // Returns a copy of the image that has been transformed using the given affine transform and scaled to the new size // The new image's orientation will be UIImageOrientationUp, regardless of the current image's orientation // If the new size is not integral, it will be rounded up - (UIImage *)resizedImage:(CGSize)newSize transform:(CGAffineTransform)transform drawTransposed:(BOOL)transpose interpolationQuality:(CGInterpolationQuality)quality { CGRect newRect = CGRectIntegral(CGRectMake(0, 0, newSize.width, newSize.height)); CGRect transposedRect = CGRectMake(0, 0, newRect.size.height, newRect.size.width); CGImageRef imageRef = self.CGImage; // Build a context that's the same dimensions as the new size CGContextRef bitmap = CGBitmapContextCreate(NULL, newRect.size.width, newRect.size.height, CGImageGetBitsPerComponent(imageRef), 0, CGImageGetColorSpace(imageRef), CGImageGetBitmapInfo(imageRef)); // Rotate and/or flip the image if requinetworking by its orientation CGContextConcatCTM(bitmap, transform); // Set the quality level to use when rescaling CGContextSetInterpolationQuality(bitmap, quality); // Draw into the context; this scales the image CGContextDrawImage(bitmap, transpose ? transposedRect : newRect, imageRef); // Get the resized image from the context and a UIImage CGImageRef newImageRef = CGBitmapContextCreateImage(bitmap); UIImage *newImage = [UIImage imageWithCGImage:newImageRef]; // Clean up CGContextRelease(bitmap); CGImageRelease(newImageRef); return newImage; } 

Esta es la licencia de ese file:

 // Created by Trevor Harmon on 8/5/09. // Free for personal or commercial use, with or without modification. // No warranty is expressed or implied. 

Hay una categoría UIImage extremadamente eficiente llamada NYXImagesKit. Utiliza vDSP, CoreImage y vImage para ser lo más rápido posible. Tiene una categoría UIImage + Rotating que me ha salvado el día 🙂

https://github.com/Nyx0uf/NYXImagesKit

Para Swift: aquí hay una extensión simple a UIImage:

 //ImageRotation.swift import UIKit extension UIImage { public func imageRotatedByDegrees(degrees: CGFloat, flip: Bool) -> UIImage { let radiansToDegrees: (CGFloat) -> CGFloat = { return $0 * (180.0 / CGFloat(M_PI)) } let degreesToRadians: (CGFloat) -> CGFloat = { return $0 / 180.0 * CGFloat(M_PI) } // calculate the size of the rotated view's containing box for our drawing space let rotatedViewBox = UIView(frame: CGRect(origin: CGPointZero, size: size)) let t = CGAffineTransformMakeRotation(degreesToRadians(degrees)); rotatedViewBox.transform = t let rotatedSize = rotatedViewBox.frame.size // Create the bitmap context UIGraphicsBeginImageContext(rotatedSize) let bitmap = UIGraphicsGetCurrentContext() // Move the origin to the middle of the image so we will rotate and scale around the center. CGContextTranslateCTM(bitmap, rotatedSize.width / 2.0, rotatedSize.height / 2.0); // // Rotate the image context CGContextRotateCTM(bitmap, degreesToRadians(degrees)); // Now, draw the rotated/scaled image into the context var yFlip: CGFloat if(flip){ yFlip = CGFloat(-1.0) } else { yFlip = CGFloat(1.0) } CGContextScaleCTM(bitmap, yFlip, -1.0) CGContextDrawImage(bitmap, CGRectMake(-size.width / 2, -size.height / 2, size.width, size.height), CGImage) let newImage = UIGraphicsGetImageFromCurrentImageContext() UIGraphicsEndImageContext() return newImage } } 

( Source )

Use it with:

 rotatedPhoto = rotatedPhoto?.imageRotatedByDegrees(90, flip: false) 

The former will rotate an image and flip it if flip is set to true.