美文网首页
UIImage 方向问题-UIImageOrientation

UIImage 方向问题-UIImageOrientation

作者: 朽木自雕也 | 来源:发表于2019-01-24 17:03 被阅读0次

重现问题:

拍照获得的图片,由于尺寸不对,需要拆切.但是有的图片拆切出来,方向就乱了.查找了一些质量才知道.图片还有个方向属性! imageOrientation.

一个图片包含两个方面的信息:

  1. 数据本身: 每个像素的颜色值.

  2. 文件头: 图片的基本信息.比如:图片的宽高.图片的方向信息.

为什么会有图片方向?

为了让照片可以真实的反应人们拍摄时看到的场景,现在很多相机中就加入了方向传感器,它能够记录下拍摄时相机的方向,并将这一信息保存在照片中。照片的存储方式还是没有任何改变,它仍然是以相机的坐标系来保存,只是当相机来浏览这些照片时,相机可以根据照片中的方向信息,结合此时相机的方向,对照片进行旋转,从而转到适合人们观看的角度。

什么叫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 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

UIImageOrientationUp

左边的图片是正常显示,不需要做任何调整

UIImageOrientationDown

如下截图是苹果官方文档对 UIImageOrientationDown 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

UIImageOrientationDown

从图中可以看出图片颠倒了过来,如果要吧左图还原成右边的图片,要做的是把图片顺时针旋转180度

UIImageOrientationLeft

如下截图是苹果官方文档对 UIImageOrientationLeft 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

UIImageOrientationLeft

从图中可以看出来,右边的图片通过顺时针旋转90度得到左边的图片,如果要把左边的图片还原成右边的图片,需要顺时针旋转270度

UIImageOrientationRight

如下截图是苹果官方文档对 UIImageOrientationRight 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

UIImageOrientationRight

从上图中可以看出来,右边图片通过顺时针旋转270度后得到左边的图片,如果需要把左边图片还原成右边图片,需要顺时针旋转90度

UIImageOrientationUpMirrored

如下截图是苹果官方文档对 UIImageOrientationRight 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片

UIImageOrientationUpMirrored

从上图中可以看出来,右边的图片通过水平翻转得到左边图片,如果需要把左边图片还原成右边图片,需要做一次水平翻转

UIImageOrientationDownMirrored

如下截图是苹果官方文档对 UIImageOrientationRight 的描述,图片的左边是未修正方向的图片,图片的右边是正确显示的图片


UIImageOrientationDownMirrored

从上图中可以看出来,右边的图片通过垂直翻转得到左边图片,如果需要把左边图片还原成右边图片,需要做一次垂直翻转

UIImageOrientationLeftMirrored

如下截图是苹果官方文档对 UIImageOrientationLeftMirrored 的描述,左图是未修正方向的图片,右图是正确显示的图片


UIImageOrientationLeftMirrored

从图中也不难看出,右图通以下两个步骤

  1. 第一步,过顺指针旋转90度;
  2. 第二部,再做一次水平翻转,

若要把左图还原成右图,执行同样的步骤即可

  1. 第一步,顺时针旋转90度;
  2. 第二步,水平翻转;

UIImageOrientationRightMirrored

如下截图是苹果官方文档对 UIImageOrientationRightMirrored 的描述,左图是未修正方向的图片,右图是正确显示的图片


UIImageOrientationRightMirrored

从上图也不难看出,右图通过以下两个步骤得到左图

  1. 第一步,顺时针旋转90度;
  2. 第二步,垂直翻转;

若要把左图还原成右图,执行同样的步骤即可

  1. 第一步,顺时针旋转90度;
  2. 第二步,垂直翻转;

在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

相关文章

网友评论

      本文标题:UIImage 方向问题-UIImageOrientation

      本文链接:https://www.haomeiwen.com/subject/utsmjqtx.html