From 9918bbeb968739d330a7518dd951b7e7370de115 Mon Sep 17 00:00:00 2001 From: Ran Greenberg Date: Tue, 19 Jul 2016 12:42:13 +0300 Subject: [PATCH] add ratio overlay feature --- example/CameraScreen.ios.js | 19 +- .../project.pbxproj | 12 ++ ios/lib/ReactNativeCameraKit/CKCamera.h | 1 + ios/lib/ReactNativeCameraKit/CKCamera.m | 187 +++++++++++++----- .../ReactNativeCameraKit/CKCameraManager.m | 2 +- .../CKCameraOverlayView.h | 26 +++ .../CKCameraOverlayView.m | 109 ++++++++++ .../ReactNativeCameraKit/CKOverlayObject.h | 21 ++ .../ReactNativeCameraKit/CKOverlayObject.m | 52 +++++ src/CameraKitCamera.ios.js | 8 +- 10 files changed, 378 insertions(+), 59 deletions(-) create mode 100644 ios/lib/ReactNativeCameraKit/CKCameraOverlayView.h create mode 100644 ios/lib/ReactNativeCameraKit/CKCameraOverlayView.m create mode 100644 ios/lib/ReactNativeCameraKit/CKOverlayObject.h create mode 100644 ios/lib/ReactNativeCameraKit/CKOverlayObject.m diff --git a/example/CameraScreen.ios.js b/example/CameraScreen.ios.js index 069f151..2c3d330 100644 --- a/example/CameraScreen.ios.js +++ b/example/CameraScreen.ios.js @@ -19,6 +19,8 @@ const FLASH_MODE_AUTO = "auto"; const FLASH_MODE_ON = "on"; const FLASH_MODE_OFF = "off"; +const RATIOS = ['3:4', '6:9', '1:1', '2:1']; + export default class CameraScreen extends Component { constructor(props) { @@ -31,7 +33,8 @@ export default class CameraScreen extends Component { shouldOpenCamera: false, shouldShowListView: false, image:{imageURI:""}, - flashMode:FLASH_MODE_AUTO + flashMode:FLASH_MODE_AUTO, + ratiosArrayPosition: 0 } } render() { @@ -49,11 +52,13 @@ export default class CameraScreen extends Component { ref={(cam) => { this.camera = cam; }} - style={{flex: 1}} + style={{flex: 1, backgroundColor:'white'}} cameraOptions= {{ flashMode: 'auto', // on/off/auto(default) focusMode: 'on', // off/on(default) - zoomMode: 'on' // off/on(default) + zoomMode: 'on', // off/on(default) + ratioOverlay:RATIOS[this.state.ratiosArrayPosition], + ratioOverlayColor: '#00000077' }} /> @@ -87,11 +92,19 @@ export default class CameraScreen extends Component { + this.ratioPressed() }> + {RATIOS[this.state.ratiosArrayPosition]} + + ) } + ratioPressed() { + this.setState({ratiosArrayPosition: (this.state.ratiosArrayPosition+1)%(RATIOS.length)}) + } + async onSwitchCameraPressed() { const success = await this.camera.changeCamera(); } diff --git a/ios/lib/ReactNativeCameraKit.xcodeproj/project.pbxproj b/ios/lib/ReactNativeCameraKit.xcodeproj/project.pbxproj index 0e93320..ff273f6 100644 --- a/ios/lib/ReactNativeCameraKit.xcodeproj/project.pbxproj +++ b/ios/lib/ReactNativeCameraKit.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ 26550AF61CFC7086007FF2DF /* CKCameraManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 26550AF51CFC7086007FF2DF /* CKCameraManager.m */; }; 2685AA241CFD89A300E4A446 /* CKCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = 2685AA231CFD89A300E4A446 /* CKCamera.m */; }; 268A64B71D2BFE5A0034460B /* SelectionGesture.m in Sources */ = {isa = PBXBuildFile; fileRef = 268A64B61D2BFE5A0034460B /* SelectionGesture.m */; }; + 269292831D3B7D6000E07DDF /* CKCameraOverlayView.m in Sources */ = {isa = PBXBuildFile; fileRef = 269292821D3B7D6000E07DDF /* CKCameraOverlayView.m */; }; + 269292861D3B81C800E07DDF /* CKOverlayObject.m in Sources */ = {isa = PBXBuildFile; fileRef = 269292851D3B81C800E07DDF /* CKOverlayObject.m */; }; 26F556721D2501C9007B1C11 /* GalleryData.m in Sources */ = {isa = PBXBuildFile; fileRef = 26F556711D2501C9007B1C11 /* GalleryData.m */; }; /* End PBXBuildFile section */ @@ -42,6 +44,10 @@ 2685AA231CFD89A300E4A446 /* CKCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKCamera.m; sourceTree = ""; }; 268A64B51D2BFE5A0034460B /* SelectionGesture.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SelectionGesture.h; sourceTree = ""; }; 268A64B61D2BFE5A0034460B /* SelectionGesture.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SelectionGesture.m; sourceTree = ""; }; + 269292811D3B7D6000E07DDF /* CKCameraOverlayView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKCameraOverlayView.h; sourceTree = ""; }; + 269292821D3B7D6000E07DDF /* CKCameraOverlayView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKCameraOverlayView.m; sourceTree = ""; }; + 269292841D3B81C800E07DDF /* CKOverlayObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CKOverlayObject.h; sourceTree = ""; }; + 269292851D3B81C800E07DDF /* CKOverlayObject.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CKOverlayObject.m; sourceTree = ""; }; 26F556701D2501C9007B1C11 /* GalleryData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = GalleryData.h; sourceTree = ""; }; 26F556711D2501C9007B1C11 /* GalleryData.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = GalleryData.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -90,6 +96,10 @@ 26F556711D2501C9007B1C11 /* GalleryData.m */, 268A64B51D2BFE5A0034460B /* SelectionGesture.h */, 268A64B61D2BFE5A0034460B /* SelectionGesture.m */, + 269292811D3B7D6000E07DDF /* CKCameraOverlayView.h */, + 269292821D3B7D6000E07DDF /* CKCameraOverlayView.m */, + 269292841D3B81C800E07DDF /* CKOverlayObject.h */, + 269292851D3B81C800E07DDF /* CKOverlayObject.m */, ); path = ReactNativeCameraKit; sourceTree = ""; @@ -152,8 +162,10 @@ files = ( 26550AF61CFC7086007FF2DF /* CKCameraManager.m in Sources */, 262E42201D183A6B00C82B27 /* CKGalleryCollectionViewCell.m in Sources */, + 269292861D3B81C800E07DDF /* CKOverlayObject.m in Sources */, 26550AE61CFC2437007FF2DF /* CKGalleryManager.m in Sources */, 2685AA241CFD89A300E4A446 /* CKCamera.m in Sources */, + 269292831D3B7D6000E07DDF /* CKCameraOverlayView.m in Sources */, 26F556721D2501C9007B1C11 /* GalleryData.m in Sources */, 268A64B71D2BFE5A0034460B /* SelectionGesture.m in Sources */, 262E421D1D182C1200C82B27 /* CKGalleryViewManager.m in Sources */, diff --git a/ios/lib/ReactNativeCameraKit/CKCamera.h b/ios/lib/ReactNativeCameraKit/CKCamera.h index 59e6c5a..9b17a5e 100644 --- a/ios/lib/ReactNativeCameraKit/CKCamera.h +++ b/ios/lib/ReactNativeCameraKit/CKCamera.h @@ -58,5 +58,6 @@ typedef NS_ENUM(NSInteger, CKCameraZoomMode) { - (void)snapStillImage:(BOOL)shouldSaveToCameraRoll success:(CaptureBlock)block; - (void)changeCamera:(CallbackBlock)block; - (void)setFlashMode:(AVCaptureFlashMode)flashMode callback:(CallbackBlock)block; +- (void)setRatio:(NSString*)ratioString; @end diff --git a/ios/lib/ReactNativeCameraKit/CKCamera.m b/ios/lib/ReactNativeCameraKit/CKCamera.m index 885464f..fddab0c 100644 --- a/ios/lib/ReactNativeCameraKit/CKCamera.m +++ b/ios/lib/ReactNativeCameraKit/CKCamera.m @@ -11,6 +11,7 @@ #import "CKCamera.h" #import "UIView+React.h" #import "RCTConvert.h" +#import "CKCameraOverlayView.h" static void * CapturingStillImageContext = &CapturingStillImageContext; @@ -52,9 +53,11 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ -#define CAMERA_OPTION_FLASH_MODE @"flashMode" -#define CAMERA_OPTION_FOCUS_MODE @"focusMode" -#define CAMERA_OPTION_ZOOM_MODE @"zoomMode" +#define CAMERA_OPTION_FLASH_MODE @"flashMode" +#define CAMERA_OPTION_FOCUS_MODE @"focusMode" +#define CAMERA_OPTION_ZOOM_MODE @"zoomMode" +#define CAMERA_OPTION_CAMERA_RATIO_OVERLAY @"ratioOverlay" +#define CAMERA_OPTION_CAMERA_RATIO_OVERLAY_COLOR @"ratioOverlayColor" #define TIMER_FOCUS_TIME_SECONDS 5 @interface CKCamera () @@ -64,6 +67,7 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ @property (nonatomic, strong) NSDictionary *cameraOptions; @property (nonatomic, strong) UIView *focusView; @property (nonatomic, strong) NSTimer *focusViewTimer; +@property (nonatomic, strong) CKCameraOverlayView *cameraOverlayView; // session management @property (nonatomic) dispatch_queue_t sessionQueue; @@ -82,6 +86,8 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ @property (nonatomic) CKCameraFocushMode focusMode; @property (nonatomic) CKCameraZoomMode zoomMode; @property (nonatomic, strong) PHFetchOptions *fetchOptions; +@property (nonatomic, strong) NSString* ratioOverlayString; +@property (nonatomic, strong) UIColor *ratioOverlayColor; @property (nonatomic) BOOL isAddedOberver; @@ -118,18 +124,14 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ - (void)removeFromSuperview { - + [super removeFromSuperview]; dispatch_async( self.sessionQueue, ^{ if ( self.setupResult == CKSetupResultSuccess ) { [self.session stopRunning]; [self removeObservers]; } - } ); - [super removeFromSuperview]; - - } - (instancetype)initWithFrame:(CGRect)frame { @@ -198,6 +200,19 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ [self addGestureRecognizer:pinchGesture]; } } + + // CAMERA_OPTION_CAMERA_RATIO_OVERLAY_COLOR + id ratioOverlayColor = self.cameraOptions[CAMERA_OPTION_CAMERA_RATIO_OVERLAY_COLOR]; + if (ratioOverlayColor) { + self.ratioOverlayColor = [RCTConvert UIColor:ratioOverlayColor]; + } + + // CAMERA_OPTION_CAMERA_RATIO_OVERLAY + id ratioOverlay = self.cameraOptions[CAMERA_OPTION_CAMERA_RATIO_OVERLAY]; + if (ratioOverlay) { + self.ratioOverlayString = [RCTConvert NSString:ratioOverlay]; + [self setRatio:self.ratioOverlayString]; + } } @@ -300,6 +315,7 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ [super reactSetFrame:frame]; self.previewLayer.frame = self.bounds; + [self setOverlayRatioView]; dispatch_async( self.sessionQueue, ^{ switch ( self.setupResult ) @@ -343,6 +359,18 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ } ); } +-(void)setRatioOverlayString:(NSString *)ratioOverlayString { + _ratioOverlayString = ratioOverlayString; + [self.cameraOverlayView setRatio:self.ratioOverlayString]; +} + +-(void)setOverlayRatioView { + if (!self.cameraOverlayView) { + self.cameraOverlayView = [[CKCameraOverlayView alloc] initWithFrame:self.bounds ratioString:self.ratioOverlayString overlayColor:self.ratioOverlayColor]; + [self addSubview:self.cameraOverlayView]; + } +} + #pragma mark - @@ -385,6 +413,7 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ captureDevice = device; break; } + } return captureDevice; @@ -413,6 +442,12 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ } } +- (void)setRatio:(NSString*)ratioString { + if (ratioString && ![ratioString isEqualToString:@""]) { + self.ratioOverlayString = ratioString; + } +} + #pragma mark - actions @@ -425,14 +460,27 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ // Update the orientation on the still image output video connection before capturing. connection.videoOrientation = self.previewLayer.connection.videoOrientation; - // Flash set to Auto for Still Capture. - // [CKCamera setFlashMode:AVCaptureFlashModeAuto forDevice:self.videoDeviceInput.device]; // Capture a still image. [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler:^( CMSampleBufferRef imageDataSampleBuffer, NSError *error ) { if ( imageDataSampleBuffer ) { // The sample buffer is not retained. Create image data before saving the still image to the photo library asynchronously. NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer]; + UIImage *capturedImage = [UIImage imageWithData:imageData]; + capturedImage = [CKCamera rotateImage:capturedImage]; + + CGSize previewScaleSize = [CKCamera cropImageToPreviewSize:capturedImage size:self.previewLayer.bounds.size]; + CGRect rectToCrop = CGRectMake((capturedImage.size.width-previewScaleSize.width)*0.5, (capturedImage.size.height-previewScaleSize.height)*0.5, previewScaleSize.width, previewScaleSize.height); + + if (self.ratioOverlayString) { + + rectToCrop = [CKCamera cropRectForSize:rectToCrop overlayObject:self.cameraOverlayView.overlayObject]; + } + + CGImageRef imageRef = CGImageCreateWithImageInRect(capturedImage.CGImage, rectToCrop); + capturedImage = [UIImage imageWithCGImage:imageRef scale:capturedImage.scale orientation:UIImageOrientationUp]; + imageData = UIImageJPEGRepresentation(capturedImage, capturedImage.scale); // TODO: check JPEG representation + [PHPhotoLibrary requestAuthorization:^( PHAuthorizationStatus status ) { if ( status == PHAuthorizationStatusAuthorized ) { @@ -450,7 +498,7 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ if (success) { PHFetchResult *fetchResult = [PHAsset fetchAssetsWithMediaType:PHAssetMediaTypeImage options:self.fetchOptions]; - PHAsset *lastImageAsset = [fetchResult firstObject]; + PHAsset *lastImageAsset = [fetchResult lastObject]; if (lastImageAsset.localIdentifier) { imageInfoDict[@"id"] = lastImageAsset.localIdentifier; @@ -481,6 +529,22 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ } ); } ++(UIImage*)rotateImage:(UIImage*)originalImage { + + if (originalImage.imageOrientation == UIImageOrientationUp || originalImage == nil) + return originalImage; + + + UIGraphicsBeginImageContextWithOptions(originalImage.size, NO, originalImage.scale); + + [originalImage drawInRect:(CGRect){0, 0, originalImage.size}]; + UIImage *normalizedImage = UIGraphicsGetImageFromCurrentImageContext(); + + UIGraphicsEndImageContext(); + + return normalizedImage; +} + -(void)changeCamera:(CallbackBlock)block { @@ -643,7 +707,6 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ } - - (void)focusWithMode:(AVCaptureFocusMode)focusMode exposeWithMode:(AVCaptureExposureMode)exposureMode atDevicePoint:(CGPoint)point monitorSubjectAreaChange:(BOOL)monitorSubjectAreaChange { dispatch_async( self.sessionQueue, ^{ @@ -695,6 +758,64 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ } ++ (UIImage *)imageWithImage:(UIImage *)image scaledToRect:(CGSize)newSize { + //UIGraphicsBeginImageContext(newSize); + // In next line, pass 0.0 to use the current device's pixel scaling factor (and thus account for Retina resolution). + // Pass 1.0 to force exact pixel size. + UIGraphicsBeginImageContextWithOptions(newSize, NO, 0.0); + [image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)]; + UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext(); + UIGraphicsEndImageContext(); + return newImage; +} + + ++(CGRect)cropRectForSize:(CGRect)frame overlayObject:(CKOverlayObject*)overlayObject { + + CGRect ans = CGRectZero; + CGSize centerSize = CGSizeZero; + + if (overlayObject.width < overlayObject.height) { + centerSize.width = frame.size.width; + centerSize.height = frame.size.height * overlayObject.ratio; + + ans.origin.x = 0; + ans.origin.y = (frame.size.height - centerSize.height)*0.5; + + } + else if (overlayObject.width > overlayObject.height){ + centerSize.width = frame.size.width / overlayObject.ratio; + centerSize.height = frame.size.height; + + ans.origin.x = (frame.size.width - centerSize.width)*0.5; + ans.origin.y = 0; + + } + else { // ratio is 1:1 + centerSize.width = frame.size.width; + centerSize.height = frame.size.width; + + ans.origin.x = 0; + ans.origin.y = (frame.size.height - centerSize.height)/2; + } + + ans.size = centerSize; + ans.origin.x += frame.origin.x; + ans.origin.y += frame.origin.y; + return ans; +} + ++(CGSize)cropImageToPreviewSize:(UIImage*)image size:(CGSize)previewSize { + + CGRect ans = CGRectZero; + CGSize centerSize = CGSizeZero; + + float imageToPreviewWidthScale = image.size.width/previewSize.width; + float imageToPreviewHeightScale = image.size.width/previewSize.width; + + return CGSizeMake(previewSize.width*imageToPreviewWidthScale, previewSize.height*imageToPreviewHeightScale); +} + #pragma mark - observers @@ -713,7 +834,6 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ // and show a preview is paused message. See the documentation of AVCaptureSessionWasInterruptedNotification for other // interruption reasons. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionWasInterrupted:) name:AVCaptureSessionWasInterruptedNotification object:self.session]; - [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(sessionInterruptionEnded:) name:AVCaptureSessionInterruptionEndedNotification object:self.session]; self.isAddedOberver = YES; } } @@ -737,48 +857,7 @@ RCT_ENUM_CONVERTER(CKCameraZoomMode, (@{ reason == AVCaptureSessionInterruptionReasonVideoDeviceInUseByAnotherClient ) { showResumeButton = YES; } - // else if ( reason == AVCaptureSessionInterruptionReasonVideoDeviceNotAvailableWithMultipleForegroundApps ) { - // // Simply fade-in a label to inform the user that the camera is unavailable. - // self.cameraUnavailableLabel.hidden = NO; - // self.cameraUnavailableLabel.alpha = 0.0; - // [UIView animateWithDuration:0.25 animations:^{ - // self.cameraUnavailableLabel.alpha = 1.0; - // }]; - // } } - else { - //NSLog( @"Capture session was interrupted" ); - showResumeButton = ( [UIApplication sharedApplication].applicationState == UIApplicationStateInactive ); - } - - // if ( showResumeButton ) { - // // Simply fade-in a button to enable the user to try to resume the session running. - // self.resumeButton.hidden = NO; - // self.resumeButton.alpha = 0.0; - // [UIView animateWithDuration:0.25 animations:^{ - // self.resumeButton.alpha = 1.0; - // }]; - // } -} - -- (void)sessionInterruptionEnded:(NSNotification *)notification -{ - //NSLog( @"Capture session interruption ended" ); - - // if ( ! self.resumeButton.hidden ) { - // [UIView animateWithDuration:0.25 animations:^{ - // self.resumeButton.alpha = 0.0; - // } completion:^( BOOL finished ) { - // self.resumeButton.hidden = YES; - // }]; - // } - // if ( ! self.cameraUnavailableLabel.hidden ) { - // [UIView animateWithDuration:0.25 animations:^{ - // self.cameraUnavailableLabel.alpha = 0.0; - // } completion:^( BOOL finished ) { - // self.cameraUnavailableLabel.hidden = YES; - // }]; - // } } diff --git a/ios/lib/ReactNativeCameraKit/CKCameraManager.m b/ios/lib/ReactNativeCameraKit/CKCameraManager.m index 3cd92ff..ef5205c 100644 --- a/ios/lib/ReactNativeCameraKit/CKCameraManager.m +++ b/ios/lib/ReactNativeCameraKit/CKCameraManager.m @@ -27,7 +27,7 @@ RCT_EXPORT_MODULE() return self.camera; } -RCT_REMAP_VIEW_PROPERTY(cameraOptions, cameraOptions, NSDictionary) +RCT_EXPORT_VIEW_PROPERTY(cameraOptions, NSDictionary) RCT_EXPORT_METHOD(checkDeviceAuthorizationStatus:(RCTPromiseResolveBlock)resolve diff --git a/ios/lib/ReactNativeCameraKit/CKCameraOverlayView.h b/ios/lib/ReactNativeCameraKit/CKCameraOverlayView.h new file mode 100644 index 0000000..40c8f51 --- /dev/null +++ b/ios/lib/ReactNativeCameraKit/CKCameraOverlayView.h @@ -0,0 +1,26 @@ +// +// CKCameraOverlayView.h +// ReactNativeCameraKit +// +// Created by Ran Greenberg on 17/07/2016. +// Copyright © 2016 Wix. All rights reserved. +// + +#import +#import "CKOverlayObject.h" + +@interface CKCameraOverlayView : UIView + + +@property (nonatomic, strong, readonly) UIView *centerView; +@property (nonatomic, strong, readonly) CKOverlayObject *overlayObject; + + + +-(instancetype)initWithFrame:(CGRect)frame ratioString:(NSString*)ratioString overlayColor:(UIColor*)overlayColor; + +-(void)setRatio:(NSString*)ratioString; + + + +@end diff --git a/ios/lib/ReactNativeCameraKit/CKCameraOverlayView.m b/ios/lib/ReactNativeCameraKit/CKCameraOverlayView.m new file mode 100644 index 0000000..4820876 --- /dev/null +++ b/ios/lib/ReactNativeCameraKit/CKCameraOverlayView.m @@ -0,0 +1,109 @@ +// +// CKCameraOverlayView.m +// ReactNativeCameraKit +// +// Created by Ran Greenberg on 17/07/2016. +// Copyright © 2016 Wix. All rights reserved. +// + +#import "CKCameraOverlayView.h" + + + +@interface CKCameraOverlayView () + +@property (nonatomic, strong, readwrite) CKOverlayObject *overlayObject; +@property (nonatomic, strong) UIView *topView; +@property (nonatomic, strong, readwrite) UIView *centerView; +@property (nonatomic, strong) UIView *bottomView; + + +@end + +@implementation CKCameraOverlayView + + + +-(instancetype)initWithFrame:(CGRect)frame ratioString:(NSString*)ratioString overlayColor:(UIColor*)overlayColor { + + self = [super initWithFrame:frame]; + + if (self) { + + self.overlayObject = [[CKOverlayObject alloc] initWithString:ratioString]; + self.topView = [[UIView alloc] initWithFrame:CGRectZero]; + self.centerView = [[UIView alloc] initWithFrame:CGRectZero]; + self.bottomView = [[UIView alloc] initWithFrame:CGRectZero]; + + overlayColor = overlayColor ? overlayColor : [UIColor colorWithRed:0 green:0 blue:0 alpha:0.3]; + + self.topView.backgroundColor = overlayColor; + self.bottomView.backgroundColor = overlayColor; + + [self addSubview:self.topView]; + [self addSubview:self.centerView]; + [self addSubview:self.bottomView]; + + [self setOverlayParts]; + } + + return self; +} + + +-(void)setOverlayParts { + + if (self.overlayObject.ratio == 0) return; + + CGSize centerSize = CGSizeZero; + CGSize sideSize = CGSizeZero; + + if (self.overlayObject.width < self.overlayObject.height) { + + centerSize.width = self.frame.size.width; + centerSize.height = self.frame.size.height * self.overlayObject.ratio; + + sideSize.width = centerSize.width; + sideSize.height = (self.frame.size.height - centerSize.height)/2.0; + + self.topView.frame = CGRectMake(0, 0, sideSize.width, sideSize.height); + self.centerView.frame = CGRectMake(0, self.topView.frame.size.height + self.topView.frame.origin.y, centerSize.width, centerSize.height); + self.bottomView.frame = CGRectMake(0, self.centerView.frame.size.height + self.centerView.frame.origin.y, sideSize.width, sideSize.height); + } + else if (self.overlayObject.width > self.overlayObject.height){ + centerSize.width = self.frame.size.width / self.overlayObject.ratio; + centerSize.height = self.frame.size.height; + + sideSize.width = (self.frame.size.width - centerSize.width)/2.0; + sideSize.height = centerSize.height; + + self.topView.frame = CGRectMake(0, 0, sideSize.width, sideSize.height); + self.centerView.frame = CGRectMake(self.topView.frame.size.width + self.topView.frame.origin.x, 0, centerSize.width, centerSize.height); + self.bottomView.frame = CGRectMake(self.centerView.frame.size.width + self.centerView.frame.origin.x, 0, sideSize.width, sideSize.height); + } + else { // ratio is 1:1 + centerSize.width = self.frame.size.width; + centerSize.height = self.frame.size.width; + + sideSize.width = centerSize.width; + sideSize.height = (self.frame.size.height - centerSize.height)/2.0; + + self.topView.frame = CGRectMake(0, 0, sideSize.width, sideSize.height); + self.centerView.frame = CGRectMake(0, self.topView.frame.size.height + self.topView.frame.origin.y, centerSize.width, centerSize.height); + self.bottomView.frame = CGRectMake(0, self.centerView.frame.size.height + self.centerView.frame.origin.y, sideSize.width, sideSize.height); + } +} + + +-(void)setRatio:(NSString*)ratioString { + self.overlayObject = [[CKOverlayObject alloc] initWithString:ratioString]; + +// self.alpha =0; + [UIView animateWithDuration:0.2 animations:^{ + [self setOverlayParts]; + } completion:nil]; + +} + + +@end diff --git a/ios/lib/ReactNativeCameraKit/CKOverlayObject.h b/ios/lib/ReactNativeCameraKit/CKOverlayObject.h new file mode 100644 index 0000000..baafeaf --- /dev/null +++ b/ios/lib/ReactNativeCameraKit/CKOverlayObject.h @@ -0,0 +1,21 @@ +// +// CKOverlayObject.h +// ReactNativeCameraKit +// +// Created by Ran Greenberg on 17/07/2016. +// Copyright © 2016 Wix. All rights reserved. +// + +#import + +@interface CKOverlayObject : NSObject + + +@property (nonatomic, readonly) float width; +@property (nonatomic, readonly) float height; +@property (nonatomic, readonly) float ratio; + +-(instancetype)initWithString:(NSString*)str; + + +@end diff --git a/ios/lib/ReactNativeCameraKit/CKOverlayObject.m b/ios/lib/ReactNativeCameraKit/CKOverlayObject.m new file mode 100644 index 0000000..da20a6c --- /dev/null +++ b/ios/lib/ReactNativeCameraKit/CKOverlayObject.m @@ -0,0 +1,52 @@ +// +// CKOverlayObject.m +// ReactNativeCameraKit +// +// Created by Ran Greenberg on 17/07/2016. +// Copyright © 2016 Wix. All rights reserved. +// + +#import "CKOverlayObject.h" + +@interface CKOverlayObject () + +@property (nonatomic, readwrite) float width; +@property (nonatomic, readwrite) float height; +@property (nonatomic, readwrite) float ratio; + +@end + +@implementation CKOverlayObject + +-(instancetype)initWithString:(NSString*)str { + + self = [super init]; + + if (self) { + [self commonInit:str]; + } + + return self; +} + +-(void)commonInit:(NSString*)str { + + NSArray *array = [str componentsSeparatedByString:@":"]; + if (array.count == 2) { + float first = [array[0] floatValue]; + float second = [array[1] floatValue]; + + if (first != 0 && second != 0) { + self.width = first; + self.height = second; + self.ratio = self.width/self.height; + } + } +} + +-(NSString *)description { + return [NSString stringWithFormat:@"width:%f height:%f ratio:%f", self.width, self.height, self.ratio]; +} + + +@end diff --git a/src/CameraKitCamera.ios.js b/src/CameraKitCamera.ios.js index c98c3e5..bd30316 100644 --- a/src/CameraKitCamera.ios.js +++ b/src/CameraKitCamera.ios.js @@ -1,7 +1,9 @@ +import _ from 'lodash'; import React, {Component} from 'react'; import { requireNativeComponent, - NativeModules + NativeModules, + processColor } from 'react-native'; const NativeCamera = requireNativeComponent('CKCamera', null); @@ -9,6 +11,10 @@ const NativeCameraAction = NativeModules.CKCameraManager; export default class CameraKitCamera extends React.Component { render() { + + const transformedProps = {...this.props}; + _.update(transformedProps, 'cameraOptions.ratioOverlayColor', (c) => processColor(c)); + return }