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

----参考框架:

a122273328/Camera

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

https://github.com/a122273328/Camera

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

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





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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值