// // CACameraSessionDelegate.h // // Created by Christopher Cohen & Gabriel Alvarado on 1/23/15. // Copyright (c) 2015 Gabriel Alvarado. All rights reserved. // #import "CameraSessionView.h" #import "CaptureSessionManager.h" #import //Custom UI classes #import "CameraShutterButton.h" #import "CameraToggleButton.h" #import "CameraFlashButton.h" #import "CameraDismissButton.h" #import "CameraFocalReticule.h" #import "Constants.h" @interface CameraSessionView () { //Size of the UI elements variables CGSize shutterButtonSize; CGSize topBarSize; CGSize barButtonItemSize; //Variable vith the current camera being used (Rear/Front) CameraType cameraBeingUsed; } //Primative Properties @property (readwrite) BOOL animationInProgress; //Object References @property (nonatomic, strong) CaptureSessionManager *captureManager; @property (nonatomic, strong) CameraShutterButton *cameraShutter; @property (nonatomic, strong) CameraToggleButton *cameraToggle; @property (nonatomic, strong) CameraFlashButton *cameraFlash; @property (nonatomic, strong) CameraDismissButton *cameraDismiss; @property (nonatomic, strong) CameraFocalReticule *focalReticule; @property (nonatomic, strong) UIView *topBarView; //Temporary/Diagnostic properties @property (nonatomic, strong) UILabel *ISOLabel, *apertureLabel, *shutterSpeedLabel; @end @implementation CameraSessionView -(void)drawRect:(CGRect)rect { if (self) { _animationInProgress = NO; [self setupCaptureManager:RearFacingCamera]; cameraBeingUsed = RearFacingCamera; [self composeInterface]; [[_captureManager captureSession] startRunning]; } } -(instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; return self; } - (id)initWithCoder:(NSCoder *)aDecoder { self = [super initWithCoder:aDecoder]; return self; } #pragma mark - Setup -(void)setupCaptureManager:(CameraType)camera { // remove existing input AVCaptureInput* currentCameraInput = [self.captureManager.captureSession.inputs objectAtIndex:0]; [self.captureManager.captureSession removeInput:currentCameraInput]; _captureManager = nil; //Create and configure 'CaptureSessionManager' object _captureManager = [CaptureSessionManager new]; // indicate that some changes will be made to the session [self.captureManager.captureSession beginConfiguration]; if (_captureManager) { //Configure [_captureManager setDelegate:self]; [_captureManager initiateCaptureSessionForCamera:camera]; [_captureManager addStillImageOutput]; [_captureManager addVideoPreviewLayer]; [self.captureManager.captureSession commitConfiguration]; //Preview Layer setup CGRect layerRect = self.layer.bounds; [_captureManager.previewLayer setBounds:layerRect]; [_captureManager.previewLayer setPosition:CGPointMake(CGRectGetMidX(layerRect),CGRectGetMidY(layerRect))]; //Apply animation effect to the camera's preview layer CATransition *applicationLoadViewIn =[CATransition animation]; [applicationLoadViewIn setDuration:0.6]; [applicationLoadViewIn setType:kCATransitionReveal]; [applicationLoadViewIn setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn]]; [_captureManager.previewLayer addAnimation:applicationLoadViewIn forKey:kCATransitionReveal]; //Add to self.view's layer [self.layer addSublayer:_captureManager.previewLayer]; } } -(void)composeInterface { //Adding notifier for orientation changes [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil]; //Define adaptable sizing variables for UI elements to the right device family (iPhone or iPad) if ( UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad ) { //Declare the sizing of the UI elements for iPad shutterButtonSize = CGSizeMake(self.bounds.size.width * 0.1, self.bounds.size.width * 0.1); topBarSize = CGSizeMake(self.frame.size.width, self.frame.size.height * 0.06); barButtonItemSize = CGSizeMake([[UIScreen mainScreen] bounds].size.height * 0.04, [[UIScreen mainScreen] bounds].size.height * 0.04); } else { //Declare the sizing of the UI elements for iPhone shutterButtonSize = CGSizeMake(self.bounds.size.width * 0.21, self.bounds.size.width * 0.21); topBarSize = CGSizeMake(self.frame.size.width, [[UIScreen mainScreen] bounds].size.height * 0.07); barButtonItemSize = CGSizeMake([[UIScreen mainScreen] bounds].size.height * 0.05, [[UIScreen mainScreen] bounds].size.height * 0.05); } //Create shutter button _cameraShutter = [CameraShutterButton new]; if (_captureManager && !_hiddenShutter) { //Button Visual attribution _cameraShutter.frame = (CGRect){0,0, shutterButtonSize}; _cameraShutter.center = CGPointMake(self.frame.size.width/2, self.frame.size.height*0.875); _cameraShutter.tag = ShutterButtonTag; _cameraShutter.backgroundColor = [UIColor clearColor]; //Button target [_cameraShutter addTarget:self action:@selector(inputManager:) forControlEvents:UIControlEventTouchUpInside]; [self addSubview:_cameraShutter]; } //Create the top bar and add the buttons to it _topBarView = [UIView new]; if (_topBarView && !_hiddenTopBar) { //Setup visual attribution for bar _topBarView.frame = (CGRect){0,0, topBarSize}; _topBarView.backgroundColor = [UIColor colorWithRed: 0.176 green: 0.478 blue: 0.529 alpha: 0.64]; [self addSubview:_topBarView]; //Add the flash button _cameraFlash = [CameraFlashButton new]; if (_cameraFlash) { _cameraFlash.frame = (CGRect){0,0, barButtonItemSize}; _cameraFlash.center = CGPointMake(_topBarView.center.x * 0.80, _topBarView.center.y); _cameraFlash.tag = FlashButtonTag; if ( UI_USER_INTERFACE_IDIOM() != UIUserInterfaceIdiomPad ) [_topBarView addSubview:_cameraFlash]; } //Add the camera toggle button _cameraToggle = [CameraToggleButton new]; if (_cameraToggle) { _cameraToggle.frame = (CGRect){0,0, barButtonItemSize}; _cameraToggle.center = CGPointMake(_topBarView.center.x * 1.20, _topBarView.center.y); _cameraToggle.tag = ToggleButtonTag; [_topBarView addSubview:_cameraToggle]; } //Add the camera dismiss button _cameraDismiss = [CameraDismissButton new]; if (_cameraDismiss) { _cameraDismiss.frame = (CGRect){0,0, barButtonItemSize}; _cameraDismiss.center = CGPointMake(20, _topBarView.center.y); _cameraDismiss.tag = DismissButtonTag; [_topBarView addSubview:_cameraDismiss]; } //Attribute and configure all buttons in the bar's subview for (UIButton *button in _topBarView.subviews) { button.backgroundColor = [UIColor clearColor]; [button addTarget:self action:@selector(inputManager:) forControlEvents:UIControlEventTouchUpInside]; } } //Create the focus reticule UIView _focalReticule = [CameraFocalReticule new]; if (_focalReticule) { _focalReticule.frame = (CGRect){0,0, 60, 60}; _focalReticule.backgroundColor = [UIColor clearColor]; _focalReticule.hidden = YES; [self addSubview:_focalReticule]; } //Create the gesture recognizer for the focus tap UITapGestureRecognizer *singleTapGestureRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(focusGesture:)]; if (singleTapGestureRecognizer) [self addGestureRecognizer:singleTapGestureRecognizer]; } #pragma mark - User Interaction -(void)inputManager:(id)sender { //If animation is in progress, ignore input if (_animationInProgress) return; //If sender does not inherit from 'UIButton', return if (![sender isKindOfClass:[UIButton class]]) return; //Input manager switch switch ([(UIButton *)sender tag]) { case ShutterButtonTag: [self onTapShutterButton]; return; case ToggleButtonTag: [self onTapToggleButton]; return; case FlashButtonTag: [self onTapFlashButton]; return; case DismissButtonTag: [self onTapDismissButton]; return; } } - (void)onTapShutterButton { //Animate shutter release [self animateShutterRelease]; //Capture image from camera [_captureManager captureStillImage]; } - (void)onTapFlashButton { BOOL enable = !self.captureManager.isTorchEnabled; self.captureManager.enableTorch = enable; } - (void)onTapToggleButton { if (cameraBeingUsed == RearFacingCamera) { [self setupCaptureManager:FrontFacingCamera]; cameraBeingUsed = FrontFacingCamera; [self composeInterface]; [[_captureManager captureSession] startRunning]; _cameraFlash.hidden = YES; } else { [self setupCaptureManager:RearFacingCamera]; cameraBeingUsed = RearFacingCamera; [self composeInterface]; [[_captureManager captureSession] startRunning]; _cameraFlash.hidden = NO; } } - (void)onTapDismissButton { [_captureManager stop]; if ([self.delegate respondsToSelector:@selector(didDismiss)]) { [self.delegate didDismiss]; } // [UIView animateWithDuration:0.3 animations:^{ // self.center = CGPointMake(self.center.x, self.center.y*3); // } completion:^(BOOL finished) { // [self removeFromSuperview]; // // }]; } - (void)focusGesture:(id)sender { if ([sender isKindOfClass:[UITapGestureRecognizer class]]) { UITapGestureRecognizer *tap = sender; if (tap.state == UIGestureRecognizerStateRecognized) { CGPoint location = [sender locationInView:self]; [self focusAtPoint:location completionHandler:^{ [self animateFocusReticuleToPoint:location]; }]; } } } #pragma mark - Animation - (void)animateShutterRelease { _animationInProgress = YES; //Disables input manager [UIView animateWithDuration:.1 animations:^{ _cameraShutter.transform = CGAffineTransformMakeScale(1.25, 1.25); } completion:^(BOOL finished) { [UIView animateWithDuration:.1 animations:^{ _cameraShutter.transform = CGAffineTransformMakeScale(1, 1); } completion:^(BOOL finished) { _animationInProgress = NO; //Enables input manager }]; }]; } - (void)animateFocusReticuleToPoint:(CGPoint)targetPoint { _animationInProgress = YES; //Disables input manager [self.focalReticule setCenter:targetPoint]; self.focalReticule.alpha = 0.0; self.focalReticule.hidden = NO; [UIView animateWithDuration:0.4 animations:^{ self.focalReticule.alpha = 1.0; } completion:^(BOOL finished) { [UIView animateWithDuration:0.4 animations:^{ self.focalReticule.alpha = 0.0; }completion:^(BOOL finished) { _animationInProgress = NO; //Enables input manager }]; }]; } - (void)orientationChanged:(NSNotification *)notification{ //Animate top bar buttons on orientation changes switch ([[UIDevice currentDevice] orientation]) { case UIDeviceOrientationPortrait: { //Standard device orientation (Portrait) [UIView animateWithDuration:0.6 animations:^{ CGAffineTransform transform = CGAffineTransformMakeRotation( 0 ); _cameraFlash.transform = transform; _cameraFlash.center = CGPointMake(_topBarView.center.x * 0.80, _topBarView.center.y); _cameraToggle.transform = transform; _cameraToggle.center = CGPointMake(_topBarView.center.x * 1.20, _topBarView.center.y); _cameraDismiss.center = CGPointMake(20, _topBarView.center.y); }]; } break; case UIDeviceOrientationLandscapeLeft: { //Device orientation changed to landscape left [UIView animateWithDuration:0.6 animations:^{ CGAffineTransform transform = CGAffineTransformMakeRotation( M_PI_2 ); _cameraFlash.transform = transform; _cameraFlash.center = CGPointMake(_topBarView.center.x * 1.25, _topBarView.center.y); _cameraToggle.transform = transform; _cameraToggle.center = CGPointMake(_topBarView.center.x * 1.60, _topBarView.center.y); _cameraDismiss.center = CGPointMake(_topBarView.center.x * 0.25, _topBarView.center.y); }]; } break; case UIDeviceOrientationLandscapeRight: { //Device orientation changed to landscape right [UIView animateWithDuration:0.6 animations:^{ CGAffineTransform transform = CGAffineTransformMakeRotation( - M_PI_2 ); _cameraFlash.transform = transform; _cameraFlash.center = CGPointMake(_topBarView.center.x * 0.40, _topBarView.center.y); _cameraToggle.transform = transform; _cameraToggle.center = CGPointMake(_topBarView.center.x * 0.75, _topBarView.center.y); _cameraDismiss.center = CGPointMake(_topBarView.center.x * 1.75, _topBarView.center.y); }]; } break; default:; } } #pragma mark - Camera Session Manager Delegate Methods -(void)cameraSessionManagerDidCaptureImage { if (self.delegate) { if ([self.delegate respondsToSelector:@selector(didCaptureImage:)]) [self.delegate didCaptureImage:[[self captureManager] stillImage]]; if ([self.delegate respondsToSelector:@selector(didCaptureImageWithData:)]) [self.delegate didCaptureImageWithData:[[self captureManager] stillImageData]]; } } -(void)cameraSessionManagerFailedToCaptureImage { } -(void)cameraSessionManagerDidReportAvailability:(BOOL)deviceAvailability forCameraType:(CameraType)cameraType { } -(void)cameraSessionManagerDidReportDeviceStatistics:(CameraStatistics)deviceStatistics { } #pragma mark - Helper Methods - (void)focusAtPoint:(CGPoint)point completionHandler:(void(^)())completionHandler { AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];; CGPoint pointOfInterest = CGPointZero; CGSize frameSize = self.bounds.size; pointOfInterest = CGPointMake(point.y / frameSize.height, 1.f - (point.x / frameSize.width)); if ([device isFocusPointOfInterestSupported] && [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { //Lock camera for configuration if possible NSError *error; if ([device lockForConfiguration:&error]) { if ([device isWhiteBalanceModeSupported:AVCaptureWhiteBalanceModeAutoWhiteBalance]) { [device setWhiteBalanceMode:AVCaptureWhiteBalanceModeAutoWhiteBalance]; } if ([device isFocusModeSupported:AVCaptureFocusModeContinuousAutoFocus]) { [device setFocusMode:AVCaptureFocusModeAutoFocus]; [device setFocusPointOfInterest:pointOfInterest]; } if([device isExposurePointOfInterestSupported] && [device isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) { [device setExposurePointOfInterest:pointOfInterest]; [device setExposureMode:AVCaptureExposureModeContinuousAutoExposure]; } [device unlockForConfiguration]; completionHandler(); } } else { completionHandler(); } } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return (interfaceOrientation == UIInterfaceOrientationPortrait); } -(BOOL)shouldAutorotate { return YES; } -(NSUInteger)supportedInterfaceOrientations { return UIInterfaceOrientationMaskPortrait; } -(void)viewDidDisappear:(BOOL)animated{ [[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; } #pragma mark - API Functions - (void)setTopBarColor:(UIColor *)topBarColor { _topBarView.backgroundColor = topBarColor; } - (void)hideFlashButton { _cameraFlash.hidden = YES; } - (void)hideCameraToggleButton { _cameraToggle.hidden = YES; } - (void)hideDismissButton { _cameraDismiss.hidden = YES; } - (void)dealloc { [[NSNotificationCenter defaultCenter] removeObserver:self]; } @end