iOS AVFoundation/AVCaptureSession实现自定义相机界面拍照(四)拍照、自定义裁剪框、图片查看器

本文主要是介绍iOS AVFoundation/AVCaptureSession实现自定义相机界面拍照(四)拍照、自定义裁剪框、图片查看器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

----参考框架:

a122273328/Camera

https://blog.csdn.net/aa122273328/article/details/72886022

https://github.com/a122273328/Camera

从系统相册选择照片后,自定义裁剪框:

LazyDuan/LDImagePicker

https://github.com/LazyDuan/LDImagePicker

图片查看器:PYPhotoBrowser    https://github.com/ko1o/PYPhotoBrowser

MWPhotoBrowser  :https://github.com/mwaterfall/MWPhotoBrowser


-----------自定义裁剪框的步骤:-----------

1.当我们实现了UIImagePickerController的代理后,需要在 imagePickerController:didFinishPickingMediaWithInfo:

imagePickerController.allowsEditing = true; 如果为true,就不会展现我们自己的裁剪视图了,就无法自定义了

2.跳转到自定义的控制器中去,吧从相册中的获取的图片传递到控制器中;

 UIImage *originImage = info[@"UIImagePickerControllerOriginalImage"];

    ImagePickerCropViewController *vc = [[ImagePickerCropViewController alloc] init];

    vc.originImage = originImage;

    [picker pushViewController:vc animated:true];

3.在控制器中用一个Imageview显示图片,然后给imageview添加手势;实现缩放;最后保存;

************

#import "ViewController.h"
#import "ImagePickerCropViewController.h"@interface ViewController () <UINavigationControllerDelegate, UIImagePickerControllerDelegate>@end@implementation ViewController- (void)viewDidLoad {[super viewDidLoad];}- (void)didReceiveMemoryWarning {[super didReceiveMemoryWarning];}- (IBAction)choosePhotot:(id)sender {UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
//     imagePickerController.allowsEditing = true; 如果为true,就不会展现我们自己的裁剪视图了,就无法自定义了imagePickerController.delegate = self;[self presentViewController:imagePickerController animated:true completion:nil];}- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info {UIImage *originImage = info[@"UIImagePickerControllerOriginalImage"];ImagePickerCropViewController *vc = [[ImagePickerCropViewController alloc] init];vc.originImage = originImage;[picker pushViewController:vc animated:true];
}- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker {[picker dismissViewControllerAnimated:true completion:nil];
}@end


#import <UIKit/UIKit.h>@interface ImagePickerCropViewController : UIViewController@property (nonatomic, strong) UIImage *originImage;@end


#import "ImagePickerCropViewController.h"@interface ImagePickerCropViewController ()@property (nonatomic, strong) UIImageView *cropImageView;@end@implementation ImagePickerCropViewController- (void)viewDidLoad {[super viewDidLoad];self.view.backgroundColor = [UIColor blackColor];UIBarButtonItem *item = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemSave target:self action:@selector(save)];self.navigationItem.rightBarButtonItem = item;CGRect frame = CGRectMake(0, 0, self.view.bounds.size.width, self.view.bounds.size.height - 44);self.cropImageView = [[UIImageView alloc] initWithFrame:frame];_cropImageView.contentMode = UIViewContentModeScaleAspectFit;[_cropImageView setImage:self.originImage];_cropImageView.userInteractionEnabled = true;[self.view addSubview:_cropImageView];UIPanGestureRecognizer *pan = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handlePan:)];[self.cropImageView addGestureRecognizer:pan];UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinch:)];[self.cropImageView addGestureRecognizer:pinch];UIView *maskView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 200, 200)];maskView.center = self.view.center;maskView.backgroundColor = [UIColor clearColor];maskView.layer.borderWidth = 0.5;maskView.layer.borderColor = [UIColor whiteColor].CGColor;[self.view addSubview:maskView];}- (void)handlePinch:(UIPinchGestureRecognizer *)recognizer {CGFloat scale = recognizer.scale;recognizer.view.transform = CGAffineTransformScale(recognizer.view.transform, scale, scale); //在已缩放大小基础下进行累加变化;区别于:使用 CGAffineTransformMakeScale 方法就是在原大小基础下进行变化recognizer.scale = 1.0;
}- (void)handlePan:(UIPanGestureRecognizer *)recognizer {if (recognizer.state != UIGestureRecognizerStateEnded && recognizer.state != UIGestureRecognizerStateFailed){CGPoint translation = [recognizer translationInView:self.view];CGPoint center = self.cropImageView.center;self.cropImageView.center = CGPointMake(center.x + translation.x, center.y + translation.y);[recognizer setTranslation:CGPointMake(0, 0) inView:self.view];}
}- (UIImage *)captureScreen {UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];CGRect rect = [keyWindow bounds];UIGraphicsBeginImageContextWithOptions(rect.size, false, 0.0);CGContextRef context = UIGraphicsGetCurrentContext();[keyWindow.layer renderInContext:context];UIImage *img = UIGraphicsGetImageFromCurrentImageContext();img = [UIImage imageWithCGImage:CGImageCreateWithImageInRect(img.CGImage, CGRectMake((self.view.center.x-100)*2+2, (self.view.center.y-100)*2+2, 400-4, 400-4))];UIGraphicsEndImageContext();return img;
}- (void)save {UIImageWriteToSavedPhotosAlbum([self captureScreen], nil, nil, nil);
}- (void)didReceiveMemoryWarning {[super didReceiveMemoryWarning];
}@end

----------------------

#import "ViewController.h"

#import <AVFoundation/AVFoundation.h>

#import <AssetsLibrary/AssetsLibrary.h>//写入相册需要的


@interface ViewController ()<UIGestureRecognizerDelegate>

/**

 *  AVCaptureSession对象来执行输入设备和输出设备之间的数据传递

 */

@property (nonatomic,strong)AVCaptureSession* session;

/**

 *  输入设备

 */

@property (nonatomic,strong)AVCaptureDeviceInput* videoInput;

/**

 *  照片输出流

 */

@property (nonatomic,strong)AVCaptureStillImageOutput* stillImageOutput;//10.0以前

//@property (nonatomic, strong) AVCapturePhotoOutput* stillImageOutput;//10.0以后

/**

 *  预览图层

 */

@property (nonatomic,strong)AVCaptureVideoPreviewLayer* previewLayer;


@property (strong,nonatomicUIButton *captureBtn;//拍照按钮

@property (strong,nonatomic)UIButton *openCaptureBtn;//打开摄像头按钮

@property(nonatomic,assign)BOOL isUsingFrontFacingCamera;//切换镜头

/**

 *  记录开始的缩放比例

 */

@property(nonatomic,assign)CGFloat beginGestureScale;

/**

 *  最后的缩放比例

 */

@property(nonatomic,assign)CGFloat effectiveScale;

@end


@implementation ViewController


-(void)takeCapture{

    [selftakePhotoButtonClick:nil];//拍照


}

-(void)openCapture{



}


-(void)flashBtn{

    [selfflashButtonClick:nil];//闪光灯

}


-(void)glassBtn{

    [selfswitchCameraSegmentedControlClick:nil];//切换镜头


}

- (void)viewDidLoad {

    [superviewDidLoad];

    [selfsetUpGesture];


    UIButton *captureBtn=[[UIButtonalloc]initWithFrame:CGRectMake(30,300,60,30)];

    self.captureBtn=captureBtn;

    captureBtn.backgroundColor=[UIColorblueColor];

    captureBtn.titleLabel.textColor=[UIColorgreenColor];

    [captureBtn setTitle:@"拍照"forState:UIControlStateNormal];

    [captureBtn addTarget:self action:@selector(takeCapture)forControlEvents:UIControlEventTouchDown];

    [self.viewaddSubview:captureBtn];

    

    UIButton *openCaptureBtn=[[UIButtonalloc]initWithFrame:CGRectMake(30,380,60,30)];

    self.openCaptureBtn=openCaptureBtn;

    openCaptureBtn.backgroundColor=[UIColorblueColor];

    [openCaptureBtn setTitle:@"摄像"forState:UIControlStateNormal];

    [openCaptureBtn addTarget:selfaction:@selector(openCapture)forControlEvents:UIControlEventTouchDown];

    [self.viewaddSubview:openCaptureBtn];

    

    UIButton *flashBtn=[[UIButtonalloc]initWithFrame:CGRectMake(30,420,60,30)];


    flashBtn.backgroundColor=[UIColorblueColor];

    [flashBtn setTitle:@"闪光灯"forState:UIControlStateNormal];

    [flashBtn addTarget:selfaction:@selector(flashBtn)forControlEvents:UIControlEventTouchDown];

    [self.viewaddSubview:flashBtn];


    UIButton *glassBtn=[[UIButtonalloc]initWithFrame:CGRectMake(30,480,60,30)];

    

    glassBtn.backgroundColor=[UIColorblueColor];

    [glassBtn setTitle:@"切换摄像头"forState:UIControlStateNormal];

    [glassBtn addTarget:selfaction:@selector(glassBtn)forControlEvents:UIControlEventTouchDown];

    [self.viewaddSubview:glassBtn];

        [selfinitAVCaptureSession];

//    self.openCaptureBtn.hidden = NO;

//    self.captureBtn.hidden = YES;

}



//闪光灯的设置非常简单,只需要修改deviceflashMode属性即可,这里需要注意的是,修改device时候需要先锁住,修改完成后再解锁,否则会崩溃,设置闪光灯的时候也需要做安全判断,验证设备是否支持闪光灯,有些iOS设备是没有闪光灯的,如果不做判断还是会crash

- (void)flashButtonClick:(UIBarButtonItem *)sender {

    

    NSLog(@"flashButtonClick");

    //mediatype类型: AVMediaTypeVideo, AVMediaTypeAudio, or AVMediaTypeMuxed

    AVCaptureDevice *device = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];

    

    //修改前必须先锁定

    [device lockForConfiguration:nil];

    //必须判定是否有闪光灯,否则如果没有闪光灯会崩溃

    if ([devicehasFlash]) {

        device.flashMode =AVCaptureFlashModeOn;


//        if (device.flashMode == AVCaptureFlashModeOff) {

//            device.flashMode = AVCaptureFlashModeOn;

//            

            [sender setTitle:@"flashOn"];

//        } else if (device.flashMode == AVCaptureFlashModeOn) {

//            device.flashMode = AVCaptureFlashModeAuto;

            [sender setTitle:@"flashAuto"];

//        } else if (device.flashMode == AVCaptureFlashModeAuto) {

//            device.flashMode = AVCaptureFlashModeOff;

            [sender setTitle:@"flashOff"];

//        }

        

    } else {

        

        NSLog(@"设备不支持闪光灯");

    }

    [device unlockForConfiguration];

}


#pragma 创建手势

- (void)setUpGesture{

    

    UIPinchGestureRecognizer *pinch = [[UIPinchGestureRecognizeralloc]initWithTarget:selfaction:@selector(handlePinchGesture:)];

    pinch.delegate =self;

    [self.viewaddGestureRecognizer:pinch];

}


#pragma mark gestureRecognizer delegate

- (BOOL)gestureRecognizerShouldBegin:(UIGestureRecognizer *)gestureRecognizer

{

    if ( [gestureRecognizerisKindOfClass:[UIPinchGestureRecognizerclass]] ) {

        self.beginGestureScale =self.effectiveScale;

    }

    returnYES;

}

//缩放手势用于调整焦距

- (void)handlePinchGesture:(UIPinchGestureRecognizer *)recognizer{

    

    BOOL allTouchesAreOnThePreviewLayer =YES;

    NSUInteger numTouches = [recognizernumberOfTouches], i;//几个手指

    for ( i =0; i < numTouches; ++i ) {

        CGPoint location = [recognizerlocationOfTouch:iinView:self.view];//i是指第几个手指

        CGPoint convertedLocation = [self.previewLayerconvertPoint:locationfromLayer:self.previewLayer.superlayer];//selfview上的点转换到self.previewLayer上坐标

        if ( ! [self.previewLayercontainsPoint:convertedLocation] ) {

            allTouchesAreOnThePreviewLayer = NO;//如果self.view上的转换到preview的坐标不在preview上,设置NO

            break;

        }

    }

    

    if ( allTouchesAreOnThePreviewLayer ) {

        

        

        self.effectiveScale =self.beginGestureScale * recognizer.scale;//获取当前手势的缩放比例

        if (self.effectiveScale <1.0){

            self.effectiveScale =1.0;

        }

        

        NSLog(@"%f-------------->%f------------recognizerScale%f",self.effectiveScale,self.beginGestureScale,recognizer.scale);

        

        //获取最大缩放比例

        CGFloat maxScaleAndCropFactor = [[self.stillImageOutputconnectionWithMediaType:AVMediaTypeVideo]videoMaxScaleAndCropFactor];

        

        NSLog(@"%f",maxScaleAndCropFactor);

        //超过最大,取最大

        if (self.effectiveScale > maxScaleAndCropFactor)

            self.effectiveScale = maxScaleAndCropFactor;

   

        //layer层的隐式动画

        [CATransactionbegin];

        [CATransactionsetAnimationDuration:.025];

        [self.previewLayersetAffineTransform:CGAffineTransformMakeScale(self.effectiveScale,self.effectiveScale)];//缩放

        [CATransactioncommit];//提交动画

        

    }

    

}


//切换镜头

- (void)switchCameraSegmentedControlClick:(UISegmentedControl *)sender {

    

    NSLog(@"%ld",(long)sender.selectedSegmentIndex);

    

    AVCaptureDevicePosition desiredPosition;

    if (self.isUsingFrontFacingCamera){

        desiredPosition = AVCaptureDevicePositionBack;//摄像头位置在后面

    }else{

        desiredPosition = AVCaptureDevicePositionFront;//摄像头位置在前面

    }

    

    for (AVCaptureDevice *din [AVCaptureDevicedevicesWithMediaType:AVMediaTypeVideo]) {

        if ([dposition] == desiredPosition) {

            [self.previewLayer.sessionbeginConfiguration];//开启配置

            AVCaptureDeviceInput *input = [AVCaptureDeviceInputdeviceInputWithDevice:derror:nil];

            for (AVCaptureInput *oldInputinself.previewLayer.session.inputs) {

                [[self.previewLayersession]removeInput:oldInput];//移除旧的会话

            }

            [self.previewLayer.sessionaddInput:input];//新的输入关联会话

            [self.previewLayer.sessioncommitConfiguration];//重新配置后,会话重新提交配置

            break;

        }

    }

    

    self.isUsingFrontFacingCamera = !self.isUsingFrontFacingCamera;

}



- (void)initAVCaptureSession{

    

    self.session = [[AVCaptureSessionalloc]init];

    

    NSError *error;

    

    AVCaptureDevice *device = [AVCaptureDevicedefaultDeviceWithMediaType:AVMediaTypeVideo];

    

    //更改这个设置的时候必须先锁定设备,修改完后再解锁,否则崩溃

    [device lockForConfiguration:nil];

    //设置闪光灯为自动

    [device setFlashMode:AVCaptureFlashModeAuto];

    [device unlockForConfiguration];

    

    self.videoInput = [[AVCaptureDeviceInputalloc]initWithDevice:deviceerror:&error];

    if (error) {

        NSLog(@"%@",error);

    }

    self.stillImageOutput = [[AVCaptureStillImageOutputalloc]init];

    //输出设置。AVVideoCodecJPEG  输出jpeg格式图片

    NSDictionary * outputSettings = [[NSDictionaryalloc]initWithObjectsAndKeys:AVVideoCodecJPEG,AVVideoCodecKey,nil];

    [self.stillImageOutputsetOutputSettings:outputSettings];

    

    if ([self.sessioncanAddInput:self.videoInput]) {

        [self.sessionaddInput:self.videoInput];

    }

    if ([self.sessioncanAddOutput:self.stillImageOutput]) {

        [self.sessionaddOutput:self.stillImageOutput];

    }

    

    //初始化预览图层

    self.previewLayer = [[AVCaptureVideoPreviewLayeralloc]initWithSession:self.session];

    [self.previewLayersetVideoGravity:AVLayerVideoGravityResizeAspect];

    self.previewLayer.frame =CGRectMake(0,0,375,375 - 64);

    self.view.layer.masksToBounds = YES;

    [self.view.layeraddSublayer:self.previewLayer];

}


- (void)viewWillAppear:(BOOL)animated{

    

    [superviewWillAppear:YES];

    

    if (self.session) {

        

        [self.sessionstartRunning];//开启会话

    }

}



- (void)viewDidDisappear:(BOOL)animated{

    

    [superviewDidDisappear:YES];

    

    if (self.session) {

        

        [self.sessionstopRunning];

    }

}



//拍照,输出图片

- (void)takePhotoButtonClick:(UIBarButtonItem *)sender {

    //输出图像的时候需要用到AVCaptureConnection这个类,session通过AVCaptureConnection连接AVCaptureStillImageOutput进行图片输出,

    AVCaptureConnection *stillImageConnection = [self.stillImageOutput        connectionWithMediaType:AVMediaTypeVideo];

    UIDeviceOrientation curDeviceOrientation = [[UIDevicecurrentDevice]orientation];

    AVCaptureVideoOrientation avcaptureOrientation = [selfavOrientationForDeviceOrientation:curDeviceOrientation];

    [stillImageConnection setVideoOrientation:avcaptureOrientation];

//这个方法是控制焦距用的暂时先固定为1,后边写手势缩放焦距的时候会修改这里

    [stillImageConnection setVideoScaleAndCropFactor:1];

    

    [self.stillImageOutputcaptureStillImageAsynchronouslyFromConnection:stillImageConnectioncompletionHandler:^(CMSampleBufferRef imageDataSampleBuffer,NSError *error) {

    //获得图片数据

        NSData *jpegData = [AVCaptureStillImageOutputjpegStillImageNSDataRepresentation:imageDataSampleBuffer];

        

        CFDictionaryRef attachments =CMCopyDictionaryOfAttachments(kCFAllocatorDefault,

                                                                    imageDataSampleBuffer,

                                                                   kCMAttachmentMode_ShouldPropagate);

//

        


    // 写入相册之前需要判断用户是否允许了程序访问相册,否则程序会崩溃,包括在开启相机的时候和拍摄按钮点击的时候都需要做安全验证,验证设别是否支持拍照,用户是否允许程序访问相机。

//        ALAuthorizationStatus author = [ALAssetsLibrary authorizationStatus];

//        if (author == ALAuthorizationStatusRestricted || author == ALAuthorizationStatusDenied){

//            //无权限

//            return ;

//        }

//        ALAssetsLibrary *library = [[ALAssetsLibrary alloc] init];

//        [library writeImageDataToSavedPhotosAlbum:jpegData metadata:(__bridge id)attachments completionBlock:^(NSURL *assetURL, NSError *error) {

//

//        }];

//        

    }];

    

     }


//设置方向,       照片写入相册之前需要进行旋转

-(AVCaptureVideoOrientation )avOrientationForDeviceOrientation:(UIDeviceOrientation)deviceOrientation

     {

         AVCaptureVideoOrientation result = (AVCaptureVideoOrientation)deviceOrientation;

         if ( deviceOrientation ==UIDeviceOrientationLandscapeLeft )

             result = AVCaptureVideoOrientationLandscapeRight;

         elseif ( deviceOrientation ==UIDeviceOrientationLandscapeRight )

             result = AVCaptureVideoOrientationLandscapeLeft;

         return result;

     }


@end





===================================================




这篇关于iOS AVFoundation/AVCaptureSession实现自定义相机界面拍照(四)拍照、自定义裁剪框、图片查看器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1017770

相关文章

Python实现对阿里云OSS对象存储的操作详解

《Python实现对阿里云OSS对象存储的操作详解》这篇文章主要为大家详细介绍了Python实现对阿里云OSS对象存储的操作相关知识,包括连接,上传,下载,列举等功能,感兴趣的小伙伴可以了解下... 目录一、直接使用代码二、详细使用1. 环境准备2. 初始化配置3. bucket配置创建4. 文件上传到os

关于集合与数组转换实现方法

《关于集合与数组转换实现方法》:本文主要介绍关于集合与数组转换实现方法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录1、Arrays.asList()1.1、方法作用1.2、内部实现1.3、修改元素的影响1.4、注意事项2、list.toArray()2.1、方

使用Python实现可恢复式多线程下载器

《使用Python实现可恢复式多线程下载器》在数字时代,大文件下载已成为日常操作,本文将手把手教你用Python打造专业级下载器,实现断点续传,多线程加速,速度限制等功能,感兴趣的小伙伴可以了解下... 目录一、智能续传:从崩溃边缘抢救进度二、多线程加速:榨干网络带宽三、速度控制:做网络的好邻居四、终端交互

java实现docker镜像上传到harbor仓库的方式

《java实现docker镜像上传到harbor仓库的方式》:本文主要介绍java实现docker镜像上传到harbor仓库的方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地... 目录1. 前 言2. 编写工具类2.1 引入依赖包2.2 使用当前服务器的docker环境推送镜像2.2

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Java easyExcel实现导入多sheet的Excel

《JavaeasyExcel实现导入多sheet的Excel》这篇文章主要为大家详细介绍了如何使用JavaeasyExcel实现导入多sheet的Excel,文中的示例代码讲解详细,感兴趣的小伙伴可... 目录1.官网2.Excel样式3.代码1.官网easyExcel官网2.Excel样式3.代码

python实现对数据公钥加密与私钥解密

《python实现对数据公钥加密与私钥解密》这篇文章主要为大家详细介绍了如何使用python实现对数据公钥加密与私钥解密,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录公钥私钥的生成使用公钥加密使用私钥解密公钥私钥的生成这一部分,使用python生成公钥与私钥,然后保存在两个文

浏览器插件cursor实现自动注册、续杯的详细过程

《浏览器插件cursor实现自动注册、续杯的详细过程》Cursor简易注册助手脚本通过自动化邮箱填写和验证码获取流程,大大简化了Cursor的注册过程,它不仅提高了注册效率,还通过友好的用户界面和详细... 目录前言功能概述使用方法安装脚本使用流程邮箱输入页面验证码页面实战演示技术实现核心功能实现1. 随机

Golang如何对cron进行二次封装实现指定时间执行定时任务

《Golang如何对cron进行二次封装实现指定时间执行定时任务》:本文主要介绍Golang如何对cron进行二次封装实现指定时间执行定时任务问题,具有很好的参考价值,希望对大家有所帮助,如有错误... 目录背景cron库下载代码示例【1】结构体定义【2】定时任务开启【3】使用示例【4】控制台输出总结背景

Golang如何用gorm实现分页的功能

《Golang如何用gorm实现分页的功能》:本文主要介绍Golang如何用gorm实现分页的功能方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录背景go库下载初始化数据【1】建表【2】插入数据【3】查看数据4、代码示例【1】gorm结构体定义【2】分页结构体