图片采集的方向问题

栏目: IOS · 发布时间: 5年前

内容简介:刚开始使用AVFoundation进行采集的时候,经常会发现采集回来的图片方向不对。一般我们都是垂直(HOME键在底部)操作手机,但是在手机用相册或者在电脑上点开采集的图片时,都会发现日常开发中,在平时我们并没有发现
图片采集的方向问题

刚开始使用AVFoundation进行采集的时候,经常会发现采集回来的图片方向不对。一般我们都是垂直(HOME键在底部)操作手机,但是在手机用相册或者在电脑上点开采集的图片时,都会发现 图片逆时针旋转了90度 。为了发现问题的所在,我们需要了解一下通常在图片采集中我们会遇到的各种方向。

图片方向 UIImageOrientation

日常开发中, UIImage 是一个使用频率很高的类,但是一般我们并不太在意他的方向问题。我们可以通过 imageOrientation 属性获取 UIImage 的图片方向,即 UIImageOrientation 。该方向总共有八种情况,用于表示当前图片的方向状态:

UIImageOrientationUp
UIImageOrientationDown
UIImageOrientationLeft
UIImageOrientationRight
UIImageOrientationUpMirrored
UIImageOrientationDownMirrored
UIImageOrientationLeftMirrored
UIImageOrientationRightMirrored

在平时我们并没有发现 UIImage 的显示方向有问题,是因为它在显示的时候会根据当前图片的 imageOrientation 属性,进行相应的转换,即 逆操作 。如果值是 UIImageOrientationLeft 则表示图片在显示的时候,需要顺时针旋转90度。

简单来说, UIImageOrientation 就是告诉我们该图像的方向属于什么状态,在显示时候是需要做一个逆操作来让图像真正变成我们想要的方向。

回到文章一开始的问题, 图片逆时针旋转了90度 是因为当前的图像的像素点数据是真的逆时针旋转了90度。虽然整个图片中是有图片方向这个属性的,但是在用文件显示图片的过程中, 系统并不会根据该属性进行逆操作 ,而是耿直的直接显示了。

视频方向 AVCaptureVideoOrientation

在进行媒体的采集中,无论是进行拍照和录像,都会有一个相似的操作,即设置连接的 videoOrientation 属性。系统是不知道你视频图片的正确方向的,只能 通过 videoOrientation 的值来进行图片方向的设置 。视频方向一共有四个,这里使用Home键的位置进行解释:

AVCaptureVideoOrientationPortrait
AVCaptureVideoOrientationPortraitUpsideDown
AVCaptureVideoOrientationLandscapeRight
AVCaptureVideoOrientationLandscapeLeft

简单来说, AVCaptureVideoOrientation 是不会真正的修改图片像素点的位置,只是给图片设置一个合适的方向(参照当前视频的正确方向)属性。

罪魁祸首

在了解了 UIImageOrientationAVCaptureVideoOrientation 后,我们就来解答开篇问题,找出引发这个问题的“罪魁祸首”。

下面的讲解中,我简单把图片看成是两个部分组成:

  • 图片数据
  • 图片方向

在图片采集的时候,图片数据是按照相机获取的数据。平时我们都是都认HOME键在下方是正确的方向,但是对于相机,他正确的方向是 摄像头在用户的左上方 的情况,即 HOME键在右边 的情况:

图片采集的方向问题

PS: 图片数据的方向 就是 相机的方向

因此在 videoOrientationAVCaptureVideoOrientationPortrait 的情况下,图片数据效果就是右侧的图片。虽然他的图片方向是 UIImageOrientationLeft ,但是一般的文件显示都是直接显示他原来的面貌。因此, 用户看到的和我们最终保存的图片颠倒“罪魁祸首”就是相机的原始方向与我们的预期不符合

解决方法

图片本身是没错的,错的是显示的时候没有没有按图片方向进行逆操作。那么,我们只要在每次采集到图片的时候对图片进行一次逆操作,让图片数据直接变成与“ 图片数据+图片方向 ”的效果即可:

- (UIImage *)fixOrientation
{
    // No-op if the orientation is already correct
    if (self.imageOrientation == UIImageOrientationUp) 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.
    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;
}
复制代码

PS:新生成的图片 imageOrientation 是默认的 UIImageOrientationUp

采集方向解决方向

有的 App 支持横屏,有的不支持。在方向问题解决上是有两种主要的解决方向的:

  • 不支持横屏:
    1. 固定死 AVCaptureConnection 的 videoOrientation 属性,一般就支持 AVCaptureVideoOrientationPortrait
    2. 在获取图片的时候根据设备当前物理方向( [UIDevice currentDevice].orientation )进行变换( CATransform )
  • 支持横屏:
    1. 在每次确定方向( videoOrientation )的时候,都需要获取最新的 videoOrientation

PS: AVCaptureConnection 在 input 发生变化的时候,会跟着变化。比如切换前后摄像头, old input 被移除, new input 被添加,最后会导致 connection 的替换。

至此就是我在图片采集遇到的一个问题和解决方法。大家有什么意见或者建议,欢迎在评论区中提出。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Scrum敏捷软件开发

Scrum敏捷软件开发

Mike Cohn / 廖靖斌、吕梁岳、陈争云、阳陆育 / 清华大学出版社 / 2010-11 / 69.00元

《Scrum敏捷软件开发》是敏捷联盟及Scrum联盟创始人之一、敏捷估算及计划的鼻祖Mike Cohn三大经典著作中影响最为深厚的扛鼎之作,也是全球敏捷社区中获得广泛肯定的企业敏捷转型权威参考。作者花四年时间,把自己近十五年的敏捷实践经验,特别是近四年中针对各种敏捷转型企业的咨询和指导工作,并结合旁征博引的方式,从更高的思想层次对敏捷与Scrum多年来的经验和教训进行深入而前面的梳理和总结,最终集......一起来看看 《Scrum敏捷软件开发》 这本书的介绍吧!

CSS 压缩/解压工具
CSS 压缩/解压工具

在线压缩/解压 CSS 代码

随机密码生成器
随机密码生成器

多种字符组合密码

URL 编码/解码
URL 编码/解码

URL 编码/解码