2009-08-22 139 views
165

我有一个UIImageUIImageOrientationUp(肖像),我想逆时针旋转90度(横向)。我不想使用CGAffineTransform。我希望UIImage的像素实际移位。我正在使用一组代码(如下所示),最初打算调整UIImage来执行此操作。我设定的目标尺寸为UIImage的电流大小,但我得到一个错误:如何旋转90度的UIImage?

(Error): CGBitmapContextCreate: invalid data bytes/row: should be at least 1708 for 8 integer bits/component, 3 components, kCGImageAlphaPremultipliedLast.

(每当我提供一个更小的尺寸作为目标大小BTW我没有得到一个错误)。如何在保持当前尺寸的同时使用核心图形功能来旋转90度逆时针旋转我的UIImage

-(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; 
} 
+0

我发现了另一个有用的链接。希望这有助于有人.. http://mobiledevelopertips.com/user-interface/rotate-an-image- with-animation.html – 2013-01-01 14:09:30

+0

解决方案.......... http://stackoverflow.com/questions/5427656/ios-uiimagepickercontroller-result-image-orientation-after-upload/5427890#5427890 – Fattie 2014-05-18 09:36:38

+0

我的问题被上传到Amazon S3的照片被旋转。该解决方案通过视觉和上传解决了该问题。 – chrisallick 2014-08-17 15:35:11

回答

82

什么是这样的:

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; 
} 
+0

后谢谢。我试过了,虽然没有改变图像..你说我可能需要做一些额外的东西,对吧?你能详细说明一下吗? – RexOnRoids 2009-08-23 06:39:06

+1

我的评论是drawAtPoint可能需要在调用设置适当的RotateCTM之后调用。尝试将drawAtPoint移动到UIGraphicsGetImageFromCurrentImageContext – fbrereto 2009-08-23 06:52:09

+4

之前这不适用于后台线程。 UIGraphicsGetCurrentContext()不是线程安全的,只应在主(UI)线程上调用。 – 2010-06-24 14:25:06

0

resize-a-uiimage-the-right-way解释了这样做有一定的问题,许多代码样本,并有一些代码片段,以帮助应对UIImages - 私有助手方法中的UIImage + resize.m接受一个允许旋转的变换,所以你只需要将它公开为公共接口。

// 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; 
} 

这是该文件的许可证:

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

退房哈迪马西亚在简单和真棒代码:cutting-scaling-and-rotating-uiimages

只需拨打

UIImage *rotatedImage = [originalImage imageRotatedByDegrees:90.0]; 

谢谢哈马西亚!

部首:

  • (的UIImage *)imageAtRect:(的CGRect)RECT; (UIImage *)imageByScalingProportionallyToMinimumSize:(CGSize)targetSize; (UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize; (UIImage *)imageByScalingToSize :(CGSize)targetSize;(CGSize)targetSize;
  • (UIImage *)imageRotatedByRadians :(CGFloat)radians;
  • (UIImage *)imageRotatedByDegrees :(CGFloat)度;

由于连杆可能会死,这里展示的代码

// 
// 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; 
+0

...之前移动drawAtPoint方法...链接已经死亡。 +1包含完整代码 – Greg 2018-01-21 07:29:25

397

我认为最简单的方法(和线程安全太)是做:

//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]; 

注:由于Brainware说,这只是修改图像的方位数据 - 像素数据未触及。对于某些应用程序,这可能还不够。

还是在斯威夫特:

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

使其更通用:UIImage * origImg = [UIImage imageNamed:@“1.JPG”]; UIImage * fixed = [UIImage imageWithCGImage:[origImg CGImage] scale:1.0 orientation:origImg.imageOrientation]; – 2013-08-02 10:23:38

+11

这实际上并没有旋转图像。它复制图像并将图像的imageFlags属性的imageOrientation位设置为0,1,2或3.有些类忽略这些标记,例如UIActivityViewController。如果你确实需要旋转图像,那么请参阅Ben Groot的答案,即Hardy Macia的UIImage扩展。 – Brainware 2013-09-18 23:44:10

+0

如果将您的应用程序用于视网膜和非视网膜屏幕,则必须采用originalImage.scale并将其作为缩放组件传递,否则将缩放比例设置为1.0将不起作用。 – teradyl 2014-01-22 23:41:43

29

一个线程安全的旋转功能如下(它的效果要好得多):

-(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; 
} 
+0

您的代码存在问题...它在图像周围添加了一个奇怪的白框, UIImageOrientationDown'。 – iosfreak 2012-04-05 20:58:51

+1

你不希望这个调用CGColorSpaceRelease(colorspace),请参阅http://stackoverflow.com/questions/5269815/does-the-result-of-cgimagegetcolorspaceimage-have-to-be-released – 2014-04-17 21:10:41

+0

对不起有关该版本 – thewormsterror 2014-04-18 11:20:48

1

我喜欢Peter Sarnowski的答案的古朴典雅,但它当你不能依赖于元数据等时会导致问题。在你需要旋转实际图像数据的情况下我建议是这样的:

- (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; 
} 

上面的代码需要的图像,其取向Landscape(不记得,如果它是Landscape LeftLandscape Right)并将其旋转到Portrait。这是一个可以根据您的需求进行修改的示例。

您必须使用的关键参数是CGContextRotateCTM(context, M_PI_2),您可以在其中决定要旋转多少,但是必须确保图片仍然使用CGContextTranslateCTM(context, 0, -640)在屏幕上绘制。最后一部分对于确保您看到图像而不是空白屏幕非常重要。

欲了解更多信息,请查阅source

+2

Downvote for broken link and no explanation of -640 magic number。如果修复将会反转。 – Nate 2015-12-10 10:17:48

6

如果你想添加一个照片旋转按钮,将继续以90度的增量旋转照片,在这里你去。 (finalImage是一个已经在其他地方创建一个UIImage)

- (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; 
} 
30

奇怪,因为这似乎是,下面的代码解决了我的问题:

+ (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; 
} 
+8

它可以工作,因为一旦你绘制了矩形,图像方向就不会保留。 – Mercurial 2013-09-12 13:13:45

16

我有麻烦与上面的LL,包括批准的答案。我将哈代的类别转换回了一种方法,因为我只想旋转图像。下面的代码和用法:

- (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; 
} 

和使用:

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

谢谢哈!

2

我试试这个代码,它的工作原理,并从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; 
} 
0

了有一个名为NYXImagesKit一个非常有效的UIImage的类别。它使用vDSP,CoreImage和vImage尽可能快。它有一个UIImage +旋转的类别,救了我的一天:)

https://github.com/Nyx0uf/NYXImagesKit

5

简单。只需更改图像方向标志。

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]; 
0

对于斯威夫特:这是一个简单的扩展的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

与使用它:

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

前者将旋转图像和如果flip设置为true,则将其翻转。

+0

你能解释一下吗? – 2016-03-03 10:44:38

+1

这似乎与纵横比由于某种原因搞乱 – fwhenin 2016-03-10 00:49:29

12

旋转图像90度(顺时针/反时针方向)

函数调用 -

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

实现:

- (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; 
    } 
+0

这增加了图像大小 – 2017-09-13 13:09:31

1

次要变化到作为其他的答案基于Hardy Macia的代码。不需要简单地创建一个完整的对象来计算旋转图像的边界矩形。只需使用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; 
} 
4

这是UIImage的Swift扩展,它可以以任意角度旋转图像。像这样使用它:let rotatedImage = image.rotated(byDegrees: degree)。 我在其他答案之一中使用了Objective-C代码,并删除了我们不正确的几行(旋转框东西),并将其转换为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 
} 
} 
+0

工程太棒了!我改变了一点,以便我可以交换宽度和高度:func rotate(byDegrees degree:Double,toSize:CGSize?= nil) - > UIImage让rotateSize = toSize ?? self.size – 2016-08-03 07:01:13

+1

这并没有正确设置图像边界。您最终会看到旋转后的图像溢出原始边界。 – 2016-11-23 20:47:25

+0

非常感谢。令人惊讶的是,我花了多少时间在今天。 – ChrisH 2017-07-07 00:42:26

2

斯威夫特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 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()!) 
}