重现问题:
拍照获得的图片,由于尺寸不对,需要拆切.但是有的图片拆切出来,方向就乱了.查找了一些质量才知道.图片还有个方向属性! imageOrientation.
一个图片包含两个方面的信息:
-
数据本身: 每个像素的颜色值.
-
文件头: 图片的基本信息.比如:图片的宽高.图片的方向信息.
为什么会有图片方向?
为了让照片可以真实的反应人们拍摄时看到的场景,现在很多相机中就加入了方向传感器,它能够记录下拍摄时相机的方向,并将这一信息保存在照片中。照片的存储方式还是没有任何改变,它仍然是以相机的坐标系来保存,只是当相机来浏览这些照片时,相机可以根据照片中的方向信息,结合此时相机的方向,对照片进行旋转,从而转到适合人们观看的角度。
什么叫EXIF?
维基百科上对其的解释为:
可交换图像文件格式常被简称为Exif(Exchangeable image file format),是专门为数码相机的照片设定的,可以记录数码照片的属性信息和拍摄数据… Exif可以附加于JPEG、TIFF、RIFF等文件之中.
什么叫Orientation?
在EXIF涵盖的各种信息之中,其中有一个叫做Orientation (rotation)的标签,用于记录图像的方向,这便是相机写入方向信息的最终位置。它总共定义了八个值:
注意:对于上面的八种方向中,加了*的并不常见,因为它们代表的是镜像方向,如果不做任何的处理,不管相机以任何角度拍摄,都无法出现镜像的情况。
这个表格代表什么意义?我们来看第一行,值为1时,右边两列的值分别为:Row #0 is Top,Column #0 is Left side,其实很好理解,它表示照片的第一行位于顶端,而第一列位于左侧,那么这张照片自然就是以正常角度拍摄的。
什么时候会造成图片方向不对?
用相机拍摄出来的照片含有EXIF信息,UIImage的imageOrientation属性指的就是EXIF中的orientation信息。
如果我们忽略orientation信息,而直接对照片进行像素处理或者drawInRect等操作,得到的结果是翻转或者旋转90之后的样子。这是因为我们执行像素处理或者drawInRect等操作之后,imageOrientaion信息被删除了,imageOrientaion被重设为0,造成照片内容和imageOrientaion不匹配。
所以,在对照片进行处理之前,先将照片旋转到正确的方向,并且返回的imageOrientaion为0。
在iOS中又是怎么处理
UIImageOrientationUp
如下截图是苹果官方文档对 UIImageOrientationUp 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

左边的图片是正常显示,不需要做任何调整
UIImageOrientationDown
如下截图是苹果官方文档对 UIImageOrientationDown 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

从图中可以看出图片颠倒了过来,如果要吧左图还原成右边的图片,要做的是把图片顺时针旋转180度
UIImageOrientationLeft
如下截图是苹果官方文档对 UIImageOrientationLeft 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

从图中可以看出来,右边的图片通过顺时针旋转90度得到左边的图片,如果要把左边的图片还原成右边的图片,需要顺时针旋转270度
UIImageOrientationRight
如下截图是苹果官方文档对 UIImageOrientationRight 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

从上图中可以看出来,右边图片通过顺时针旋转270度后得到左边的图片,如果需要把左边图片还原成右边图片,需要顺时针旋转90度
UIImageOrientationUpMirrored
如下截图是苹果官方文档对 UIImageOrientationRight 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

从上图中可以看出来,右边的图片通过水平翻转得到左边图片,如果需要把左边图片还原成右边图片,需要做一次水平翻转
UIImageOrientationDownMirrored
如下截图是苹果官方文档对 UIImageOrientationRight 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

从上图中可以看出来,右边的图片通过垂直翻转得到左边图片,如果需要把左边图片还原成右边图片,需要做一次垂直翻转
UIImageOrientationLeftMirrored
如下截图是苹果官方文档对 UIImageOrientationLeftMirrored 的描述,左图是未修正方向的图片,右图是正确显示的图片

从图中也不难看出,右图通以下两个步骤
- 第一步,过顺指针旋转90度;
- 第二部,再做一次水平翻转,
若要把左图还原成右图,执行同样的步骤即可
- 第一步,顺时针旋转90度;
- 第二步,水平翻转;
UIImageOrientationRightMirrored
如下截图是苹果官方文档对 UIImageOrientationRightMirrored 的描述,左图是未修正方向的图片,右图是正确显示的图片

从上图也不难看出,右图通过以下两个步骤得到左图
- 第一步,顺时针旋转90度;
- 第二步,垂直翻转;
若要把左图还原成右图,执行同样的步骤即可
- 第一步,顺时针旋转90度;
- 第二步,垂直翻转;
在iOS中解决图片方向不对的方法有两种
第一种,纠正方向,代码如下
- (UIImage *)fixOrientation {
//图片不需要调整
if (self.imageOrientation == UIImageOrientationUp) {
return self;
}
CGAffineTransform transform = CGAffineTransformIdentity;
//旋转
switch (self.imageOrientation) {
//顺时针旋转 180度
case UIImageOrientationDown:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformRotate(transform, M_PI);
break;
//顺时针旋转270度
case UIImageOrientationLeft:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformRotate(transform, M_PI_2 * 3);
break;
//顺时针旋转90度
case UIImageOrientationRight:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformRotate(transform, M_PI_2);
break;
//做一次水平翻转
case UIImageOrientationUpMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformScale(transform, -1, 1);
break;
//做一次垂直翻转
case UIImageOrientationDownMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformScale(transform, 1, -1);
break;
/**
1. 第一步,顺时针旋转90度;
2. 第二步,水平翻转;
*/
case UIImageOrientationLeftMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformScale(transform, -1, 1);
break;
/**
1. 第一步,顺时针旋转90度;
2. 第二步,垂直翻转;
*/
case UIImageOrientationRightMirrored:
transform = CGAffineTransformTranslate(transform, self.size.width, 0);
transform = CGAffineTransformRotate(transform, M_PI_2);
transform = CGAffineTransformTranslate(transform, self.size.width, self.size.height);
transform = CGAffineTransformScale(transform, 1, -1);
break;
default:
break;
}
// 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 *)normalizedImage {
if (self.imageOrientation == UIImageOrientationUp) return self;
UIGraphicsBeginImageContextWithOptions(self.size, NO, self.scale);
[self drawInRect:(CGRect){0, 0, self.size}];
UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return normalizedImage;
}
参考文章1:https://developer.apple.com/documentation/uikit/uiimageorientation?language=objc
参考文章2:https://www.cnblogs.com/mancong/p/6208682.html
参考文章3:https://www.jianshu.com/p/473201923d8e
网友评论