ios - voltea - Cómo rotar un UIImage 90 grados?
voltear fotos espejo (18)
Tengo un UIImage
que es UIImageOrientationUp
(retrato) que me gustaría rotar en sentido antihorario 90 grados (hacia el paisaje). No quiero usar CGAffineTransform
. Quiero que los píxeles del UIImage
realmente cambien de posición. 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. Establecí un tamaño objetivo como el tamaño actual del UIImage
pero recibo un error:
(Error): CGBitmapContextCreate: bytes / fila de datos no válidos: debe ser de al menos 1708 para 8 bits / componentes enteros, 3 componentes, kCGImageAlphaPremultipliedLast.
(No obtengo un error cada vez que proporciono un tamaño MÁS PEQUEÑO que el tamaño objetivo por cierto). ¿Cómo puedo GIRAR mi UIImage
90 grados CCW usando solo funciones de gráficos centrales mientras se preserva 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;
}
"tint uiimage en escala de grises" parece ser el Google-Fu apropiado para este
de inmediato me sale:
https://discussions.apple.com/message/8104516?messageID=8104516�
https://discussions.apple.com/thread/2751445?start=0&tstart=0
¿Cómo puedo teñir una imagen programáticamente en el iPhone?
¿Qué tal 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;
}
Aquí hay una extensión de Swift a UIImage que rota la imagen en cualquier ángulo arbitrario. Úselo así: let rotatedImage = image.rotated(byDegrees: degree)
. Usé el código Objective-C en una de las otras respuestas y eliminé algunas líneas que incorrectas (roté cosas de la caja) y las 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
}
}
Cambio menor a las otras respuestas que se basan en el código de Hardy Macia. No es necesario crear un objeto UIView
completo simplemente para calcular el rectángulo delimitador de la imagen girada. Simplemente aplique una transformación rotar al rectángulo de la imagen 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;
}
Creo que la manera más fácil (y segura también) 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 imagen, los datos de los píxeles no se tocan. Para algunas aplicaciones, esto puede no ser suficiente.
O en Swift:
let portraitImage : UIImage = UIImage(CGImage: landscapeImage.CGImage ,
scale: 1.0 ,
orientation: UIImageOrientation.Right)
Intento este código, funciona, y lo tomé de 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;
}
Me gusta la elegancia simple de la respuesta de Peter Sarnowski
, pero puede causar problemas cuando no puede confiar en los metadatos EXIF
y similares. En situaciones donde necesita rotar los datos de imagen 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 imagen cuya orientación es Landscape
(no se recuerda si es Landscape Left
o Landscape Right
) y la gira hacia Portrait
. Es un ejemplo que puede modificarse para sus necesidades.
Los argumentos clave con los que debería jugar son CGContextRotateCTM(context, M_PI_2)
donde decide cuánto quiere rotar, pero luego debe asegurarse de que la imagen aún se dibuje en la pantalla usando CGContextTranslateCTM(context, 0, -640)
Esta última parte es bastante importante para asegurarse de ver la imagen y no una pantalla en blanco.
Para obtener más información, consulte la source .
Mira el código simple y sorprendente 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) radianes;
- (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;
Por extraño que parezca, el siguiente código me solucionó 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;
}
Sencillo. Simplemente cambie la bandera de orientación de la imagen.
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 mirrored orientations similarly ...
}
UIImage *rotatedImage = [UIImage imageWithCGImage:oldImage.CGImage scale:1.0f orientation:newOrientation];
Si desea agregar un botón de rotación de fotos que seguirá girando la foto en incrementos de 90 grados, aquí tiene. ( 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;
}
Swift 3 UIImage extensión:
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 Mirrored.
var transform: CGAffineTransform = .identity
if ( self.imageOrientation == .down || self.imageOrientation == .downMirrored ) {
transform = transform.translatedBy(x: self.size.width, y: self.size.height)
transform = transform.rotated(by: .pi)
}
if ( self.imageOrientation == .left || self.imageOrientation == .leftMirrored ) {
transform = transform.translatedBy(x: self.size.width, y: 0)
transform = transform.rotated(by: .pi/2)
}
if ( self.imageOrientation == .right || self.imageOrientation == .rightMirrored ) {
transform = transform.translatedBy(x: 0, y: self.size.height);
transform = transform.rotated(by: -.pi/2);
}
if ( self.imageOrientation == .upMirrored || self.imageOrientation == .downMirrored ) {
transform = transform.translatedBy(x: self.size.width, y: 0)
transform = transform.scaledBy(x: -1, y: 1)
}
if ( self.imageOrientation == .leftMirrored || self.imageOrientation == .rightMirrored ) {
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 == .leftMirrored ||
self.imageOrientation == .right ||
self.imageOrientation == .rightMirrored ) {
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()!)
}
Tuve problemas con ll de los anteriores, incluida la respuesta aprobada. Volví a convertir la categoría de Hardy en un método, ya que todo lo que quería era rotar una imagen. 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!
Una función de rotación de hilo seguro 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 UIImageOrientationUpMirrored: //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 UIImageOrientationDownMirrored: //EXIF = 4
transform = CGAffineTransformMakeTranslation(0.0, imageSize.height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
break;
case UIImageOrientationLeftMirrored: //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 UIImageOrientationRightMirrored: //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 red, 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;
}
resize-a-uiimage-the-right-way explica algunos de los problemas que tienen muchos ejemplos de código para hacer esto, y tiene algunos fragmentos de código para ayudar a lidiar con UIImages - el método de ayuda privada en UIImage + resize.m acepta una transformación para permitir rotación, por lo que solo tendrías que exponer eso 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 required 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 archivo:
// Created by Trevor Harmon on 8/5/09.
// Free for personal or commercial use, with or without modification.
// No warranty is expressed or implied.
Girar la imagen 90 grados (sentido horario / antihorario)
Llamada de función -
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;
}
For Swift: Here is a simple extension to 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.
There is a extremely efficient UIImage category named NYXImagesKit. It uses vDSP, CoreImage and vImage to be as fast as possible. It has a UIImage+Rotating category that saved my day :)