From 8610e9136850e2dab430b11631b9e90ce508f646 Mon Sep 17 00:00:00 2001 From: bluesuedesw Date: Fri, 6 Mar 2015 10:09:25 -0800 Subject: [PATCH 1/8] Handle disabled autorotation Sets the correct AVCaptureVideoOrientation by checking the currentDevice orientation to support apps that have autorotation disabled --- LLSimpleCamera/LLSimpleCamera.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LLSimpleCamera/LLSimpleCamera.m b/LLSimpleCamera/LLSimpleCamera.m index 8ecdaef..bf92a67 100644 --- a/LLSimpleCamera/LLSimpleCamera.m +++ b/LLSimpleCamera/LLSimpleCamera.m @@ -537,7 +537,7 @@ - (void)viewWillLayoutSubviews { - (AVCaptureVideoOrientation)orientationForConnection { AVCaptureVideoOrientation videoOrientation = AVCaptureVideoOrientationPortrait; - switch (self.interfaceOrientation) { + switch ([UIDevice currentDevice].orientation) { case UIInterfaceOrientationLandscapeLeft: videoOrientation = AVCaptureVideoOrientationLandscapeLeft; break; From 386ef85e5efea730abb80146032245a18c9f3de6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Mon, 9 Mar 2015 18:07:22 +0200 Subject: [PATCH 2/8] properly handle camera permission --- LLSimpleCamera/LLSimpleCamera.h | 6 +++++ LLSimpleCamera/LLSimpleCamera.m | 47 +++++++++++++++++++++++++++++---- 2 files changed, 48 insertions(+), 5 deletions(-) diff --git a/LLSimpleCamera/LLSimpleCamera.h b/LLSimpleCamera/LLSimpleCamera.h index bb5f5c7..9185ab5 100644 --- a/LLSimpleCamera/LLSimpleCamera.h +++ b/LLSimpleCamera/LLSimpleCamera.h @@ -28,6 +28,12 @@ typedef enum : NSUInteger { CameraQualityPhoto } CameraQuality; +extern NSString *const LLSimpleCameraErrorDomain; +typedef enum : NSUInteger { + LLSimpleCameraErrorCodePermission = 10, + LLSimpleCameraErrorCodeSession = 11 +} LLSimpleCameraErrorCode; + @interface LLSimpleCamera : UIViewController /** diff --git a/LLSimpleCamera/LLSimpleCamera.m b/LLSimpleCamera/LLSimpleCamera.m index bf92a67..48d1008 100644 --- a/LLSimpleCamera/LLSimpleCamera.m +++ b/LLSimpleCamera/LLSimpleCamera.m @@ -23,6 +23,8 @@ @interface LLSimpleCamera () @property (strong, nonatomic) CAAnimation *focusBoxAnimation; @end +NSString *const LLSimpleCameraErrorDomain = @"LLSimpleCameraErrorDomain"; + @implementation LLSimpleCamera - (instancetype)initWithQuality:(CameraQuality)quality andPosition:(CameraPosition)position { @@ -113,9 +115,29 @@ - (void) previewTapped: (UIGestureRecognizer *) gestureRecognizer #pragma mark Camera Actions - (void)start { - + // in iOS7 & iOS8 we have check if we have permission t camera + if ([AVCaptureDevice respondsToSelector:@selector(requestAccessForMediaType: completionHandler:)]) { + [AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted) { + if (granted) { + dispatch_async(dispatch_get_main_queue(), ^{ + [self initialize]; + }); + } else { + NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain + code:LLSimpleCameraErrorCodePermission + userInfo:nil]; + dispatch_async(dispatch_get_main_queue(), ^{ + self.onError(self, error); + }); + } + }]; + } else { + [self initialize]; + } +} + +- (void)initialize { if(!_session) { - self.session = [[AVCaptureSession alloc] init]; NSString *sessionPreset = nil; @@ -200,12 +222,20 @@ - (void)stop { -(void)capture:(void (^)(LLSimpleCamera *camera, UIImage *image, NSDictionary *metadata, NSError *error))onCapture exactSeenImage:(BOOL)exactSeenImage { + if(!self.session) { + NSError *error = [NSError errorWithDomain:LLSimpleCameraErrorDomain + code:LLSimpleCameraErrorCodeSession + userInfo:nil]; + onCapture(self, nil, nil, error); + return; + } + // get connection and set orientation AVCaptureConnection *videoConnection = [self captureConnection]; videoConnection.videoOrientation = [self orientationForConnection]; - [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) - { + [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:videoConnection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { + //Stop capturing data to freeze the screen to indicate the pictrue has been taken [self.captureVideoPreviewLayer.connection setEnabled:NO]; @@ -298,6 +328,9 @@ - (BOOL)isFlashAvailable { -(void)setCameraFlash:(CameraFlash)cameraFlash { + if(!self.session) + return; + AVCaptureFlashMode flashMode; if(cameraFlash == CameraFlashOn) { @@ -340,6 +373,10 @@ - (BOOL) setFlashMode:(AVCaptureFlashMode)flashMode } - (CameraPosition)togglePosition { + if(!self.session) { + return self.cameraPosition; + } + if(self.cameraPosition == CameraPositionBack) { self.cameraPosition = CameraPositionFront; } @@ -352,7 +389,7 @@ - (CameraPosition)togglePosition { - (void)setCameraPosition:(CameraPosition)cameraPosition { - if(_cameraPosition == cameraPosition) { + if(_cameraPosition == cameraPosition || !self.session) { return; } From a5197949ceef65bdfe8e8efd3028400c403735f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Mon, 9 Mar 2015 18:08:23 +0200 Subject: [PATCH 3/8] update example to support denied permission --- LLSimpleCameraExample/HomeViewController.m | 26 +++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/LLSimpleCameraExample/HomeViewController.m b/LLSimpleCameraExample/HomeViewController.m index cf8a3ed..37d06db 100644 --- a/LLSimpleCameraExample/HomeViewController.m +++ b/LLSimpleCameraExample/HomeViewController.m @@ -12,6 +12,7 @@ @interface HomeViewController () @property (strong, nonatomic) LLSimpleCamera *camera; +@property (strong, nonatomic) UILabel *errorLabel; @property (strong, nonatomic) UIButton *snapButton; @property (strong, nonatomic) UIButton *switchButton; @property (strong, nonatomic) UIButton *flashButton; @@ -22,7 +23,7 @@ @implementation HomeViewController - (void)viewDidLoad { [super viewDidLoad]; - self.view.backgroundColor = [UIColor redColor]; + self.view.backgroundColor = [UIColor blackColor]; [self.navigationController setNavigationBarHidden:YES animated:NO]; CGRect screenRect = [[UIScreen mainScreen] bounds]; @@ -58,6 +59,26 @@ - (void)viewDidLoad { [self.camera setOnError:^(LLSimpleCamera *camera, NSError *error) { NSLog(@"Camera error: %@", error); + + if([error.domain isEqualToString:LLSimpleCameraErrorDomain]) { + if(error.code == LLSimpleCameraErrorCodePermission) { + if(weakSelf.errorLabel) + [weakSelf.errorLabel removeFromSuperview]; + + UILabel *label = [[UILabel alloc] initWithFrame:CGRectZero]; + label.text = @"We need permission for the camera.\nPlease go to your settings."; + label.numberOfLines = 2; + label.lineBreakMode = NSLineBreakByWordWrapping; + label.backgroundColor = [UIColor clearColor]; + label.font = [UIFont fontWithName:@"AvenirNext-DemiBold" size:13.0f]; + label.textColor = [UIColor whiteColor]; + label.textAlignment = NSTextAlignmentCenter; + [label sizeToFit]; + label.center = CGPointMake(screenRect.size.width / 2.0f, screenRect.size.height / 2.0f); + weakSelf.errorLabel = label; + [weakSelf.view addSubview:weakSelf.errorLabel]; + } + } }]; // ----- camera buttons -------- // @@ -138,6 +159,9 @@ - (void)snapButtonPressed:(UIButton *)button { ImageViewController *imageVC = [[ImageViewController alloc] initWithImage:image]; [self presentViewController:imageVC animated:NO completion:nil]; } + else { + NSLog(@"An error has occured: %@", error); + } } exactSeenImage:YES]; } From 575afd7767ad3ace2332f5c49b8aa21bb6296aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Mon, 9 Mar 2015 18:53:59 +0200 Subject: [PATCH 4/8] improved flash related methods --- LLSimpleCamera/LLSimpleCamera.h | 19 ++++++---- LLSimpleCamera/LLSimpleCamera.m | 65 ++++++++++++++++----------------- 2 files changed, 44 insertions(+), 40 deletions(-) diff --git a/LLSimpleCamera/LLSimpleCamera.h b/LLSimpleCamera/LLSimpleCamera.h index 9185ab5..5007806 100644 --- a/LLSimpleCamera/LLSimpleCamera.h +++ b/LLSimpleCamera/LLSimpleCamera.h @@ -49,12 +49,12 @@ typedef enum : NSUInteger { /** * Camera flash mode. */ -@property (nonatomic) CameraFlash cameraFlash; +@property (nonatomic, readonly) CameraFlash flash; /** * Position of the camera. */ -@property (nonatomic) CameraPosition cameraPosition; +@property (nonatomic) CameraPosition position; /** * Fixess the orientation after the image is captured is set to Yes. @@ -92,19 +92,24 @@ typedef enum : NSUInteger { - (void)attachToViewController:(UIViewController *)vc withFrame:(CGRect)frame; /** - Changes the posiition of the camera (either back or front) and returns the final position. + * Changes the posiition of the camera (either back or front) and returns the final position. */ - (CameraPosition)togglePosition; /** - Checks if flash is avilable for the currently active device. + * Update the flash mode of the camera. Returns true if it is successful. Otherwise false. + */ +- (BOOL)updateFlashMode:(CameraFlash)cameraFlash; + +/** + * Checks if flash is avilable for the currently active device. */ - (BOOL)isFlashAvailable; /** - Alter the layer and the animation displayed when the user taps on screen. - @param layer Layer to be displayed - @param animation to be applied after the layer is shown + * Alter the layer and the animation displayed when the user taps on screen. + * @param layer Layer to be displayed + * @param animation to be applied after the layer is shown */ - (void)alterFocusBox:(CALayer *)layer animation:(CAAnimation *)animation; diff --git a/LLSimpleCamera/LLSimpleCamera.m b/LLSimpleCamera/LLSimpleCamera.m index 48d1008..0db03f4 100644 --- a/LLSimpleCamera/LLSimpleCamera.m +++ b/LLSimpleCamera/LLSimpleCamera.m @@ -42,7 +42,7 @@ - (instancetype)initWithQuality:(CameraQuality)quality andPosition:(CameraPositi - (void)viewDidLoad { [super viewDidLoad]; - _cameraFlash = CameraFlashOff; + _flash = CameraFlashOff; self.view.backgroundColor = [UIColor clearColor]; self.view.autoresizingMask = UIViewAutoresizingNone; @@ -171,7 +171,7 @@ - (void)initialize { self.captureVideoPreviewLayer = captureVideoPreviewLayer; AVCaptureDevicePosition devicePosition; - switch (self.cameraPosition) { + switch (self.position) { case CameraPositionBack: devicePosition = AVCaptureDevicePositionBack; break; @@ -312,8 +312,18 @@ - (AVCaptureConnection *)captureConnection { - (void)setCaptureDevice:(AVCaptureDevice *)captureDevice { _captureDevice = captureDevice; - // reset flash - self.cameraFlash = CameraFlashOff; + if(captureDevice.flashMode == AVCaptureFlashModeAuto) { + _flash = CameraFlashAuto; + } + else if(captureDevice.flashMode == AVCaptureFlashModeOn) { + _flash = CameraFlashOn; + } + else if(captureDevice.flashMode == AVCaptureFlashModeOff) { + _flash = CameraFlashOff; + } + else { + _flash = CameraFlashOff; + } // trigger block if(self.onDeviceChange) { @@ -325,14 +335,12 @@ - (BOOL)isFlashAvailable { return self.captureDevice.isFlashAvailable; } - --(void)setCameraFlash:(CameraFlash)cameraFlash { - +- (BOOL)updateFlashMode:(CameraFlash)cameraFlash { if(!self.session) - return; + return NO; AVCaptureFlashMode flashMode; - + if(cameraFlash == CameraFlashOn) { flashMode = AVCaptureFlashModeOn; } @@ -343,53 +351,44 @@ -(void)setCameraFlash:(CameraFlash)cameraFlash { flashMode = AVCaptureFlashModeOff; } - BOOL done = [self setFlashMode:flashMode]; - if(done) { - _cameraFlash = cameraFlash; - } - else { - _cameraFlash = CameraFlashOff; - } -} - -- (BOOL) setFlashMode:(AVCaptureFlashMode)flashMode -{ if([_captureDevice isFlashModeSupported:flashMode]) { - - if(_captureDevice.flashMode == flashMode) { - return YES; - } - - if([_captureDevice lockForConfiguration:nil]) { + NSError *error; + if([_captureDevice lockForConfiguration:&error]) { _captureDevice.flashMode = flashMode; [_captureDevice unlockForConfiguration]; + _flash = cameraFlash; return YES; } + else { + self.onError(self, error); + return NO; + } + } + else { + return NO; } - - return NO; } - (CameraPosition)togglePosition { if(!self.session) { - return self.cameraPosition; + return self.position; } - if(self.cameraPosition == CameraPositionBack) { + if(self.position == CameraPositionBack) { self.cameraPosition = CameraPositionFront; } else { self.cameraPosition = CameraPositionBack; } - return self.cameraPosition; + return self.position; } - (void)setCameraPosition:(CameraPosition)cameraPosition { - if(_cameraPosition == cameraPosition || !self.session) { + if(_position == cameraPosition || !self.session) { return; } @@ -424,7 +423,7 @@ - (void)setCameraPosition:(CameraPosition)cameraPosition return; } - _cameraPosition = cameraPosition; + _position = cameraPosition; [self.session addInput:newVideoInput]; [self.session commitConfiguration]; From 8687de409d35062db37155610d400a064d5d8934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Mon, 9 Mar 2015 19:10:37 +0200 Subject: [PATCH 5/8] added option to use general device orientation --- LLSimpleCamera/LLSimpleCamera.h | 6 +++++ LLSimpleCamera/LLSimpleCamera.m | 48 ++++++++++++++++++++++++--------- 2 files changed, 41 insertions(+), 13 deletions(-) diff --git a/LLSimpleCamera/LLSimpleCamera.h b/LLSimpleCamera/LLSimpleCamera.h index 5007806..18052b9 100644 --- a/LLSimpleCamera/LLSimpleCamera.h +++ b/LLSimpleCamera/LLSimpleCamera.h @@ -67,6 +67,12 @@ typedef enum : NSUInteger { */ @property (nonatomic) BOOL tapToFocus; +/** + * Set YES if you your view controller does not allow autorotation, + * however you want to take the device rotation into account no matter what. Disabled by default. + */ +@property (nonatomic) BOOL useDeviceOrientation; + /** * Returns an instance of LLSimpleCamera with the given quality. * @param quality The quality of the camera. diff --git a/LLSimpleCamera/LLSimpleCamera.m b/LLSimpleCamera/LLSimpleCamera.m index 0db03f4..54cf2ad 100644 --- a/LLSimpleCamera/LLSimpleCamera.m +++ b/LLSimpleCamera/LLSimpleCamera.m @@ -34,6 +34,7 @@ - (instancetype)initWithQuality:(CameraQuality)quality andPosition:(CameraPositi self.cameraPosition = position; self.fixOrientationAfterCapture = NO; self.tapToFocus = YES; + self.useDeviceOrientation = NO; } return self; @@ -573,20 +574,41 @@ - (void)viewWillLayoutSubviews { - (AVCaptureVideoOrientation)orientationForConnection { AVCaptureVideoOrientation videoOrientation = AVCaptureVideoOrientationPortrait; - switch ([UIDevice currentDevice].orientation) { - case UIInterfaceOrientationLandscapeLeft: - videoOrientation = AVCaptureVideoOrientationLandscapeLeft; - break; - case UIInterfaceOrientationLandscapeRight: - videoOrientation = AVCaptureVideoOrientationLandscapeRight; - break; - case UIInterfaceOrientationPortraitUpsideDown: - videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown; - break; - default: - videoOrientation = AVCaptureVideoOrientationPortrait; - break; + + if(self.useDeviceOrientation) { + switch ([UIDevice currentDevice].orientation) { + case UIDeviceOrientationLandscapeLeft: + // yes we to the right, this is not bug! + videoOrientation = AVCaptureVideoOrientationLandscapeRight; + break; + case UIDeviceOrientationLandscapeRight: + videoOrientation = AVCaptureVideoOrientationLandscapeLeft; + break; + case UIDeviceOrientationPortraitUpsideDown: + videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown; + break; + default: + videoOrientation = AVCaptureVideoOrientationPortrait; + break; + } + } + else { + switch (self.interfaceOrientation) { + case UIInterfaceOrientationLandscapeLeft: + videoOrientation = AVCaptureVideoOrientationLandscapeLeft; + break; + case UIInterfaceOrientationLandscapeRight: + videoOrientation = AVCaptureVideoOrientationLandscapeRight; + break; + case UIInterfaceOrientationPortraitUpsideDown: + videoOrientation = AVCaptureVideoOrientationPortraitUpsideDown; + break; + default: + videoOrientation = AVCaptureVideoOrientationPortrait; + break; + } } + return videoOrientation; } From 7b258e49681c2eb379025f0fefe9145bde8b8b76 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Mon, 9 Mar 2015 19:11:57 +0200 Subject: [PATCH 6/8] update flash method --- LLSimpleCameraExample/HomeViewController.m | 26 +++++++++++++++------- 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/LLSimpleCameraExample/HomeViewController.m b/LLSimpleCameraExample/HomeViewController.m index 37d06db..b3fc8b9 100644 --- a/LLSimpleCameraExample/HomeViewController.m +++ b/LLSimpleCameraExample/HomeViewController.m @@ -49,12 +49,17 @@ - (void)viewDidLoad { // device changed, check if flash is available if([camera isFlashAvailable]) { weakSelf.flashButton.hidden = NO; + + if(camera.flash == CameraFlashOff) { + weakSelf.flashButton.selected = NO; + } + else { + weakSelf.flashButton.selected = YES; + } } else { weakSelf.flashButton.hidden = YES; } - - weakSelf.flashButton.selected = NO; }]; [self.camera setOnError:^(LLSimpleCamera *camera, NSError *error) { @@ -128,20 +133,25 @@ - (void)viewWillDisappear:(BOOL)animated { [self.camera stop]; } -/* camera buttons */ +/* camera button methods */ + - (void)switchButtonPressed:(UIButton *)button { [self.camera togglePosition]; } - (void)flashButtonPressed:(UIButton *)button { - if(self.camera.cameraFlash == CameraFlashOff) { - self.camera.cameraFlash = CameraFlashOn; - self.flashButton.selected = YES; + if(self.camera.flash == CameraFlashOff) { + BOOL done = [self.camera updateFlashMode:CameraFlashOn]; + if(done) { + self.flashButton.selected = YES; + } } else { - self.camera.cameraFlash = CameraFlashOff; - self.flashButton.selected = NO; + BOOL done = [self.camera updateFlashMode:CameraFlashOff]; + if(done) { + self.flashButton.selected = NO; + } } } From a4f225e041edb8fcfe224d7c3d620a3f4a226253 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Mon, 9 Mar 2015 19:34:40 +0200 Subject: [PATCH 7/8] README update --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index e87ccaa..3c5a64e 100755 --- a/README.md +++ b/README.md @@ -10,6 +10,12 @@ LLSimpleCamera is a library for creating a customized camera screens similar to * hides the nitty gritty details from the developer * doesn't have to be presented in a new modal view controller, simply can be embedded inside any of your VCs. (like Snapchat) +#### Version 2.2.0 +- camera permissions are supported, if the permission is not given by the user, onError will be triggered. +- camera flash methods are altered. Now you have to call **- (BOOL)updateFlashMode:(CameraFlash)cameraFlash;** +- cameraFlash and cameraPosition property names are simplified to: **flash** and **position**. +- added support for device orientation in case your vc orientation is locked but you want to use the device orientation no matter what. + #### Version 2.1.1 - freezing the screen just after the photo is taken for better user experience. From 584512f4d6250a80da1b32cbd9d0e331fd309b09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=96mer=20Faruk=20G=C3=BCl?= Date: Mon, 9 Mar 2015 19:35:41 +0200 Subject: [PATCH 8/8] podspec update for v2.2.0 --- LLSimpleCamera.podspec | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/LLSimpleCamera.podspec b/LLSimpleCamera.podspec index 626d13c..576205e 100644 --- a/LLSimpleCamera.podspec +++ b/LLSimpleCamera.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = "LLSimpleCamera" - s.version = "2.1.1" + s.version = "2.2.0" s.summary = "LLSimpleCamera: A simple customizable camera control." s.description = <<-DESC LLSimpleCamera is a library for creating a customized camera screens similar to snapchat's. You don't have to present the camera in a new view controller. @@ -13,9 +13,9 @@ hides the nitty gritty details from the developer s.homepage = "https://github.com/omergul123/LLSimpleCamera" s.license = { :type => 'APACHE', :file => 'LICENSE' } - s.author = { "Ömer Faruk Gül" => "omer.gul@louvredigital.com" } + s.author = { "Ömer Faruk Gül" => "omergul123@gmail.com" } s.platform = :ios,'7.0' - s.source = { :git => "https://github.com/omergul123/LLSimpleCamera.git", :tag => "v2.1.1" } + s.source = { :git => "https://github.com/omergul123/LLSimpleCamera.git", :tag => "v2.2.0" } s.source_files = 'LLSimpleCamera/*.{h,m}' s.requires_arc = true s.framework = 'AVFoundation'