内容简介:刚开始使用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
是不会真正的修改图片像素点的位置,只是给图片设置一个合适的方向(参照当前视频的正确方向)属性。
罪魁祸首
在了解了 UIImageOrientation
和 AVCaptureVideoOrientation
后,我们就来解答开篇问题,找出引发这个问题的“罪魁祸首”。
下面的讲解中,我简单把图片看成是两个部分组成:
- 图片数据
- 图片方向
在图片采集的时候,图片数据是按照相机获取的数据。平时我们都是都认HOME键在下方是正确的方向,但是对于相机,他正确的方向是 摄像头在用户的左上方 的情况,即 HOME键在右边 的情况:
PS: 图片数据的方向 就是 相机的方向
因此在 videoOrientation
为 AVCaptureVideoOrientationPortrait
的情况下,图片数据效果就是右侧的图片。虽然他的图片方向是 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 支持横屏,有的不支持。在方向问题解决上是有两种主要的解决方向的:
- 不支持横屏:
- 固定死 AVCaptureConnection 的
videoOrientation
属性,一般就支持AVCaptureVideoOrientationPortrait
- 在获取图片的时候根据设备当前物理方向(
[UIDevice currentDevice].orientation
)进行变换(CATransform
)
- 固定死 AVCaptureConnection 的
- 支持横屏:
- 在每次确定方向(
videoOrientation
)的时候,都需要获取最新的videoOrientation
- 在每次确定方向(
PS: AVCaptureConnection 在 input
发生变化的时候,会跟着变化。比如切换前后摄像头, old input
被移除, new input
被添加,最后会导致 connection
的替换。
至此就是我在图片采集遇到的一个问题和解决方法。大家有什么意见或者建议,欢迎在评论区中提出。
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
Head First JavaScript Programming
Eric T. Freeman、Elisabeth Robson / O'Reilly Media / 2014-4-10 / USD 49.99
This brain-friendly guide teaches you everything from JavaScript language fundamentals to advanced topics, including objects, functions, and the browser’s document object model. You won’t just be read......一起来看看 《Head First JavaScript Programming》 这本书的介绍吧!