iOS自定义拍照框拍照&裁剪(一)

  • 卡片机时代

很重要的一点是,相机本身是没有方向概念的,它不理解拍摄的内容,只会以相机自己的坐标系去保存数据,下图展示了相机对“F”进行四个角度拍摄时返回的图片数据。

最初的卡片机时代,照片都会经由底片洗出来,那时不存在照片的方向问题,我们总可以把洗出来的照片通过简单的旋转来进行观看。比如这张照片墙中的照片,你能否说哪些照片是横着?哪些颠倒着?你甚至都无法判断每张照片相机是以何种角度拍摄的,因为每张都已经旋转至适合观看的角度。

  • 数码时代

可是到了数码时代,不再需要底片,照片需要被存成一个图像文件。对于上面的拍摄角度,存储方式并没有变化,所有的场景仍然是以相机的坐标系来保存。于是这些照片仍像上面一样,原封不动的保存了下来。

虽然存储方式不变,和卡机机时代的实体相片不同的是,由于电子设备可不知道照片应该如何旋转,只能够以它存储于磁盘中的方向来展示。这便是为何照片传到电脑上之后,会出现横了,或者颠倒的情况。
  • 方向传感器

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

在iOS的设备中也包含了方向传感器,它但是它默认的照片方向并不是竖着拿手机时的情况,而是横向,即Home键在右侧,如下:

如此一来,如果竖着拿手机拍摄时,就相当于对手机顺时针旋转了90度,也即上面相机图片中的最后一幅

  • iPhone拍照方向问题处理

iPhone通过API获取到的是图片内容数据,不带方向信息,此时,我们需要手动的根据传感器方向将方向信息填充进去,并且根据方向信息对照片进行相应的旋转,得到人类视角正向的图片。代码如下:

//iOS11以上支持AVCapturePhotoOutput代理
- (void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhoto:(AVCapturePhoto *)photo
                error:(NSError *)error {
    if (error) {
            NSLog(@"获取图片错误 --- %@",error.localizedDescription);
        }
        if (photo) {
           UIImageOrientation orient = UIImageOrientationUp;
            //后置摄像头
            if (self.shootingOrientation == UIDeviceOrientationLandscapeRight){
                orient = UIImageOrientationDown;
            }else if(self.shootingOrientation == UIDeviceOrientationPortrait){
                orient = UIImageOrientationRight;
            }else if(self.shootingOrientation == UIDeviceOrientationLandscapeLeft){
                orient = UIImageOrientationUp;
            }else if(self.shootingOrientation == UIDeviceOrientationPortraitUpsideDown){
                orient = UIImageOrientationLeft;
            }
            //前置摄像头
            AVCaptureDevice *currentDevice = [self.videoWriterManager.videoInput device];
            AVCaptureDevicePosition currentPosition = [currentDevice position];
            if (currentPosition == AVCaptureDevicePositionFront){
                //前置摄像头
                if (self.shootingOrientation == UIDeviceOrientationLandscapeRight){
                    orient = UIImageOrientationUp;
                }else if(self.shootingOrientation == UIDeviceOrientationLandscapeLeft){
                    orient = UIImageOrientationDown;
                }
            }
            UIImage *image = [UIImage imageWithCGImage:photo.CGImageRepresentation scale:1 orientation:orient];
            //图片修正为人类视角看起来正向的图片
            //[self fixOrientation:image];
        }
}


//将原始图片数据调整为 人类视角正向的图片
- (UIImage *)fixOrientation:(UIImage *)image{
    // No-op if the orientation is already correct
    if (image.imageOrientation == UIImageOrientationUp) return image;
    
    // 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;
    CGFloat imageWidth = CGImageGetWidth(image.CGImage);
    CGFloat imageHeight = CGImageGetHeight(image.CGImage);
    //创建的位图宽高
    CGFloat contextWidth = imageWidth < imageHeight ? imageWidth : imageHeight;
    CGFloat contextHeight = imageWidth > imageHeight ? imageWidth : imageHeight;
    

    switch (image.imageOrientation) {
        case UIImageOrientationDown:
        case UIImageOrientationDownMirrored:{
                //创建横着显示的位图上下文,宽大于高
                CGFloat temp = contextWidth;
                contextWidth = contextHeight;
                contextHeight = temp;
                //旋转180度
                transform = CGAffineTransformTranslate(transform, contextWidth, contextHeight);
                transform = CGAffineTransformRotate(transform, M_PI);
            }
            break;
            
        case UIImageOrientationLeft:
        case UIImageOrientationLeftMirrored:
            //逆时针旋转90度
            transform = CGAffineTransformTranslate(transform, contextWidth, 0);
            transform = CGAffineTransformRotate(transform, M_PI_2);
            break;
            
        case UIImageOrientationRight:
        case UIImageOrientationRightMirrored:
            //顺时针90度
            transform = CGAffineTransformTranslate(transform, 0, contextHeight);
            transform = CGAffineTransformRotate(transform, -M_PI_2);
            break;
            
        default:
            break;
    }
    
    switch (image.imageOrientation) {
        case UIImageOrientationUpMirrored:
        case UIImageOrientationDownMirrored:
            //镜像图片Y轴翻转坐标系
            transform = CGAffineTransformTranslate(transform, contextWidth, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
            
        case UIImageOrientationLeftMirrored:
        case UIImageOrientationRightMirrored:
            //镜像图片Y轴翻转坐标系
            transform = CGAffineTransformTranslate(transform, contextHeight, 0);
            transform = CGAffineTransformScale(transform, -1, 1);
            break;
            
        default:
            break;
    }
    
    //创建竖直显示的画布
    CGContextRef ctx = CGBitmapContextCreate(NULL, contextWidth, contextHeight,
                                             CGImageGetBitsPerComponent(image.CGImage), 0,
                                             CGImageGetColorSpace(image.CGImage),
                                             CGImageGetBitmapInfo(image.CGImage));

    CGContextConcatCTM(ctx, transform);
    CGContextDrawImage(ctx, CGRectMake(0, 0, imageWidth, imageHeight), image.CGImage);
    
    // 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;
}

图片来源于(https://feihu.me/blog/2015/how-to-handle-image-orientation-on-iOS/)

参考 https://feihu.me/blog/2015/how-to-handle-image-orientation-on-iOS/

posted @ 2021-10-15 09:24  iOS小熊  阅读(866)  评论(0编辑  收藏  举报