diff --git a/docs/RNCamera.md b/docs/RNCamera.md index 9c8a3c821..e00196a01 100644 --- a/docs/RNCamera.md +++ b/docs/RNCamera.md @@ -180,6 +180,14 @@ Most cameras have a Auto Focus feature. It adjusts your camera lens position aut Use the `autoFocus` property to specify the auto focus setting of your camera. `RNCamera.Constants.AutoFocus.on` turns it ON, `RNCamera.Constants.AutoFocus.off` turns it OFF. +#### `autoFocusPointOfInterest` + +Values: Object `{ x: 0.5, y: 0.5 }`. + +Setting this property causes the auto focus feature of the camera to attempt to focus on the part of the image at this coordiate. + +Coordinates values are measured as floats from `0` to `1.0`. `{ x: 0, y: 0 }` will focus on the top left of the image, `{ x: 1, y: 1 }` will be the bottom right. Values are based on landscape mode with the home button on the right—this applies even if the device is in portrait mode. + #### `iOS` `captureAudio` Values: `true` (Boolean), `false` (default) diff --git a/ios/RN/RNCamera.h b/ios/RN/RNCamera.h index 83efe6d3d..402649290 100644 --- a/ios/RN/RNCamera.h +++ b/ios/RN/RNCamera.h @@ -27,6 +27,7 @@ @property (assign, nonatomic) NSInteger flashMode; @property (assign, nonatomic) CGFloat zoom; @property (assign, nonatomic) NSInteger autoFocus; +@property (copy, nonatomic) NSDictionary *autoFocusPointOfInterest; @property (assign, nonatomic) float focusDepth; @property (assign, nonatomic) NSInteger whiteBalance; @property (nonatomic, assign, getter=isReadingBarCodes) BOOL barCodeReading; @@ -37,6 +38,7 @@ - (void)updateFlashMode; - (void)updateFocusMode; - (void)updateFocusDepth; +- (void)updateAutoFocusPointOfInterest; - (void)updateZoom; - (void)updateWhiteBalance; - (void)updateFaceDetecting:(id)isDetectingFaces; diff --git a/ios/RN/RNCamera.m b/ios/RN/RNCamera.m index ee7de48be..2ded27433 100644 --- a/ios/RN/RNCamera.m +++ b/ios/RN/RNCamera.m @@ -180,6 +180,34 @@ - (void)updateFlashMode [device unlockForConfiguration]; } +- (void)updateAutoFocusPointOfInterest +{ + AVCaptureDevice *device = [self.videoCaptureDeviceInput device]; + NSError *error = nil; + + if (![device lockForConfiguration:&error]) { + if (error) { + RCTLogError(@"%s: %@", __func__, error); + } + return; + } + + if ([self.autoFocusPointOfInterest objectForKey:@"x"] && [self.autoFocusPointOfInterest objectForKey:@"y"]) { + float xValue = [self.autoFocusPointOfInterest[@"x"] floatValue]; + float yValue = [self.autoFocusPointOfInterest[@"y"] floatValue]; + if ([device isFocusPointOfInterestSupported]) { + CGPoint autofocusPoint = CGPointMake(xValue, yValue); + [device setFocusPointOfInterest:autofocusPoint]; + [device setFocusMode:AVCaptureFocusModeContinuousAutoFocus]; + } + else { + RCTLogWarn(@"AutoFocusPointOfInterest not supported"); + } + } + + [device unlockForConfiguration]; +} + - (void)updateFocusMode { AVCaptureDevice *device = [self.videoCaptureDeviceInput device]; @@ -560,6 +588,7 @@ - (void)initializeCaptureSessionInput [self updateZoom]; [self updateFocusMode]; [self updateFocusDepth]; + [self updateAutoFocusPointOfInterest]; [self updateWhiteBalance]; [self.previewLayer.connection setVideoOrientation:orientation]; [self _updateMetadataObjectsToRecognize]; diff --git a/ios/RN/RNCameraManager.m b/ios/RN/RNCameraManager.m index 89f710e8c..1718863a8 100644 --- a/ios/RN/RNCameraManager.m +++ b/ios/RN/RNCameraManager.m @@ -144,6 +144,12 @@ + (NSDictionary *)faceDetectorConstants [view updateFocusMode]; } +RCT_CUSTOM_VIEW_PROPERTY(autoFocusPointOfInterest, NSDictionary, RNCamera) +{ + [view setAutoFocusPointOfInterest:[RCTConvert NSDictionary:json]]; + [view updateAutoFocusPointOfInterest]; +} + RCT_CUSTOM_VIEW_PROPERTY(focusDepth, NSNumber, RNCamera) { [view setFocusDepth:[RCTConvert float:json]]; diff --git a/src/RNCamera.js b/src/RNCamera.js index 91a6c2815..392052add 100644 --- a/src/RNCamera.js +++ b/src/RNCamera.js @@ -30,7 +30,7 @@ const styles = StyleSheet.create({ }, }); -type Orientation = "auto"|"landscapeLeft"|"landscapeRight"|"portrait"|"portraitUpsideDown"; +type Orientation = 'auto' | 'landscapeLeft' | 'landscapeRight' | 'portrait' | 'portraitUpsideDown'; type PictureOptions = { quality?: number, @@ -90,6 +90,7 @@ type PropsType = typeof View.props & { whiteBalance?: number | string, faceDetectionLandmarks?: number, autoFocus?: string | boolean | number, + autoFocusPointOfInterest?: { x: number, y: number }, faceDetectionClassifications?: number, onFacesDetected?: ({ faces: Array }) => void, onTextRecognized?: ({ textBlocks: Array }) => void, @@ -188,6 +189,7 @@ export default class Camera extends React.Component { flashMode: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), whiteBalance: PropTypes.oneOfType([PropTypes.string, PropTypes.number]), autoFocus: PropTypes.oneOfType([PropTypes.string, PropTypes.number, PropTypes.bool]), + autoFocusPointOfInterest: PropTypes.shape({ x: PropTypes.number, y: PropTypes.number }), permissionDialogTitle: PropTypes.string, permissionDialogMessage: PropTypes.string, notAuthorizedView: PropTypes.element, @@ -318,7 +320,7 @@ export default class Camera extends React.Component { } }; - async componentWillMount() { + async UNSAFE_componentWillMount() { const hasVideoAndAudio = this.props.captureAudio; const isAuthorized = await requestPermissions( hasVideoAndAudio,