本文主要是介绍iOS AVFoundation/AVCaptureSession实现自定义相机界面拍照(四)拍照、自定义裁剪框、图片查看器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
----参考框架:
/Camera
https://blog.csdn.net/aa122273328/article/details/72886022https://github.com/a122273328/Camera
从系统相册选择照片后,自定义裁剪框:
/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,nonatomic) UIButton *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;
}
//闪光灯的设置非常简单,只需要修改device的flashMode属性即可,这里需要注意的是,修改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];//吧self。view上的点转换到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实现自定义相机界面拍照(四)拍照、自定义裁剪框、图片查看器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!