Girar una imagen CG

Tengo un UIImage que obtengo de un UIImagePickerController. Cuando recibo la imagen del - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info método de - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info Lo pongo directamente en un UIImageView para una vista previa y le doy la opción al usuario de guardar o descartar la imagen.

La pantalla de vista previa

Cuando el usuario selecciona la opción de guardar, la aplicación obtiene los datos png de la imagen y la guarda en su directorio de documentos. Pero lo que ocurre bajo una de las 2 orientaciones posibles del dispositivo (solo paisaje) es que la imagen se guarda al revés (más específicamente, se gira 180 grados de lo que debería ser). Entonces, cuando cargo la imagen en la galería, aparece boca abajo.

(Ver la imagen inferior izquierda en la galería)

Ver la imagen inferior izquierda

He resuelto que los datos de imagen en bruto en el UIImage del UIImagePickerController no se rotan, sino que la orientación se almacena como una propiedad en el objeto y solo se aplica cuando se muestra. Así que estoy tratando de rotar la CGImage asociada con el UIImage usando algún código que encontré en línea. Pero parece que no tiene ningún efecto en la imagen. El código que estoy usando sigue:

 - (void)rotateImage:(UIImage*)image byRadians:(CGFloat)rads { // calculate the size of the rotated view's containing box for our drawing space UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,image.size.width, image.size.height)]; CGAffineTransform t = CGAffineTransformMakeRotation(rads); 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 you want to rotate and scale around the center. CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2); // Rotate the image context CGContextRotateCTM(bitmap, rads); // Now, draw the rotated/scaled image into the context CGContextScaleCTM(bitmap, 1.0, -1.0); CGContextDrawImage(bitmap, CGRectMake(image.size.width / 2, image.size.height / 2, image.size.width, image.size.height), [image CGImage]); image = UIGraphicsGetImageFromCurrentImageContext(); image = [UIImage imageWithCGImage:image.CGImage scale:1.0 orientation:UIImageOrientationDown]; UIGraphicsEndImageContext(); } 

Me gustaría saber por qué este código no funciona, ya que cada pieza de código que encuentro en línea para hacer esta rotación de imágenes parece no funcionar.

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

usa este … ¡funciona perfecto! Solo asegúrese de usar esta función cuando esté recogiendo imágenes de UIImagePicker:

ejemplo:

 UIImage *image; image = [self rotate:image andOrientation:image.imageOrientation]; 

Asegúrese de utilizar esta función en el lugar donde selecciona las fotos del directorio de documentos.

Girar y duplicar UIImage CGImage Backing Data – Swift

Recientemente quise corregir un UIImage respaldado por un CGImage para que coincida con la orientación deseada en lugar de depender de las API para respetar el parámetro UIImageOrientation.

 func createMatchingBackingDataWithImage(imageRef: CGImage?, orienation: UIImageOrientation) -> CGImage? { var orientedImage: CGImage? if let imageRef = imageRef { let originalWidth = imageRef.width let originalHeight = imageRef.height let bitsPerComponent = imageRef.bitsPerComponent let bytesPerRow = imageRef.bytesPerRow let bitmapInfo = imageRef.bitmapInfo guard let colorSpace = imageRef.colorSpace else { return nil } var degreesToRotate: Double var swapWidthHeight: Bool var mirrored: Bool switch orienation { case .up: degreesToRotate = 0.0 swapWidthHeight = false mirrored = false break case .upMirrored: degreesToRotate = 0.0 swapWidthHeight = false mirrored = true break case .right: degreesToRotate = 90.0 swapWidthHeight = true mirrored = false break case .rightMirrored: degreesToRotate = 90.0 swapWidthHeight = true mirrored = true break case .down: degreesToRotate = 180.0 swapWidthHeight = false mirrored = false break case .downMirrored: degreesToRotate = 180.0 swapWidthHeight = false mirrored = true break case .left: degreesToRotate = -90.0 swapWidthHeight = true mirrored = false break case .leftMirrored: degreesToRotate = -90.0 swapWidthHeight = true mirrored = true break } let radians = degreesToRotate * Double.pi / 180.0 var width: Int var height: Int if swapWidthHeight { width = originalHeight height = originalWidth } else { width = originalWidth height = originalHeight } let contextRef = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace, bitmapInfo: bitmapInfo.rawValue) contextRef?.translateBy(x: CGFloat(width) / 2.0, y: CGFloat(height) / 2.0) if mirrored { contextRef?.scaleBy(x: -1.0, y: 1.0) } contextRef?.rotate(by: CGFloat(radians)) if swapWidthHeight { contextRef?.translateBy(x: -CGFloat(height) / 2.0, y: -CGFloat(width) / 2.0) } else { contextRef?.translateBy(x: -CGFloat(width) / 2.0, y: -CGFloat(height) / 2.0) } contextRef?.draw(imageRef, in: CGRect(x: 0.0, y: 0.0, width: CGFloat(originalWidth), height: CGFloat(originalHeight))) orientedImage = contextRef?.makeImage() } return orientedImage } 

Tengo tu problema. CGContextTranslateCTM(context, -rotatedSize.width/2, -rotatedSize.height/2); volver a traducir el contexto usando CGContextTranslateCTM(context, -rotatedSize.width/2, -rotatedSize.height/2); así como también establecer el origen de rect en el dibujo en rotatedViewBox.frame.origin.x, rotatedViewBox.frame.origin.y. usa este código

 UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0,image.size.width, image.size.height)]; CGAffineTransform t = CGAffineTransformMakeRotation(0.3); rotatedViewBox.transform = t; CGSize rotatedSize = rotatedViewBox.frame.size; UIGraphicsBeginImageContext(rotatedSize); CGContextRef context = UIGraphicsGetCurrentContext(); CGContextTranslateCTM(context, rotatedSize.width/2, rotatedSize.height/2); CGContextRotateCTM (context, 0.3); CGContextScaleCTM(context, 1, -1); CGContextTranslateCTM(context, -rotatedSize.width/2, -rotatedSize.height/2); CGContextDrawImage(context, CGRectMake(-rotatedViewBox.frame.origin.x, -rotatedViewBox.frame.origin.y, image.size.width, image.size.height), [image CGImage]); UIImage *nn = UIGraphicsGetImageFromCurrentImageContext(); NSLog(@"size is %f, %f",nn.size.width,nn.size.height); UIGraphicsEndImageContext(); UIImageWriteToSavedPhotosAlbum(nn, nil,nil,nil); 

La versión de Swift 3 para la respuesta de Cameron Lowell Palmer :

 func createMatchingBackingDataWithImage(imageRef: CGImage?, orienation: UIImageOrientation) -> CGImage? { var orientedImage: CGImage? if let imageRef = imageRef { let originalWidth = imageRef.width let originalHeight = imageRef.height let bitsPerComponent = imageRef.bitsPerComponent let bytesPerRow = imageRef.bytesPerRow let colorSpace = imageRef.colorSpace let bitmapInfo = imageRef.bitmapInfo var degreesToRotate: Double var swapWidthHeight: Bool var mirrored: Bool switch orienation { case .up: degreesToRotate = 0.0 swapWidthHeight = false mirrored = false break case .upMirrored: degreesToRotate = 0.0 swapWidthHeight = false mirrored = true break case .right: degreesToRotate = 90.0 swapWidthHeight = true mirrored = false break case .rightMirrored: degreesToRotate = 90.0 swapWidthHeight = true mirrored = true break case .down: degreesToRotate = 180.0 swapWidthHeight = false mirrored = false break case .downMirrored: degreesToRotate = 180.0 swapWidthHeight = false mirrored = true break case .left: degreesToRotate = -90.0 swapWidthHeight = true mirrored = false break case .leftMirrored: degreesToRotate = -90.0 swapWidthHeight = true mirrored = true break } let radians = degreesToRotate * Double.pi / 180 var width: Int var height: Int if swapWidthHeight { width = originalHeight height = originalWidth } else { width = originalWidth height = originalHeight } if let contextRef = CGContext(data: nil, width: width, height: height, bitsPerComponent: bitsPerComponent, bytesPerRow: bytesPerRow, space: colorSpace!, bitmapInfo: bitmapInfo.rawValue) { contextRef.translateBy(x: CGFloat(width) / 2.0, y: CGFloat(height) / 2.0) if mirrored { contextRef.scaleBy(x: -1.0, y: 1.0) } contextRef.rotate(by: CGFloat(radians)) if swapWidthHeight { contextRef.translateBy(x: -CGFloat(height) / 2.0, y: -CGFloat(width) / 2.0) } else { contextRef.translateBy(x: -CGFloat(width) / 2.0, y: -CGFloat(height) / 2.0) } contextRef.draw(imageRef, in: CGRect(x: 0, y: 0, width: originalWidth, height: originalHeight)) orientedImage = contextRef.makeImage() } } return orientedImage } 

Uso:

 let newCgImage = createMatchingBackingDataWithImage(imageRef: cgImageRef, orienation: .left)