如何将 UIImage 旋转 90 度?
Posted
技术标签:
【中文标题】如何将 UIImage 旋转 90 度?【英文标题】:How to Rotate a UIImage 90 degrees? 【发布时间】:2009-08-22 05:48:29 【问题描述】:我有一个UIImage
即UIImageOrientationUp
(纵向),我想将其逆时针旋转 90 度(横向)。我不想使用CGAffineTransform
。我希望UIImage
的像素实际移动位置。我正在使用一段代码(如下所示),最初旨在调整UIImage
的大小来执行此操作。我将目标大小设置为UIImage
的当前大小,但出现错误:
(错误):CGBitmapContextCreate:无效数据字节/行:对于 8 个整数位/分量、3 个分量、kCGImageAlphaPremultipliedLast,应至少为 1708。
(当我提供一个较小的尺寸作为目标尺寸 BTW 时,我不会收到错误消息)。如何仅使用核心图形功能将UIImage
逆时针旋转 90 度,同时保留当前大小?
-(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;
【问题讨论】:
我找到了另一个有用的链接.. 希望这对某人有帮助.. mobiledevelopertips.com/user-interface/… 解决方案.......***.com/questions/5427656/… 我的问题是上传到 Amazon S3 的照片被旋转了。这个解决方案解决了视觉和上传的问题。 ***.com/questions/30701578/… hey nilam 看到这个后我会删除 【参考方案1】:我相信最简单的方法(也是线程安全的)是:
//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 所说,这只修改了图像的方向数据 - 像素数据未受影响。对于某些应用程序,这可能还不够。
或者在 Swift 中:
guard
let landscapeImage = UIImage(named: "imgname"),
let landscapeCGImage = landscapeImage.cgImage
else return
let portraitImage = UIImage(cgImage: landscapeCGImage, scale: landscapeImage.scale, orientation: .right)
【讨论】:
使其更通用:UIImage * origImg = [UIImage imageNamed:@"1.JPG"]; UIImage* fixed=[UIImage imageWithCGImage:[origImg CGImage] scale:1.0orientation:origImg.imageOrientation]; 这实际上并没有旋转图像。它复制图像并将图像的 imageFlags 属性的 imageOrientation 位设置为 0、1、2 或 3。某些类会忽略这些标志,例如 UIActivityViewController。如果您确实需要旋转图像,请参阅 Ben Groot 的回答,即 Hardy Macia 的 UIImage 扩展。 如果您的应用同时在视网膜和非视网膜屏幕上使用,则将比例设置为 1.0 将不起作用,您必须获取 originalImage.scale 并将其作为比例组件传递。 据我所知,似乎已停止在 ios10 中工作。let img = UIImage(cgImage: myImage!.cgImage!, scale: UIScreen.main.scale, orientation: .right)
【参考方案2】:
在 cutting-scaling-and-rotating-uiimages 上查看 Hardy Macia 的简单而出色的代码
只要打电话
UIImage *rotatedImage = [originalImage imageRotatedByDegrees:90.0];
感谢哈迪玛西亚!
标题:
- **(UIImage *)imageAtRect:(CGRect)rect;**
- **(UIImage *)imageByScalingProportionallyToMinimumSize:(CGSize)targetSize;**
- **(UIImage *)imageByScalingProportionallyToSize:(CGSize)targetSize;**
- **(UIImage *)imageByScalingToSize:(CGSize)targetSize;**
- **(UIImage *)imageRotatedByRadians:(CGFloat)radians;**
- **(UIImage *)imageRotatedByDegrees:(CGFloat)degrees;**
由于链接可能失效,这里是完整的代码
//
// 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;
【讨论】:
...链接已失效。 +1 包含完整代码【参考方案3】:类似的东西呢:
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;
【讨论】:
我的评论是 drawAtPoint 可能必须在调用后调用以设置正确的 RotateCTM。尝试将 drawAtPoint 移动到 UIGraphicsGetImageFromCurrentImageContext 之前 这不适用于后台线程。 UIGraphicsGetCurrentContext() 不是线程安全的,只能在主 (UI) 线程上调用。 对 CGContextRotateCTM() 的最后一次调用可能应该旋转 180,而不是 90。事实上,......向下可能应该旋转 180,而......向上可能不应该旋转。 在 iOS 4 及更高版本中,您可以从应用程序的任何线程调用 UIGraphicsGetCurrentContext 函数。 前后需要CGContextTranslateCTM(ctx, width/2, height/2)。【参考方案4】:这看起来很奇怪,下面的代码为我解决了这个问题:
+ (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;
【讨论】:
它之所以有效,是因为在矩形中绘制后不会保留图像方向。 是的,这将有助于从图像中删除方向 函数名应该是removeOrientationProperty【参考方案5】:线程安全的旋转函数如下(效果更好):
-(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;
【讨论】:
您的代码有问题...它在UIImageOrientationDown
的图像周围添加了一个奇怪的白框。
你不想调用 CGColorSpaceRelease(colorspace),见***.com/questions/5269815/…
对那个版本很抱歉【参考方案6】:
我对上述所有问题都有疑问,包括批准的答案。我将 Hardy 的类别转换回一种方法,因为我想要的只是旋转图像。下面是代码和用法:
- (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];
谢谢哈代!
【讨论】:
【参考方案7】:将图像旋转 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;
【讨论】:
这会增加图片尺寸【参考方案8】:这是一个 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
【讨论】:
效果很好!我对其进行了一些更改,以便可以交换宽度和高度: func rotate(byDegrees degree: Double, toSize: CGSize? = nil) -> UIImage let rotateSize = toSize ?? self.size 这不会正确设置图像的边界。您最终会得到一个超出原始边界的旋转图像。 非常感谢。令人惊讶的是我今天花了多少时间在这上面。【参考方案9】:如果您想添加一个照片旋转按钮,该按钮将继续以 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;
【讨论】:
【参考方案10】:简单。只需更改图像方向标志即可。
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];
【讨论】:
【参考方案11】: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 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()!)
【讨论】:
【参考方案12】:Swift 4.2 版本的RawMean's answer:
extension UIImage
func rotated(byDegrees degree: Double) -> UIImage
let radians = CGFloat(degree * .pi) / 180.0 as CGFloat
let rotatedSize = self.size
let scale = UIScreen.main.scale
UIGraphicsBeginImageContextWithOptions(rotatedSize, false, scale)
let bitmap = UIGraphicsGetCurrentContext()
bitmap?.translateBy(x: rotatedSize.width / 2, y: rotatedSize.height / 2)
bitmap?.rotate(by: radians)
bitmap?.scaleBy(x: 1.0, y: -1.0)
bitmap?.draw(
self.cgImage!,
in: CGRect.init(x: -self.size.width / 2, y: -self.size.height / 2 , width: self.size.width, height: self.size.height))
let newImage = UIGraphicsGetImageFromCurrentImageContext()
UIGraphicsEndImageContext() // this is needed
return newImage!
【讨论】:
气球增加了图像的重量。我的测试: 旋转前 =============================== 宽度 3024.0 高度 3024.0 大小 4952213 字节 ======= ======================= 旋转后========================= ===== 宽度 3024.0 高度 3024.0 大小 35191195 字节 ============================== 巴里是对的,这个方法改变了图像的权重。【参考方案13】:我尝试了这段代码,它工作正常,取自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;
【讨论】:
【参考方案14】:对基于 Hardy Macia 代码的其他答案进行了微小更改。无需简单地创建整个UIView
对象来计算旋转图像的边界矩形。只需使用 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;
【讨论】:
【参考方案15】:“tint uiimage grayscale”似乎是适合这个的 Google-Fu
我马上就明白了:
https://discussions.apple.com/message/8104516?messageID=8104516�
https://discussions.apple.com/thread/2751445?start=0&tstart=0
How would I tint an image programmatically on the iPhone?
【讨论】:
【参考方案16】:我喜欢Peter Sarnowski
的简单优雅的回答,但是当您不能依赖EXIF
元数据等时,它可能会导致问题。在您需要旋转实际图像数据的情况下,我建议您这样做:
- (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 Left
还是Landscape Right
)并将其旋转为Portrait
。这是一个可以根据您的需要进行修改的示例。
您必须使用的关键参数是CGContextRotateCTM(context, M_PI_2)
,您可以在其中决定要旋转多少,但是您必须确保使用CGContextTranslateCTM(context, 0, -640)
仍然在屏幕上绘制图片。最后一部分对于确保您看到图像而不是空白屏幕非常重要。
欲了解更多信息,请查看source。
【讨论】:
对断开的链接投反对票,并且没有解释 -640 幻数。修复后会反转。【参考方案17】:resize-a-uiimage-the-right-way 解释了许多代码示例中的一些问题,并且有一些代码 sn-ps 来帮助处理 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.
【讨论】:
【参考方案18】:有一个非常高效的 UIImage 类别,名为 NYXImagesKit。它使用 vDSP、CoreImage 和 vImage 尽可能快。它有一个 UIImage+Rotating 类别拯救了我的一天:)
https://github.com/Nyx0uf/NYXImagesKit
【讨论】:
【参考方案19】:对于 Swift:这是 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,前者将旋转图像并翻转它。
【讨论】:
你能解释一下吗? 由于某种原因,这似乎与纵横比混淆以上是关于如何将 UIImage 旋转 90 度?的主要内容,如果未能解决你的问题,请参考以下文章