一、基本思路
1、创建一个导航控制器,承载两个控制器:拍照、照片预览;
2、分别创建这两个控制器,由于视图均为静态视图,所以直接用xib创建即可;
3、引用AVFoundation框架,通过媒体与数据流的交互来获取图片;
4、各种封装
二、使用到的几个类及相关说明:
SAImagePickerController:继承导航控制器类,用他来创建一个自定义相机
SACameraCtrl:拍照控制器,即拍照主界面,取景,摄像头切换、闪光灯开关、拍照按钮都在这个界面上展示;
SAPhotoViewCtrl:照片预览控制器,即拍照后的预览界面,查看照片效果、确定使用照片或重拍;
SAPreview:自定义View,拍照取景的那个视图,自定义是为了能够监听处理该视图上的事件,如对焦等。
三、基本界面预览:
四、关键代码:
SACameraCtrl.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 | // //? SACameraCtrl.m //? Test // //? Created by 余西安 on 15/4/13. //? Copyright (c) 2015年 Sian. All rights reserved. // ? #import "SACameraCtrl.h" #import "SAPreview.h" #import "SAPhotoViewCtrl.h" #import <AVFoundation/AVFoundation.h> #import <CoreMotion/CoreMotion.h> #define SourcePath [[NSBundle mainBundle] pathForResource:@"SAImagePickerController.bundle" ofType:nil] ? @interface SACameraCtrl () ? // 输入流预览图层 @property (nonatomic, strong)?? AVCaptureVideoPreviewLayer? *previewLayer; ? @property (weak, nonatomic) IBOutlet SAPreview *preview; ? // AVCaptureSession对象来执行输入设备和输出设备之间的数据传递 @property (nonatomic, strong)?? AVCaptureSession??????????? *session; ? // 设备输入流 @property (nonatomic, strong)?? AVCaptureDeviceInput??????? *deviceInput; ? // 照片输出流 @property (nonatomic, strong)?? AVCaptureStillImageOutput?? *imageOutput; ? // 图片输出视图 @property (nonatomic, strong)?? UIImageView???? *cameraShowView; ? // 摄像头数组 @property (nonatomic, strong, readonly) NSArray *devices;?????? // AVCaptureDevices ? // 闪光灯切换按钮 @property (weak, nonatomic) IBOutlet UIButton *flashButton; ? ? @end ? @implementation SACameraCtrl ? - (void)viewDidLoad { ????[super viewDidLoad]; ????// 创建交互流 ????self.session = [[AVCaptureSession alloc] init]; ????self.session.sessionPreset = AVCaptureSessionPresetPhoto; ????? ????// 媒体输入 ????AVCaptureDevice *device = [self.devices firstObject]; ????[self setDevice:device FlashMode:AVCaptureFlashModeAuto]; ????self.deviceInput = [AVCaptureDeviceInput deviceInputWithDevice:device error:NULL]; ????if([self.session canAddInput:self.deviceInput])[self.session addInput:self.deviceInput]; ????? ????// 媒体输出 ????self.imageOutput = [[AVCaptureStillImageOutput alloc] init]; ????self.imageOutput.outputSettings = @{AVVideoCodecKey : AVVideoCodecJPEG}; ????AVCaptureConnection * connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo]; ????connection.videoOrientation = AVCaptureVideoOrientationLandscapeRight; ????if([self.session canAddOutput:self.imageOutput])[self.session addOutput:self.imageOutput]; ????? ????// 媒体预览 ????self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session]; ????self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; ????self.previewLayer.position = self.preview.center; ????[self.preview.layer addSublayer:self.previewLayer]; ????[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications]; ????[self setPreviewGesture]; } ? ? #pragma mark - 前后摄像头 - (NSArray *)devices { ????return [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; } ? - (void)viewWillAppear:(BOOL)animated { ????[super viewWillAppear:animated]; ????self.previewLayer.frame = self.preview.layer.bounds; ????self.navigationController.navigationBar.hidden = YES; ????[self.session startRunning]; } ? - (void)viewDidAppear:(BOOL)animated { ????[super viewDidAppear:animated]; ????[[UIApplication sharedApplication] setStatusBarHidden:YES]; } ? - (void)viewWillDisappear:(BOOL)animated { ????[super viewWillDisappear:animated]; ????[[UIApplication sharedApplication] setStatusBarHidden:NO]; } ? - (void)viewDidDisappear:(BOOL)animated { ????[super viewDidDisappear:animated]; ????[self.session stopRunning]; } ? /// 媒体预览图层手势事件 - (void)setPreviewGesture { ????// 注册一个手势事件来实现对焦功能 ????UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapPreview:)]; ????[self.preview addGestureRecognizer:tap]; } ? /// 预览图层点击事件 - (void)tapPreview:(UITapGestureRecognizer *)gesture { ????CGPoint point = [gesture locationInView:gesture.view]; ????CGPoint p = [self.previewLayer captureDevicePointOfInterestForPoint:point]; ????[self focusAtPoint:p]; ????self.preview.aperture.center = point; ????[self.preview showAperture]; } ? /// 对焦事件 - (void)focusAtPoint:(CGPoint)point { ????AVCaptureDevice *device = self.deviceInput.device; ????NSError *error; ????if ([device isFocusModeSupported:AVCaptureFocusModeAutoFocus] && [device isFocusPointOfInterestSupported]) ????{ ????????if ([device lockForConfiguration:&error]) { ????????????[device setFocusPointOfInterest:point]; ????????????[device setFocusMode:AVCaptureFocusModeAutoFocus]; ????????????[device unlockForConfiguration]; ????????} else { ????????????SALog(@"Error: %@", error); ????????} ????} } ? /// 摄像头切换事件 - (IBAction)switchCamera:(UIButton *)sender { ????if (self.devices.count < 2) return; ????? ????NSInteger oldIndex = [self.devices indexOfObject:self.deviceInput.device]; ????NSInteger newIndex = (oldIndex + 1) % self.devices.count; ????AVCaptureDevice *newDevice = [self.devices objectAtIndex:newIndex]; ????AVCaptureDeviceInput *newInput = [AVCaptureDeviceInput deviceInputWithDevice:newDevice error:NULL]; ????if (newInput) { ????????[self.session beginConfiguration]; ????????[self.session removeInput:self.deviceInput]; ????????[self.session addInput:newInput]; ????????[self.session commitConfiguration]; ????????self.deviceInput = newInput; ????????self.flashButton.hidden = !newDevice.isFlashAvailable; ????} } ? /// 取消事件 - (IBAction)cancel:(UIButton *)sender { ????[self dismissViewControllerAnimated:YES completion:nil]; } ? /// 拍照事件 - (IBAction)shutter:(UIButton *)sender { ????sender.userInteractionEnabled = NO; ????AVCaptureConnection * connection = [self.imageOutput connectionWithMediaType:AVMediaTypeVideo]; ????connection.videoOrientation = AVCaptureVideoOrientationPortrait; ????? ????connection.videoScaleAndCropFactor = 1.0;?? // 获取流比例 ????if (!connection) { ????????NSLog(@"take photo failed!"); ????????return; ????} ????? ????[self.imageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { ????????if (imageDataSampleBuffer == NULL) { ????????????return; ????????} ????????NSData * imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; ????????UIImage * image = [UIImage imageWithData:imageData]; ????????SAPhotoViewCtrl *photoView = [[SAPhotoViewCtrl alloc] initWithImage:image]; ????????[self.navigationController pushViewController:photoView animated:NO]; ????????sender.userInteractionEnabled = YES; ????}]; } ? /// 闪光灯开关按钮 - (IBAction)overTurn:(UIButton *)sender { ????sender.tag = (sender.tag + 1) % 3; ????NSString *imageName = [NSString stringWithFormat:@"camera_flashlight_%d.png", (int)sender.tag]; ????[sender setBackgroundImage:[UIImage imageNamed:imageName] forState:UIControlStateNormal]; ????[self setDevice:self.deviceInput.device FlashMode:(2 - sender.tag)]; } ? /// 切换闪光灯模式 - (void)setDevice:(AVCaptureDevice *)device FlashMode:(AVCaptureFlashMode)flashModel { ????if (device.isFlashAvailable == NO) return; ????if ([device lockForConfiguration:nil]) { ????????device.flashMode = flashModel; ????} ????[device unlockForConfiguration]; } ? @end |
SAImagePickerController.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 | // //? SAImagePickerController.m //? Test // //? Created by 余西安 on 15/4/15. //? Copyright (c) 2015年 Sian. All rights reserved. // ? #import "SAImagePickerController.h" #import "SACameraCtrl.h" ? @interface SAImagePickerController () ? @end ? @implementation SAImagePickerController ? + (instancetype)pickerComplete:(SAImagePickerComplete)complete { ????return [[self alloc] initWithBlock:complete]; } ? - (instancetype)initWithBlock:(SAImagePickerComplete)block { ????if (self = [super init]){ ????????if (block) self.completeBlock = block; ????} ????return self; } ? - (instancetype)init { ????SACameraCtrl *cameraCtrl = [[SACameraCtrl alloc] init]; ????if (self = [super initWithRootViewController:cameraCtrl]){ ????? ????} ????return self; } ? - (void)viewDidLoad { ????[super viewDidLoad]; } ? - (void)dealloc { ????SALog(@"SAImagePickerController is dealloc"); } @end |
SAPhotoViewCtrl.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | // //? SAPhotoViewCtrl.m //? Test // //? Created by 余西安 on 15/4/14. //? Copyright (c) 2015年 Sian. All rights reserved. // ? #import "SAPhotoViewCtrl.h" #import "SAImagePickerController.h" ? @interface SAPhotoViewCtrl () ? @property (nonatomic, strong) UIImage *image; ? @property (nonatomic, assign) NSInteger rotate; ? @end ? @implementation SAPhotoViewCtrl ? - (instancetype)initWithImage:(UIImage *)image { ????if (self = [super initWithNibName:@"SAPhotoViewCtrl" bundle:nil]){ ????????self.image = image; ????????self.rotate = 0; ????} ????return self; } ? - (void)viewWillAppear:(BOOL)animated { ????[super viewWillAppear:animated]; ????self.imageView.image = self.image; ????[[UIApplication sharedApplication] setStatusBarHidden:YES]; } ? - (void)viewWillDisappear:(BOOL)animated { ????[super viewWillDisappear:animated]; ????[[UIApplication sharedApplication] setStatusBarHidden:NO]; } ? - (void)viewDidLoad { ????[super viewDidLoad]; } ? /// 旋转图片 - (IBAction)transForm:(UIButton *)sender { ????self.rotate ++; ????[UIView animateWithDuration:0.3 animations:^{ ????????self.imageView.transform = CGAffineTransformRotate(self.imageView.transform, - M_PI_2); ????}]; } ? /// 重新拍摄 - (IBAction)reShutter:(UIButton *)sender { ????[self.navigationController popViewControllerAnimated:NO]; } ? /// 使用照片 - (IBAction)submitImage:(UIButton *)sender { ????UIImageOrientation orientation = UIImageOrientationUp; ????switch (self.rotate % 4) { ????????case 0:{ ????????????orientation = UIImageOrientationRight; ????????}break; ????????case 1:{ ????????????orientation = UIImageOrientationUp; ????????}break; ????????case 2:{ ????????????orientation = UIImageOrientationLeft; ????????}break; ????????case 3:{ ????????????orientation = UIImageOrientationDown; ????????}break; ????????????? ????????default:break; ????} ????CGFloat scale = [UIScreen mainScreen].scale; ????UIImage *image = [[UIImage alloc] initWithCGImage:self.image.CGImage scale:scale orientation:orientation]; ????SAImagePickerController *pickerCtrl = (SAImagePickerController *)self.navigationController; ????pickerCtrl.completeBlock(image); ????[self dismissViewControllerAnimated:YES completion:^{ ????????[self.navigationController popViewControllerAnimated:NO]; ????}]; } ? @end |
SAPreview.m
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | // //? SAPreview.m //? Test // //? Created by 余西安 on 15/4/14. //? Copyright (c) 2015年 Sian. All rights reserved. // ? #import "SAPreview.h" ? @implementation SAPreview ? - (instancetype)initWithCoder:(NSCoder *)aDecoder { ????if (self = [super initWithCoder:aDecoder]){ ????????UIImage *image = [UIImage imageNamed:@"camera_aperture.png"]; ????????self.aperture = [[UIImageView alloc] initWithImage:image]; ????} ????return self; } ? - (void)showAperture { ????[self addSubview:self.aperture]; ????self.aperture.transform = CGAffineTransformMakeScale(2.0, 2.0); ????[UIView animateWithDuration:0.3 animations:^{ ????????self.aperture.transform = CGAffineTransformIdentity; ????}]; ????[self.aperture performSelector:@selector(removeFromSuperview) withObject:nil afterDelay:1.0]; } ? @end |
五、基本使用
一行代码搞定!
1 2 3 4 | SAImagePickerController *imagePicker = [SAImagePickerController? pickerComplete:^(UIImage *image) { ????self.imageView.image = image; }]; [self presentViewController:imagePicker animated:YES completion:nil]; |
六、Demo下载
链接: http://pan.baidu.com/s/1bnCUte3 密码: 6k4k
Pingback: 小龙虾博客 (Crayfish)