如何将 UIImage 旋转90度?

我有一个 UIImage,这是 UIImageOrientationUp(肖像) ,我想旋转逆时针90度(景观)。我不想用 CGAffineTransform。我希望 UIImage的像素能真正移动位置。我使用的代码块(如下所示)最初打算调整一个 UIImage的大小,以做到这一点。我将目标大小设置为 UIImage的当前大小,但得到一个错误:

(错误) : CGBitmapContextCreate: 无效数据字节/行: 对于8个整数位/组件,3个组件,应该至少为1708。

(我没有得到一个错误,每当我提供一个较小的大小作为目标大小 BTW)。我如何可以旋转我的 UIImage90度 CCW 只使用核心图形功能,同时保留当前的大小?

-(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;
}
188815 次浏览

比如说:

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

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.

查看 Hardy Macia 的简单和令人敬畏的代码: 切割缩放旋转图像

打电话吧

UIImage *rotatedImage = [originalImage imageRotatedByDegrees:90.0];

谢谢 Hardy Macia!

标题:

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

我认为最简单的方法(也是线程安全的方法)是这样做:

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

注意: 正如 脑器所说,这只是修改了图像的方向数据-像素数据没有被触及。对于某些应用程序,这可能还不够。

或者用斯威夫特的话说:

guard
let landscapeImage = UIImage(named: "imgname"),
let landscapeCGImage = landscapeImage.cgImage
else { return }
let portraitImage = UIImage(cgImage: landscapeCGImage, scale: landscapeImage.scale, orientation: .right)

线程安全的旋转函数如下所示(它工作得更好) :

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

我喜欢 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)在屏幕上绘制。最后一部分非常重要,以确保您看到的是图像,而不是一个空白屏幕。

更多信息请查看 来源

如果您想添加一个照片旋转按钮,将保持旋转的照片在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*)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 *)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];

谢谢你,哈代!

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

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

Https://github.com/nyx0uf/nyximageskit

很简单,只要更改图像方向标志。

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

对于 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
}
}

(来源)

配合以下句子使用:

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

前者将旋转一个图像,并翻转它,如果翻转设置为真。

旋转图像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;
}

对基于 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;
}

下面是 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
}
}

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()!)
}

Swift 4.2版 RawMean 的回答:

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!
}


}