diff --git a/Camera.js b/Camera.js index 3aef332..97e238f 100644 --- a/Camera.js +++ b/Camera.js @@ -33,6 +33,10 @@ function convertStringProps(props) { newProps.type = Camera.constants.Type[props.type]; } + if (typeof props.captureQuality === 'string') { + newProps.captureQuality = Camera.constants.CaptureQuality[props.captureQuality]; + } + return newProps; } @@ -44,6 +48,7 @@ export default class Camera extends Component { Type: CameraManager.Type, CaptureMode: CameraManager.CaptureMode, CaptureTarget: CameraManager.CaptureTarget, + CaptureQuality: CameraManager.CaptureQuality, Orientation: CameraManager.Orientation, FlashMode: CameraManager.FlashMode, TorchMode: CameraManager.TorchMode @@ -60,6 +65,10 @@ export default class Camera extends Component { PropTypes.string, PropTypes.number ]), + captureQuality: PropTypes.oneOfType([ + PropTypes.string, + PropTypes.number + ]), captureTarget: PropTypes.oneOfType([ PropTypes.string, PropTypes.number @@ -94,6 +103,7 @@ export default class Camera extends Component { captureAudio: true, captureMode: CameraManager.CaptureMode.still, captureTarget: CameraManager.CaptureTarget.cameraRoll, + captureQuality: CameraManager.CaptureQuality.high, defaultOnFocusComponent: true, flashMode: CameraManager.FlashMode.off, torchMode: CameraManager.TorchMode.off @@ -143,6 +153,7 @@ export default class Camera extends Component { audio: props.captureAudio, mode: props.captureMode, target: props.captureTarget, + quality: props.captureQuality, type: props.type, title: '', description: '', diff --git a/README.md b/README.md index 81f71fc..d531c5a 100644 --- a/README.md +++ b/README.md @@ -139,6 +139,11 @@ Values: `Camera.constants.CaptureTarget.cameraRoll` (default), `Camera.constants This property allows you to specify the target output of the captured image data. By default the image binary is sent back as a base 64 encoded string. The disk output has been shown to improve capture response time, so that is the recommended value. +#### `iOS` `captureQuality` + +Values: `Camera.constants.CaptureQuality.high` or `"high"` (default), `Camera.constants.CaptureQuality.medium` or `"medium"`, `Camera.constants.CaptureQuality.low` or `"low"` + +This property allows you to specify the quality output of the captured image or video. By default the quality is set to high. #### `type` diff --git a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCamera.java b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCamera.java index a174df4..08d9260 100644 --- a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCamera.java +++ b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCamera.java @@ -59,6 +59,79 @@ public class RCTCamera { return cameraInfo.previewHeight; } + public Camera.Size getBestPreviewSize(int type, int width, int height) + { + Camera camera = _cameras.get(type); + Camera.Size result = null; + if(camera == null) { + return null; + } + Camera.Parameters params = camera.getParameters(); + for (Camera.Size size : params.getSupportedPreviewSizes()) { + if (size.width <= width && size.height <= height) { + if (result == null) { + result = size; + } else { + int resultArea = result.width * result.height; + int newArea = size.width * size.height; + + if (newArea > resultArea) { + result = size; + } + } + } + } + return result; + } + + public Camera.Size getBestPictureSize(int type, int width, int height) + { + Camera camera = _cameras.get(type); + Camera.Size result = null; + if(camera == null) { + return null; + } + Camera.Parameters params = camera.getParameters(); + for (Camera.Size size : params.getSupportedPictureSizes()) { + if (size.width <= width && size.height <= height) { + if (result == null) { + result = size; + } else { + int resultArea = result.width * result.height; + int newArea = size.width * size.height; + + if (newArea > resultArea) { + result = size; + } + } + } + } + return result; + } + + public Camera.Size getSmallestPictureSize(int type) + { + Camera camera = _cameras.get(type); + Camera.Size result = null; + if(camera == null) { + return null; + } + Camera.Parameters params = camera.getParameters(); + for (Camera.Size size : params.getSupportedPictureSizes()) { + if (result == null) { + result = size; + } else { + int resultArea = result.width * result.height; + int newArea = size.width * size.height; + + if (newArea < resultArea) { + result = size; + } + } + } + return result; + } + public void setOrientation(int orientation) { if (_orientation == orientation) { return; @@ -74,6 +147,33 @@ public class RCTCamera { adjustPreviewLayout(RCTCameraModule.RCT_CAMERA_TYPE_BACK); } + public void setCaptureQuality(int cameraType, String captureQuality) { + Camera camera = _cameras.get(cameraType); + if (null == camera) { + return; + } + + Camera.Parameters parameters = camera.getParameters(); + Camera.Size pictureSize = null; + switch (captureQuality) { + case "low": + pictureSize = getSmallestPictureSize(cameraType); // select the lowest res + break; + case "medium": + List sizes = parameters.getSupportedPictureSizes(); + pictureSize = sizes.get(sizes.size() / 2); + break; + case "high": + pictureSize = getBestPictureSize(cameraType, Integer.MAX_VALUE, Integer.MAX_VALUE); // select the highest res + break; + } + + if (pictureSize != null) { + parameters.setPictureSize(pictureSize.width, pictureSize.height); + camera.setParameters(parameters); + } + } + public void setTorchMode(int cameraType, int torchMode) { Camera camera = _cameras.get(cameraType); if (null == camera) { @@ -150,8 +250,10 @@ public class RCTCamera { parameters.setRotation(cameraInfo.rotation); // set preview size - int width = parameters.getSupportedPreviewSizes().get(0).width; - int height = parameters.getSupportedPreviewSizes().get(0).height; + // defaults to highest resolution available + Camera.Size optimalPreviewSize = getBestPreviewSize(type, Integer.MAX_VALUE, Integer.MAX_VALUE); + int width = optimalPreviewSize.width; + int height = optimalPreviewSize.height; parameters.setPreviewSize(width, height); try { diff --git a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraModule.java b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraModule.java index b4c8570..b73e5d1 100644 --- a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraModule.java +++ b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraModule.java @@ -69,6 +69,7 @@ public class RCTCameraModule extends ReactContextBaseJavaModule { { put("Aspect", getAspectConstants()); put("Type", getTypeConstants()); + put("CaptureQuality", getCaptureQualityConstants()); put("CaptureMode", getCaptureModeConstants()); put("CaptureTarget", getCaptureTargetConstants()); put("Orientation", getOrientationConstants()); @@ -95,6 +96,16 @@ public class RCTCameraModule extends ReactContextBaseJavaModule { }); } + private Map getCaptureQualityConstants() { + return Collections.unmodifiableMap(new HashMap() { + { + put("low", "low"); + put("medium", "medium"); + put("high", "high"); + } + }); + } + private Map getCaptureModeConstants() { return Collections.unmodifiableMap(new HashMap() { { @@ -156,6 +167,7 @@ public class RCTCameraModule extends ReactContextBaseJavaModule { promise.reject("No camera found."); return; } + RCTCamera.getInstance().setCaptureQuality(options.getInt("type"), options.getString("quality")); camera.takePicture(null, null, new Camera.PictureCallback() { @Override public void onPictureTaken(byte[] data, Camera camera) { diff --git a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraView.java b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraView.java index 2d22c3c..198c92c 100644 --- a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraView.java +++ b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraView.java @@ -17,6 +17,7 @@ public class RCTCameraView extends ViewGroup { private RCTCameraViewFinder _viewFinder = null; private int _actualDeviceOrientation = -1; private int _aspect = RCTCameraModule.RCT_CAMERA_ASPECT_FIT; + private String _captureQuality = "high"; private int _torchMode = -1; private int _flashMode = -1; @@ -66,6 +67,13 @@ public class RCTCameraView extends ViewGroup { } } + public void setCaptureQuality(String captureQuality) { + this._captureQuality = captureQuality; + if (this._viewFinder != null) { + this._viewFinder.setCaptureQuality(captureQuality); + } + } + public void setTorchMode(int torchMode) { this._torchMode = torchMode; if (this._viewFinder != null) { diff --git a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewFinder.java b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewFinder.java index 4017c48..8fa2077 100644 --- a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewFinder.java +++ b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewFinder.java @@ -65,6 +65,10 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText }).start(); } + public void setCaptureQuality(String captureQuality) { + RCTCamera.getInstance().setCaptureQuality(_cameraType, captureQuality); + } + public void setTorchMode(int torchMode) { RCTCamera.getInstance().setTorchMode(_cameraType, torchMode); } @@ -91,10 +95,16 @@ class RCTCameraViewFinder extends TextureView implements TextureView.SurfaceText try { _camera = RCTCamera.getInstance().acquireCameraInstance(_cameraType); Camera.Parameters parameters = _camera.getParameters(); + // set autofocus List focusModes = parameters.getSupportedFocusModes(); if (focusModes.contains(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE)) { parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_CONTINUOUS_PICTURE); } + // set picture size + // defaults to max available size + Camera.Size optimalPictureSize = RCTCamera.getInstance().getBestPictureSize(_cameraType, Integer.MAX_VALUE, Integer.MAX_VALUE); + parameters.setPictureSize(optimalPictureSize.width, optimalPictureSize.height); + _camera.setParameters(parameters); _camera.setPreviewTexture(_surfaceTexture); _camera.startPreview(); diff --git a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewManager.java b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewManager.java index 4e9bfed..aaa5ea1 100644 --- a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewManager.java +++ b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraViewManager.java @@ -37,6 +37,11 @@ public class RCTCameraViewManager extends ViewGroupManager { view.setCameraType(type); } + @ReactProp(name = "captureQuality") + public void setCaptureQuality(RCTCameraView view, String captureQuality) { + view.setCaptureQuality(captureQuality); + } + @ReactProp(name = "torchMode") public void setTorchMode(RCTCameraView view, int torchMode) { view.setTorchMode(torchMode); diff --git a/ios/RCTCameraManager.m b/ios/RCTCameraManager.m index feabc60..2e6423a 100644 --- a/ios/RCTCameraManager.m +++ b/ios/RCTCameraManager.m @@ -69,6 +69,15 @@ RCT_EXPORT_VIEW_PROPERTY(keepAwake, BOOL); @"still": @(RCTCameraCaptureModeStill), @"video": @(RCTCameraCaptureModeVideo) }, + @"CaptureQuality": @{ + @"low": AVCaptureSessionPresetLow, + @"AVCaptureSessionPresetLow": AVCaptureSessionPresetLow, + @"medium": AVCaptureSessionPresetMedium, + @"AVCaptureSessionPresetMedium": AVCaptureSessionPresetMedium, + @"high": AVCaptureSessionPresetHigh, + @"AVCaptureSessionPresetHigh": AVCaptureSessionPresetHigh, + @"AVCaptureSessionPresetPhoto": AVCaptureSessionPresetPhoto + }, @"CaptureTarget": @{ @"memory": @(RCTCameraCaptureTargetMemory), @"disk": @(RCTCameraCaptureTargetDisk), @@ -136,7 +145,6 @@ RCT_EXPORT_VIEW_PROPERTY(onZoomChanged, BOOL) if ((self = [super init])) { self.session = [AVCaptureSession new]; - self.session.sessionPreset = AVCaptureSessionPresetHigh; self.previewLayer = [AVCaptureVideoPreviewLayer layerWithSession:self.session]; self.previewLayer.needsDisplayOnBoundsChange = YES; @@ -257,6 +265,8 @@ RCT_EXPORT_METHOD(capture:(NSDictionary *)options NSInteger captureMode = [[options valueForKey:@"mode"] intValue]; NSInteger captureTarget = [[options valueForKey:@"target"] intValue]; + [self setCaptureQuality:[options valueForKey:@"quality"]]; + if (captureMode == RCTCameraCaptureModeStill) { [self captureStill:captureTarget options:options resolve:resolve reject:reject]; } @@ -842,4 +852,15 @@ didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL } } +- (void)setCaptureQuality:(NSString *)quality +{ + if (quality) { + [self.session beginConfiguration]; + if ([self.session canSetSessionPreset:quality]) { + self.session.sessionPreset = quality; + } + [self.session commitConfiguration]; + } +} + @end