如何旋转UIImage 90度?
我有一个UIImage
是UIImageOrientationUp
(肖像),我想逆时针旋转90度(横向)。 我不想使用CGAffineTransform
。 我想要UIImage
的像素实际移位。 我正在使用一个代码块(如下所示)最初打算调整一个UIImage
来做到这一点。 我设置一个目标大小作为UIImage
的当前大小,但我得到一个错误:
(错误):CGBitmapContextCreate:无效的数据字节/行:对于8个整数位/分量应该是至少1708,3个分量,kCGImageAlphaPremultipliedLast。
(当我提供一个SMALLER大小作为目标大小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; }
那样的事情呢?
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; }
我相信最简单的方法(也是线程安全)是:
//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中:
let portraitImage : UIImage = UIImage(CGImage: landscapeImage.CGImage , scale: 1.0 , orientation: UIImageOrientation.Right)
看看哈代马西亚简单而强大的代码: 切割和旋转uiimages
打电话
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)弧度;
- (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;
看起来很奇怪,下面的代码为我解决了这个问题:
+ (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; }
一个线程安全的旋转函数如下(它工作得更好):
-(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; }
我遇到了上述问题,包括核准的答案。 我把哈代的范畴转换成了一个方法,因为我只想旋转一个图像。 以下是代码和用法:
- (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];
谢谢哈代!
将图像旋转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; }
如果你想添加一个照片旋转按钮,将继续旋转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; }
简单。 只要改变图像方向标志。
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];
这是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 } }
我喜欢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)
。 这最后一部分是非常重要的,以确保您看到的图像,而不是一个空白的屏幕。
欲了解更多信息,请查看源代码 。
我尝试这个代码,它的工作原理,从http://www.catamount.com/blog/1015/uiimage-extensions-for-cutting-scaling-and-rotating-uiimages/
+ (UIImage *)rotateImage:(UIImage*)src byRadian:(CGFloat)radian { // calculate the size of the rotated view's containing box for our drawing space UIView *rotatedViewBox = [[UIView alloc] initWithFrame:CGRectMake(0,0, src.size.width, src.size.height)]; CGAffineTransform t = CGAffineTransformMakeRotation(radian); rotatedViewBox.transform = t; CGSize rotatedSize = rotatedViewBox.frame.size; // Create the bitmap context UIGraphicsBeginImageContext(rotatedSize); CGContextRef bitmap = UIGraphicsGetCurrentContext(); // Move the origin to the middle of the image so we will rotate and scale around the center. CGContextTranslateCTM(bitmap, rotatedSize.width/2, rotatedSize.height/2); // // Rotate the image context CGContextRotateCTM(bitmap, radian); // Now, draw the rotated/scaled image into the context CGContextScaleCTM(bitmap, 1.0, -1.0); CGContextDrawImage(bitmap, CGRectMake(-src.size.width / 2, -src.size.height / 2, src.size.width, src.size.height), [src CGImage]); UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return newImage; }
Swift 3 UIImage扩展:
func fixOrientation() -> UIImage { // No-op if the orientation is already correct if ( self.imageOrientation == .up ) { return self; } // We need to calculate the proper transformation to make the image upright. // We do it in 2 steps: Rotate if Left/Right/Down, and then flip if 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()!) }
对基于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; }
“tint uiimage grayscale”似乎是适合这个的Google-Fu
马上我得到:
https://discussions.apple.com/message/8104516?messageID=8104516
https://discussions.apple.com/thread/2751445?start=0&tstart=0
如何在iPhone上以编程方式着色图像?
resize-a-uiimage-the-right-way解释了许多代码示例所做的一些问题,并且有一些代码片段来帮助处理UIImage – 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; }
This is the license from that file:
// Created by Trevor Harmon on 8/5/09. // Free for personal or commercial use, with or without modification. // No warranty is expressed or implied.
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 🙂
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 } }
( 来源 )
Use it with:
rotatedPhoto = rotatedPhoto?.imageRotatedByDegrees(90, flip: false)
The former will rotate an image and flip it if flip is set to true.