// // RACameraViewController.m // Apex And Drivers // // Created by Jack on 2018/6/5. // Copyright © 2018年 USAI. All rights reserved. // #import "RACameraViewController.h" #import #import "RATakePhotoPreviewController.h" @interface RACameraViewController () @property (nonatomic,strong) IBOutlet UIView *previewContainer; @property (nonatomic,strong) IBOutlet UIView *controlContanier; @property (strong, nonatomic) IBOutlet UIButton *takePhotoBtn; @property (nonatomic,assign) BOOL barHidden; #pragma mark - Camera @property (nonatomic,strong) AVCaptureDevice *captureDevice; @property (nonatomic,strong) AVCaptureSession *captureSession; @property (nonatomic,strong) AVCaptureDeviceInput *captureInput; @property (nonatomic,strong) AVCaptureStillImageOutput *captureOutput; @property (nonatomic,strong) AVCaptureVideoPreviewLayer *previewLayer; @property (nonatomic,assign) BOOL cameraInitial; @end @implementation RACameraViewController + (NSString *)storyboardID { return NSStringFromClass([self class]); } + (instancetype)viewControllerFromStoryboard { RACameraViewController *cameraVC = [[UIStoryboard storyboardWithName:@"Camera" bundle:nil] instantiateViewControllerWithIdentifier:[self storyboardID]]; cameraVC.takeMode = RACameraTakeModeTakeOnce; return cameraVC; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. UIImage *normal_img = [self.class imageWithColor:[UIColor redColor] Size:CGSizeMake(60, 60)]; UIImage *highlight_img = [self.class imageWithColor:[UIColor whiteColor] Size:CGSizeMake(60, 60)]; [self.takePhotoBtn setImage:normal_img forState:UIControlStateNormal]; [self.takePhotoBtn setImage:highlight_img forState:UIControlStateHighlighted]; // [self initCapture]; // [self initTakePicture]; if ([self camerAuthorization]) { [self initCapture]; [self initTakePicture]; } else { // fix:第一次打开相机的时候授权成功后,未初始化相机 [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { dispatch_async(dispatch_get_main_queue(), ^{ if (granted) { [self initCapture]; [self initTakePicture]; CGRect frame = self.previewContainer.bounds; [self resetPreview:CGRectOffset(frame, CGRectGetWidth(frame), 0)]; [UIView animateWithDuration:0.3 animations:^{ self.previewLayer.frame = frame; }]; if (self.cameraInitial && !self.captureSession.isRunning) { [self.captureSession startRunning]; } } else { NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary]; NSString *appName = [infoDict objectForKey:@"CFBundleDisplayName"]; __weak typeof(self) weakSelf = self; UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:[NSString stringWithFormat:@"Camera access denied, please change %@ setting, allow App use camera. (setting -> privacy -> camera enable %@)",[UIDevice currentDevice].model,appName] preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [weakSelf dismissViewControllerAnimated:YES completion:nil]; }]; [alert addAction:action]; [self presentViewController:alert animated:YES completion:nil]; } }); }]; } /** * 管理导航条 * 在viewDidload的时候隐藏导航条 * 恢复导航条的显示/隐藏有两个地方:1.退出的时候;2.确认使用照片的时候 */ if (self.navigationController) { BOOL navBarHidden = self.navigationController.navigationBar.hidden; self.barHidden = navBarHidden; if (!navBarHidden) { [self.navigationController setNavigationBarHidden:YES animated:YES]; } } } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } - (void)viewWillAppear:(BOOL)animated { [super viewWillAppear:animated]; if (self.cameraInitial && !self.captureSession.isRunning) { [self.captureSession startRunning]; } } - (void)viewWillDisappear:(BOOL)animated { [super viewWillDisappear:animated]; if ([self.captureSession isRunning]) { [self.captureSession stopRunning]; } } - (BOOL)prefersStatusBarHidden { return YES; } - (void)viewDidLayoutSubviews { [super viewDidLayoutSubviews]; if ([self camerAuthorization] && self.cameraInitial) { [self resetPreview:self.previewContainer.bounds]; } } #pragma mark - Capture - (void)resetPreview:(CGRect)frame { self.previewLayer.frame = frame; if (self.previewLayer.connection.isVideoOrientationSupported) { self.previewLayer.connection.videoOrientation = [self captureVideoOrientation]; } if ([self.captureOutput connectionWithMediaType:AVMediaTypeVideo].isVideoOrientationSupported) { [self.captureOutput connectionWithMediaType:AVMediaTypeVideo].videoOrientation = [self captureVideoOrientation]; } } - (BOOL)camerAuthorization { AVAuthorizationStatus status = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo]; if (status == AVAuthorizationStatusRestricted || status == AVAuthorizationStatusDenied) { return NO; } return YES; } - (void)initCapture { self.cameraInitial = NO; if (![self camerAuthorization]) { NSDictionary* infoDict =[[NSBundle mainBundle] infoDictionary]; NSString *appName = [infoDict objectForKey:@"CFBundleDisplayName"]; __weak typeof(self) weakSelf = self; UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Warning" message:[NSString stringWithFormat:@"Camera access denied, please change %@ setting, allow App use camera. (setting -> privacy -> camera enable %@)",[UIDevice currentDevice].model,appName] preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction *action = [UIAlertAction actionWithTitle:@"Ok" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) { [weakSelf dismissViewControllerAnimated:YES completion:nil]; }]; [alert addAction:action]; [self presentViewController:alert animated:YES completion:nil]; return; } self.captureSession = [[AVCaptureSession alloc] init]; self.captureDevice = [self videoDevicePosition:AVCaptureDevicePositionBack]; if (!self.captureDevice) { NSLog(@"there is no capture device while init camera"); return; } NSError *error; self.captureInput = [[AVCaptureDeviceInput alloc] initWithDevice:self.captureDevice error:&error]; if (error) { NSLog(@"init camera error: %@",error); return; } [self.captureSession beginConfiguration]; if ([_captureSession canSetSessionPreset:AVCaptureSessionPresetPhoto]) { _captureSession.sessionPreset = AVCaptureSessionPresetPhoto; } if ([self.captureDevice isFlashAvailable] && [_captureDevice isFlashModeSupported:AVCaptureFlashModeAuto]) { NSError *configErr; [self.captureDevice lockForConfiguration:&configErr]; [self.captureDevice setFlashMode:AVCaptureFlashModeAuto]; [self.captureDevice unlockForConfiguration]; } // if ([self.captureDevice isAdjustingWhiteBalance] && [self.captureDevice isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) { // NSError *configErr; // [self.captureDevice lockForConfiguration:&configErr]; // [self.captureDevice setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance]; // [self.captureDevice unlockForConfiguration]; // } if ([self.captureSession canAddInput:self.captureInput]) { [self.captureSession addInput:self.captureInput]; // if ([self.captureSession canSetSessionPreset:AVCaptureSessionPreset1920x1080]) { // self.captureSession.sessionPreset = AVCaptureSessionPreset1920x1080; // } else { // if ([self.captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) { // self.captureSession.sessionPreset = AVCaptureSessionPresetHigh; // } // } } else { NSLog(@"init camera can't add input"); return; } [self.captureSession commitConfiguration]; self.previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.captureSession]; self.previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; [self.previewContainer.layer addSublayer:self.previewLayer]; self.cameraInitial = YES; } - (void)initTakePicture { if (!self.cameraInitial) { return; } self.captureOutput = [[AVCaptureStillImageOutput alloc] init]; NSDictionary *setting = @{AVVideoCodecKey:AVVideoCodecJPEG}; [self.captureOutput setOutputSettings:setting]; if ([self.captureSession canAddOutput:self.captureOutput]) { [self.captureSession addOutput:self.captureOutput]; } AVCaptureConnection *connection = [self.captureOutput connectionWithMediaType:AVMediaTypeVideo]; if (connection.isVideoOrientationSupported) { // addOutput之后判断,否则一直都是false connection.videoOrientation = [self captureVideoOrientation]; } } - (AVCaptureDevice *) videoDevicePosition:(AVCaptureDevicePosition)position { NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; for (AVCaptureDevice *device in videoDevices) { if ([device position] == position) { return device; } } return nil; } - (AVCaptureVideoOrientation)captureVideoOrientation { AVCaptureVideoOrientation result; UIDeviceOrientation deviceOrientation = [UIDevice currentDevice].orientation; switch (deviceOrientation) { case UIDeviceOrientationPortrait: case UIDeviceOrientationFaceUp: case UIDeviceOrientationFaceDown: result = AVCaptureVideoOrientationPortrait; break; case UIDeviceOrientationPortraitUpsideDown: //如果这里设置成AVCaptureVideoOrientationPortraitUpsideDown,则视频方向和拍摄时的方向是相反的。 result = AVCaptureVideoOrientationPortrait; break; case UIDeviceOrientationLandscapeLeft: result = AVCaptureVideoOrientationLandscapeRight; break; case UIDeviceOrientationLandscapeRight: result = AVCaptureVideoOrientationLandscapeLeft; break; default: result = AVCaptureVideoOrientationPortrait; break; } return result; } #pragma mark - Action - (IBAction)takePictureBtnClick:(UIButton *)sender { if (!self.cameraInitial) { return; } AVCaptureConnection *connection = [self.captureOutput connectionWithMediaType:AVMediaTypeVideo]; __weak typeof(self) weakSelf = self; [self.captureOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^(CMSampleBufferRef _Nullable imageDataSampleBuffer, NSError * _Nullable error) { if (imageDataSampleBuffer) { NSData *imageData=[AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; UIImage *image=[UIImage imageWithData:imageData]; RATakePhotoPreviewController *preVC = [RATakePhotoPreviewController viewControllerFromStoryboard]; preVC.photoHandler = ^(UIImage *img){ if (weakSelf) { __strong typeof(weakSelf) strongSelf = weakSelf; if (strongSelf.completion) { strongSelf.completion(img); } } }; preVC.preImage = image; if (weakSelf.takeMode == RACameraTakeModeTakeOnce) { preVC.popTo = weakSelf.fromVC; preVC.barHidden = weakSelf.barHidden; } [weakSelf.navigationController pushViewController:preVC animated:YES]; } else { NSLog(@"take picture failed: %@",error); } }]; } - (IBAction)returnButtonClick:(UIButton *)sender { if (self.navigationController) { [self.navigationController popViewControllerAnimated:YES]; } else { [self dismissViewControllerAnimated:YES completion:nil]; } if (self.navigationController) { [self.navigationController setNavigationBarHidden:self.barHidden animated:YES]; } } #pragma mark - Utils + (UIImage *)imageWithColor:(UIColor *)color Size:(CGSize)size { UIGraphicsBeginImageContextWithOptions(size, NO, [UIScreen mainScreen].scale); CGContextRef ctx = UIGraphicsGetCurrentContext(); CGContextAddEllipseInRect(ctx, CGRectMake(5, 5, size.width - 10, size.height - 10)); CGContextSetFillColorWithColor(ctx, color.CGColor); CGContextSetStrokeColorWithColor(ctx, [UIColor whiteColor].CGColor); CGContextSetLineWidth(ctx, 3.0f); CGContextDrawPath(ctx, kCGPathFillStroke); UIImage *img = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); return img; } @end