You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

489 lines
17 KiB

//
// 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 <ImageIO/ImageIO.h>
//Custom UI classes
#import "CameraShutterButton.h"
#import "CameraToggleButton.h"
#import "CameraFlashButton.h"
#import "CameraDismissButton.h"
#import "CameraFocalReticule.h"
#import "Constants.h"
@interface CameraSessionView () <CaptureSessionManagerDelegate>
{
//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