0%

优雅处理 UIImage 图片旋转

UIImag 构造方式

UIImag 构造方式大致有 4 种方式

  • 从本地 bundle 中加载 imageNamed: ,传入一个 bundle 的文件名即可
  • 从本地一个文件路径读取 imageWithContentsOfFile: ,需要传一个文件的文件路径 path
  • 通过二进制数据 NSData 来创建 imageWithData: * 通过一个 CoreGraphicsCGImageRef 来创建, initWithCGImage: * 通过一个 CoreImageCIImage 来创建 initWithCIImage 通过查阅 Apple 官网文档我们发现有 2 个这样的方法,今天就来一探究竟
1
2
3
4
5
+ (UIImage *)imageWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation NS_AVAILABLE_IOS(4_0);
+ (UIImage *)imageWithCIImage:(CIImage *)ciImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation NS_AVAILABLE_IOS(6_0);

- (instancetype)initWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation NS_AVAILABLE_IOS(4_0);
- (instancetype)initWithCIImage:(CIImage *)ciImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation NS_AVAILABLE_IOS(6_0);

2 个类方法 2 个实例方法都是类似,这里以 CGImageRef 为例

1
+ (UIImage *)imageWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation NS_AVAILABLE_IOS(4_0);
  1. 新建的 Xcode 工程选择 single Application

  2. 在 storyboard 中拖一个 UIImageView 设置它水平垂直居中对齐,宽带高度随便设一个值不要太大就行,设置 UIImageViewcontentModeAspect Fit 方便查看以免变形

  3. UIImageView 下发放一个 UIButton 控件方便后面好对图片进行旋转操作

  4. 在 viewController 中建立一个 UIImageView 引用,拉出一个 rotate 按钮的 IBAction 现在大概界面大概这样
    UIImageOrientation 效果图

  5. 下面我们实现
    - (IBAction)rotateImage:(id)sender {} 这个方法

在这里我们想通过点击按钮实现图片旋转
为了方便使用我们使用 Category 的方式实现
新建一个 UIImage 的分类取名叫 Rotate

这里需要传一张要处理的图片和一个待处理成的图片方向

1
2
+ (UIImage *)rotateImage:(UIImage *)oldImage
orientation:(UIImageOrientation)orientation;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
    + (UIImage *)rotateImage:(UIImage *)oldImage orientation:(UIImageOrientation)orientation{

UIImage *newImage = [UIImage imageWithCGImage:oldImage.CGImage scale:1 orientation:orientation];

NSString *orientationStr = nil;
switch (orientation) {
case UIImageOrientationUp: {
orientationStr = @"UIImageOrientationUp";
break;
}
case UIImageOrientationDown: {
orientationStr = @"UIImageOrientationDown";
break;
}
case UIImageOrientationLeft: {
orientationStr = @"UIImageOrientationLeft";
break;
}
case UIImageOrientationRight: {
orientationStr = @"UIImageOrientationRight";
break;
}
case UIImageOrientationUpMirrored: {
orientationStr = @"UIImageOrientationUpMirrored";
break;
}
case UIImageOrientationDownMirrored: {
orientationStr = @"UIImageOrientationDownMirrored";
break;
}
case UIImageOrientationLeftMirrored: {
orientationStr = @"UIImageOrientationLeftMirrored";
break;
}
case UIImageOrientationRightMirrored: {
orientationStr = @"UIImageOrientationRightMirrored";
break;
}

}

NSLog(@"current orientation: %@",orientationStr);

return newImage;
}

在 button 点击事件触发时的这样使用

1
2
3
4
5
6
7
8
- (IBAction)rotateImage:(id)sender {

UIImage *oldImage = self.imgView.image;

UIImage *rotatedImage = [UIImage rotateImage:oldImage orientation:UIImageOrientationLeft];

self.imgView.image = rotatedImage;
}

点击按钮测试发现第一次没问题,但是重逢点击无效
原来 + (UIImage *)imageWithCGImage:(CGImageRef)cgImage scale:(CGFloat)scale orientation:(UIImageOrientation)orientation 方法执行原理是执行前通过 @property(nonatomic,readonly) UIImageOrientation imageOrientation; 接口先判断当前图片的方向是否为将要旋转的方向,如果是就直接返回不做处理,如果不是再作旋转处理,也就是说这个方法并没有实际上旋转 image 的数据,只是用一个枚举标记旋转的状态

如果我们想每次旋转需要直接改变原始 image 的数据该怎么办呢?
在这里我们通过 CGBitmapContext ,使用 CGContextRotateCTM 来设置旋转,再把 UIImage 通过 drawInRect 重新绘制出来,通过 UIGraphicsGetImageFromCurrentImageContext 获得处理后的图片

下面是具体实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
- (UIImage *)fixedRotation{
if (self.imageOrientation == UIImageOrientationUp) return self;
CGAffineTransform transform = CGAffineTransformIdentity;

switch (self.imageOrientation) {
case UIImageOrientationDown:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;

case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;

case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, 0, self.size.height);
transform = CGAffineTransformRotate(transform, -M_PI_2);
break;
case UIImageOrientationUp:
case UIImageOrientationUpMirrored:
break;
}

switch (self.imageOrientation) {
case UIImageOrientationUpMirrored:
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;

case UIImageOrientationLeftMirrored:
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, self.size.height, 0);
transform = CGAffineTransformScale(transform, -1, 1);
break;
case UIImageOrientationUp:
case UIImageOrientationDown:
case UIImageOrientationLeft:
case UIImageOrientationRight:
break;
}

// Now we draw the underlying CGImage into a new context, applying the transform
// calculated above.
CGContextRef ctx = CGBitmapContextCreate(NULL, self.size.width, self.size.height,
CGImageGetBitsPerComponent(self.CGImage), 0,
CGImageGetColorSpace(self.CGImage),
CGImageGetBitmapInfo(self.CGImage));
CGContextConcatCTM(ctx, transform);
switch (self.imageOrientation) {
case UIImageOrientationLeft:
case UIImageOrientationLeftMirrored:
case UIImageOrientationRight:
case UIImageOrientationRightMirrored:
// Grr...
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.height,self.size.width), self.CGImage);
break;

default:
CGContextDrawImage(ctx, CGRectMake(0,0,self.size.width,self.size.height), self.CGImage);
break;
}

// And now we just create a new UIImage from the drawing context
CGImageRef cgimg = CGBitmapContextCreateImage(ctx);
UIImage *img = [UIImage imageWithCGImage:cgimg];
CGContextRelease(ctx);
CGImageRelease(cgimg);
return img;

}

现在再优化一下原来 + (UIImage *)rotateImage:(UIImage *)oldImage orientation:(UIImageOrientation)orientation 方法,修改成这样

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
+ (UIImage *)rotateImage:(UIImage *)oldImage orientation:(UIImageOrientation)orientation{

UIImage *newImage = [UIImage imageWithCGImage:oldImage.CGImage scale:1 orientation:orientation];

//fix original Image with gived orientation.
UIImage *fixedRotationImage = [newImage fixedRotation];

NSString *orientationStr = nil;
switch (orientation) {
case UIImageOrientationUp: {
orientationStr = @"UIImageOrientationUp";
break;
}
case UIImageOrientationDown: {
orientationStr = @"UIImageOrientationDown";
break;
}
case UIImageOrientationLeft: {
orientationStr = @"UIImageOrientationLeft";
break;
}
case UIImageOrientationRight: {
orientationStr = @"UIImageOrientationRight";
break;
}
case UIImageOrientationUpMirrored: {
orientationStr = @"UIImageOrientationUpMirrored";
break;
}
case UIImageOrientationDownMirrored: {
orientationStr = @"UIImageOrientationDownMirrored";
break;
}
case UIImageOrientationLeftMirrored: {
orientationStr = @"UIImageOrientationLeftMirrored";
break;
}
case UIImageOrientationRightMirrored: {
orientationStr = @"UIImageOrientationRightMirrored";
break;
}

}

NSLog(@"current orientation: %@",orientationStr);

return fixedRotationImage;
}

现在再测试一下,well,It‘s OK。

have fun!!!

参考资料

备注:欢迎转载,但请一定注明出处! http://blog.wangruofeng007.com