From be090ec70a339e699d479aab3f163a237707ce07 Mon Sep 17 00:00:00 2001 From: Dmitriy Loktev Date: Mon, 27 Jul 2015 16:08:33 +0600 Subject: [PATCH] Tap-to-focus and Pinch-to-zoom --- CameraFocusSquare.h | 3 ++ CameraFocusSquare.m | 28 +++++++++++++++ RCTCamera.h | 3 ++ RCTCamera.m | 55 +++++++++++++++++++++++++++++ RCTCamera.xcodeproj/project.pbxproj | 6 ++++ RCTCameraManager.h | 4 +++ RCTCameraManager.m | 42 ++++++++++++++++++++++ 7 files changed, 141 insertions(+) create mode 100644 CameraFocusSquare.h create mode 100644 CameraFocusSquare.m diff --git a/CameraFocusSquare.h b/CameraFocusSquare.h new file mode 100644 index 0000000..0c11382 --- /dev/null +++ b/CameraFocusSquare.h @@ -0,0 +1,3 @@ +#import +@interface RCTCameraFocusSquare : UIView +@end \ No newline at end of file diff --git a/CameraFocusSquare.m b/CameraFocusSquare.m new file mode 100644 index 0000000..b7d2073 --- /dev/null +++ b/CameraFocusSquare.m @@ -0,0 +1,28 @@ +#import "CameraFocusSquare.h" +#import + +const float squareLength = 80.0f; +@implementation RCTCameraFocusSquare + +- (id)initWithFrame:(CGRect)frame +{ + self = [super initWithFrame:frame]; + if (self) { + // Initialization code + + [self setBackgroundColor:[UIColor clearColor]]; + [self.layer setBorderWidth:2.0]; + [self.layer setCornerRadius:4.0]; + [self.layer setBorderColor:[UIColor whiteColor].CGColor]; + + CABasicAnimation* selectionAnimation = [CABasicAnimation + animationWithKeyPath:@"borderColor"]; + selectionAnimation.toValue = (id)[UIColor blueColor].CGColor; + selectionAnimation.repeatCount = 8; + [self.layer addAnimation:selectionAnimation + forKey:@"selectionAnimation"]; + + } + return self; +} +@end \ No newline at end of file diff --git a/RCTCamera.h b/RCTCamera.h index 83daf61..edeaf27 100644 --- a/RCTCamera.h +++ b/RCTCamera.h @@ -1,11 +1,14 @@ #import #import +#import "CameraFocusSquare.h" @class RCTCameraManager; @interface RCTCamera : UIView @property (nonatomic) RCTCameraManager *manager; +@property (nonatomic) RCTCameraFocusSquare *camFocus; +@property (nonatomic) BOOL multipleTouches; - (id)initWithManager:(RCTCameraManager*)manager; diff --git a/RCTCamera.m b/RCTCamera.m index 1fb9857..891b31d 100644 --- a/RCTCamera.m +++ b/RCTCamera.m @@ -5,6 +5,7 @@ #import "RCTUtils.h" #import +#import "CameraFocusSquare.h" @implementation RCTCamera @@ -64,8 +65,11 @@ if ((self = [super init])) { self.manager = manager; + UIPinchGestureRecognizer *pinchGesture = [[UIPinchGestureRecognizer alloc] initWithTarget:self action:@selector(handlePinchToZoomRecognizer:)]; + [self addGestureRecognizer:pinchGesture]; [self.manager initializeCaptureSessionInput:AVMediaTypeVideo]; [self.manager startSession]; + self.multipleTouches = NO; } return self; } @@ -102,4 +106,55 @@ [self.manager changeOrientation:orientation]; } + +- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event +{ + // Update the touch state. + if ([[event touchesForView:self] count] > 1) { + self.multipleTouches = YES; + } + +} + +- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event +{ + BOOL allTouchesEnded = ([touches count] == [[event touchesForView:self] count]); + + // Do not conflict with zooming and etc. + if (allTouchesEnded && !self.multipleTouches) { + UITouch *touch = [[event allTouches] anyObject]; + CGPoint touchPoint = [touch locationInView:touch.view]; + // Focus camera on this point + [self.manager focusAtThePoint:touchPoint]; + + if (self.camFocus) + { + [self.camFocus removeFromSuperview]; + } + // Show animated rectangle on the touched area + self.camFocus = [[RCTCameraFocusSquare alloc]initWithFrame:CGRectMake(touchPoint.x-40, touchPoint.y-40, 80, 80)]; + [self.camFocus setBackgroundColor:[UIColor clearColor]]; + [self addSubview:self.camFocus]; + [self.camFocus setNeedsDisplay]; + + [UIView beginAnimations:nil context:NULL]; + [UIView setAnimationDuration:1.0]; + [self.camFocus setAlpha:0.0]; + [UIView commitAnimations]; + } + + if (allTouchesEnded) { + self.multipleTouches = NO; + } + +} + + +-(void) handlePinchToZoomRecognizer:(UIPinchGestureRecognizer*)pinchRecognizer { + if (pinchRecognizer.state == UIGestureRecognizerStateChanged) { + [self.manager zoom:pinchRecognizer.velocity]; + } +} + + @end diff --git a/RCTCamera.xcodeproj/project.pbxproj b/RCTCamera.xcodeproj/project.pbxproj index 9bdb57a..b7d47f5 100644 --- a/RCTCamera.xcodeproj/project.pbxproj +++ b/RCTCamera.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 0314E39D1B661A460092D183 /* CameraFocusSquare.m in Sources */ = {isa = PBXBuildFile; fileRef = 0314E39C1B661A460092D183 /* CameraFocusSquare.m */; }; 4107014D1ACB732B00C6AA39 /* RCTCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = 410701481ACB732B00C6AA39 /* RCTCamera.m */; }; 4107014E1ACB732B00C6AA39 /* RCTCameraManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 4107014A1ACB732B00C6AA39 /* RCTCameraManager.m */; }; 454EBCF41B5082DC00AD0F86 /* NSMutableDictionary+ImageMetadata.m in Sources */ = {isa = PBXBuildFile; fileRef = 454EBCF31B5082DC00AD0F86 /* NSMutableDictionary+ImageMetadata.m */; }; @@ -25,6 +26,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 0314E39B1B661A0C0092D183 /* CameraFocusSquare.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CameraFocusSquare.h; sourceTree = ""; }; + 0314E39C1B661A460092D183 /* CameraFocusSquare.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraFocusSquare.m; sourceTree = ""; }; 4107012F1ACB723B00C6AA39 /* libRCTCamera.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRCTCamera.a; sourceTree = BUILT_PRODUCTS_DIR; }; 410701471ACB732B00C6AA39 /* RCTCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTCamera.h; sourceTree = ""; }; 410701481ACB732B00C6AA39 /* RCTCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCamera.m; sourceTree = ""; }; @@ -47,6 +50,8 @@ 410701241ACB719800C6AA39 = { isa = PBXGroup; children = ( + 0314E39C1B661A460092D183 /* CameraFocusSquare.m */, + 0314E39B1B661A0C0092D183 /* CameraFocusSquare.h */, 454EBCF31B5082DC00AD0F86 /* NSMutableDictionary+ImageMetadata.m */, 410701471ACB732B00C6AA39 /* RCTCamera.h */, 410701481ACB732B00C6AA39 /* RCTCamera.m */, @@ -119,6 +124,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 0314E39D1B661A460092D183 /* CameraFocusSquare.m in Sources */, 454EBCF41B5082DC00AD0F86 /* NSMutableDictionary+ImageMetadata.m in Sources */, 4107014E1ACB732B00C6AA39 /* RCTCameraManager.m in Sources */, 4107014D1ACB732B00C6AA39 /* RCTCamera.m in Sources */, diff --git a/RCTCameraManager.h b/RCTCameraManager.h index dd74661..bcb7bb7 100644 --- a/RCTCameraManager.h +++ b/RCTCameraManager.h @@ -60,6 +60,7 @@ typedef NS_ENUM(NSInteger, RCTCameraTorchMode) { @property (nonatomic) NSInteger videoTarget; @property (nonatomic, strong) RCTResponseSenderBlock videoCallback; + - (void)changeAspect:(NSString *)aspect; - (void)changeCamera:(NSInteger)camera; - (void)changeOrientation:(NSInteger)orientation; @@ -71,5 +72,8 @@ typedef NS_ENUM(NSInteger, RCTCameraTorchMode) { - (void)stopCapture; - (void)startSession; - (void)stopSession; +- (void)focusAtThePoint:(CGPoint) atPoint; +- (void)zoom:(CGFloat)velocity; + @end diff --git a/RCTCameraManager.m b/RCTCameraManager.m index a7302ff..b4759b6 100644 --- a/RCTCameraManager.m +++ b/RCTCameraManager.m @@ -105,6 +105,7 @@ RCT_EXPORT_VIEW_PROPERTY(torchMode, NSInteger); self.sessionQueue = dispatch_queue_create("cameraManagerQueue", DISPATCH_QUEUE_SERIAL); + } return self; } @@ -661,5 +662,46 @@ didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL }); } +- (void) focusAtThePoint:(CGPoint) atPoint; +{ + Class captureDeviceClass = NSClassFromString(@"AVCaptureDevice"); + if (captureDeviceClass != nil) { + dispatch_async([self sessionQueue], ^{ + AVCaptureDevice *device = [[self videoCaptureDeviceInput] device]; + if([device isFocusPointOfInterestSupported] && + [device isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { + CGRect screenRect = [[UIScreen mainScreen] bounds]; + double screenWidth = screenRect.size.width; + double screenHeight = screenRect.size.height; + double focus_x = atPoint.x/screenWidth; + double focus_y = atPoint.y/screenHeight; + if([device lockForConfiguration:nil]) { + [device setFocusPointOfInterest:CGPointMake(focus_x,focus_y)]; + [device setFocusMode:AVCaptureFocusModeAutoFocus]; + if ([device isExposureModeSupported:AVCaptureExposureModeAutoExpose]){ + [device setExposureMode:AVCaptureExposureModeAutoExpose]; + } + [device unlockForConfiguration]; + } + } + }); + } +} + +- (void) zoom:(CGFloat)velocity { + const CGFloat pinchVelocityDividerFactor = 20.0f; // TODO: calibrate or make this component's property + NSError *error = nil; + AVCaptureDevice *device = [[self videoCaptureDeviceInput] device]; + if ([device lockForConfiguration:&error]) { + CGFloat zoomFactor = device.videoZoomFactor + atan(velocity / pinchVelocityDividerFactor); + device.videoZoomFactor = zoomFactor >= 1.0f ? zoomFactor : 1.0f; + [device unlockForConfiguration]; + } else { + NSLog(@"error: %@", error); + } +} + + + @end