Tap-to-focus and Pinch-to-zoom

This commit is contained in:
Dmitriy Loktev 2015-07-27 16:08:33 +06:00
parent d3d60279fc
commit be090ec70a
7 changed files with 141 additions and 0 deletions

3
CameraFocusSquare.h Normal file
View File

@ -0,0 +1,3 @@
#import <UIKit/UIKit.h>
@interface RCTCameraFocusSquare : UIView
@end

28
CameraFocusSquare.m Normal file
View File

@ -0,0 +1,28 @@
#import "CameraFocusSquare.h"
#import <QuartzCore/QuartzCore.h>
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

View File

@ -1,11 +1,14 @@
#import <UIKit/UIKit.h>
#import <AVFoundation/AVFoundation.h>
#import "CameraFocusSquare.h"
@class RCTCameraManager;
@interface RCTCamera : UIView
@property (nonatomic) RCTCameraManager *manager;
@property (nonatomic) RCTCameraFocusSquare *camFocus;
@property (nonatomic) BOOL multipleTouches;
- (id)initWithManager:(RCTCameraManager*)manager;

View File

@ -5,6 +5,7 @@
#import "RCTUtils.h"
#import <AVFoundation/AVFoundation.h>
#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

View File

@ -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 = "<group>"; };
0314E39C1B661A460092D183 /* CameraFocusSquare.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraFocusSquare.m; sourceTree = "<group>"; };
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 = "<group>"; };
410701481ACB732B00C6AA39 /* RCTCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTCamera.m; sourceTree = "<group>"; };
@ -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 */,

View File

@ -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

View File

@ -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