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

相关文章

Nginx实现高并发的项目实践

《Nginx实现高并发的项目实践》本文主要介绍了Nginx实现高并发的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录使用最新稳定版本的Nginx合理配置工作进程(workers)配置工作进程连接数(worker_co

python中列表list切分的实现

《python中列表list切分的实现》列表是Python中最常用的数据结构之一,经常需要对列表进行切分操作,本文主要介绍了python中列表list切分的实现,文中通过示例代码介绍的非常详细,对大家... 目录一、列表切片的基本用法1.1 基本切片操作1.2 切片的负索引1.3 切片的省略二、列表切分的高

基于Python实现一个PDF特殊字体提取工具

《基于Python实现一个PDF特殊字体提取工具》在PDF文档处理场景中,我们常常需要针对特定格式的文本内容进行提取分析,本文介绍的PDF特殊字体提取器是一款基于Python开发的桌面应用程序感兴趣的... 目录一、应用背景与功能概述二、技术架构与核心组件2.1 技术选型2.2 系统架构三、核心功能实现解析

Python使用PIL库将PNG图片转换为ICO图标的示例代码

《Python使用PIL库将PNG图片转换为ICO图标的示例代码》在软件开发和网站设计中,ICO图标是一种常用的图像格式,特别适用于应用程序图标、网页收藏夹图标等场景,本文将介绍如何使用Python的... 目录引言准备工作代码解析实践操作结果展示结语引言在软件开发和网站设计中,ICO图标是一种常用的图像

dubbo3 filter(过滤器)如何自定义过滤器

《dubbo3filter(过滤器)如何自定义过滤器》dubbo3filter(过滤器)类似于javaweb中的filter和springmvc中的intercaptor,用于在请求发送前或到达前进... 目录dubbo3 filter(过滤器)简介dubbo 过滤器运行时机自定义 filter第一种 @A

使用Python实现表格字段智能去重

《使用Python实现表格字段智能去重》在数据分析和处理过程中,数据清洗是一个至关重要的步骤,其中字段去重是一个常见且关键的任务,下面我们看看如何使用Python进行表格字段智能去重吧... 目录一、引言二、数据重复问题的常见场景与影响三、python在数据清洗中的优势四、基于Python的表格字段智能去重

Spring AI集成DeepSeek实现流式输出的操作方法

《SpringAI集成DeepSeek实现流式输出的操作方法》本文介绍了如何在SpringBoot中使用Sse(Server-SentEvents)技术实现流式输出,后端使用SpringMVC中的S... 目录一、后端代码二、前端代码三、运行项目小天有话说题外话参考资料前面一篇文章我们实现了《Spring

Nginx中location实现多条件匹配的方法详解

《Nginx中location实现多条件匹配的方法详解》在Nginx中,location指令用于匹配请求的URI,虽然location本身是基于单一匹配规则的,但可以通过多种方式实现多个条件的匹配逻辑... 目录1. 概述2. 实现多条件匹配的方式2.1 使用多个 location 块2.2 使用正则表达式

使用Apache POI在Java中实现Excel单元格的合并

《使用ApachePOI在Java中实现Excel单元格的合并》在日常工作中,Excel是一个不可或缺的工具,尤其是在处理大量数据时,本文将介绍如何使用ApachePOI库在Java中实现Excel... 目录工具类介绍工具类代码调用示例依赖配置总结在日常工作中,Excel 是一个不可或缺的工http://

SpringBoot实现导出复杂对象到Excel文件

《SpringBoot实现导出复杂对象到Excel文件》这篇文章主要为大家详细介绍了如何使用Hutool和EasyExcel两种方式来实现在SpringBoot项目中导出复杂对象到Excel文件,需要... 在Spring Boot项目中导出复杂对象到Excel文件,可以利用Hutool或EasyExcel