From b67619380e6f565e456c112729e7391507f56cc6 Mon Sep 17 00:00:00 2001 From: Andhieka Putra Date: Tue, 2 Jun 2020 16:56:16 +0800 Subject: [PATCH 1/3] Add option to take picture without rotation --- .../io/flutter/plugins/camera/Camera.java | 5 +-- .../plugins/camera/MethodCallHandlerImpl.java | 2 +- packages/camera/example/lib/main.dart | 11 ++++++- packages/camera/ios/Classes/CameraPlugin.m | 31 +++++++++++++++---- packages/camera/lib/camera.dart | 8 +++-- 5 files changed, 45 insertions(+), 12 deletions(-) diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 0fcda278d836..d5202ef6b0fe 100644 --- a/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -223,7 +223,7 @@ SurfaceTextureEntry getFlutterTexture() { return flutterTexture; } - public void takePicture(String filePath, @NonNull final Result result) { + public void takePicture(String filePath, boolean shouldAutoRotate, @NonNull final Result result) { final File file = new File(filePath); if (file.exists()) { @@ -248,7 +248,8 @@ public void takePicture(String filePath, @NonNull final Result result) { final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(pictureImageReader.getSurface()); - captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, getMediaOrientation()); + int mediaOrientation = shouldAutoRotate ? getMediaOrientation() : 0; + captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mediaOrientation); cameraCaptureSession.capture( captureBuilder.build(), diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java b/packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java index cb58d19a9a02..e5dcc4fd50ce 100644 --- a/packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java +++ b/packages/camera/android/src/main/java/io/flutter/plugins/camera/MethodCallHandlerImpl.java @@ -74,7 +74,7 @@ public void onMethodCall(@NonNull MethodCall call, @NonNull final Result result) } case "takePicture": { - camera.takePicture(call.argument("path"), result); + camera.takePicture(call.argument("path"), call.argument("shouldAutoRotate"), result); break; } case "prepareForVideoRecording": diff --git a/packages/camera/example/lib/main.dart b/packages/camera/example/lib/main.dart index ce8d37457123..1ea099a7e8e1 100644 --- a/packages/camera/example/lib/main.dart +++ b/packages/camera/example/lib/main.dart @@ -43,6 +43,7 @@ class _CameraExampleHomeState extends State VideoPlayerController videoController; VoidCallback videoPlayerListener; bool enableAudio = true; + bool enableAutoRotate = true; @override void initState() { @@ -153,6 +154,14 @@ class _CameraExampleHomeState extends State } }, ), + const Text('Enable Auto Rotate:'), + Switch( + value: enableAutoRotate, + onChanged: (bool value) { + enableAutoRotate = value; + onNewCameraSelected(controller.description); + }, + ), ], ), ); @@ -451,7 +460,7 @@ class _CameraExampleHomeState extends State } try { - await controller.takePicture(filePath); + await controller.takePicture(filePath, shouldAutoRotate: enableAutoRotate); } on CameraException catch (e) { _showCameraException(e); return null; diff --git a/packages/camera/ios/Classes/CameraPlugin.m b/packages/camera/ios/Classes/CameraPlugin.m index 42cdb6d5fdf9..650e04440323 100644 --- a/packages/camera/ios/Classes/CameraPlugin.m +++ b/packages/camera/ios/Classes/CameraPlugin.m @@ -19,11 +19,13 @@ @interface FLTSavePhotoDelegate : NSObject @property(readonly, nonatomic) FlutterResult result; @property(readonly, nonatomic) CMMotionManager *motionManager; @property(readonly, nonatomic) AVCaptureDevicePosition cameraPosition; +@property(assign, nonatomic) BOOL shouldAutoRotate; - initWithPath:(NSString *)filename result:(FlutterResult)result motionManager:(CMMotionManager *)motionManager - cameraPosition:(AVCaptureDevicePosition)cameraPosition; + cameraPosition:(AVCaptureDevicePosition)cameraPosition + shouldAutoRotate:(BOOL)shouldAutoRotate; @end @interface FLTImageStreamHandler : NSObject @@ -52,13 +54,15 @@ @implementation FLTSavePhotoDelegate { - initWithPath:(NSString *)path result:(FlutterResult)result motionManager:(CMMotionManager *)motionManager - cameraPosition:(AVCaptureDevicePosition)cameraPosition { + cameraPosition:(AVCaptureDevicePosition)cameraPosition + shouldAutoRotate:(BOOL)shouldAutoRotate { self = [super init]; NSAssert(self, @"super init cannot be nil"); _path = path; _result = result; _motionManager = motionManager; _cameraPosition = cameraPosition; + _shouldAutoRotate = shouldAutoRotate; selfReference = self; return self; } @@ -90,6 +94,9 @@ - (void)captureOutput:(AVCapturePhotoOutput *)output } - (UIImageOrientation)getImageRotation { + if (!self.shouldAutoRotate) { + return UIImageOrientationRight; + } float const threshold = 45.0; BOOL (^isNearValue)(float value1, float value2) = ^BOOL(float value1, float value2) { return fabsf(value1 - value2) < threshold; @@ -204,7 +211,13 @@ - (void)startVideoRecordingAtPath:(NSString *)path result:(FlutterResult)result; - (void)stopVideoRecordingWithResult:(FlutterResult)result; - (void)startImageStreamWithMessenger:(NSObject *)messenger; - (void)stopImageStream; -- (void)captureToFile:(NSString *)filename result:(FlutterResult)result; +/// Captures a photo and save to the specified file path. +/// @param filename The path where the photo should be saved to. +/// @param shouldAutoRotate Whether to automatically rotate the captured photo. +/// If enabled, Saves the EXIF data according to device accelerometer. +- (void)captureToFile:(NSString *)path + shouldAutoRotate:(BOOL)shouldAutoRotate + result:(FlutterResult)result; @end @implementation FLTCam { @@ -272,7 +285,9 @@ - (void)stop { [_captureSession stopRunning]; } -- (void)captureToFile:(NSString *)path result:(FlutterResult)result { +- (void)captureToFile:(NSString *)path + shouldAutoRotate:(BOOL)shouldAutoRotate + result:(FlutterResult)result { AVCapturePhotoSettings *settings = [AVCapturePhotoSettings photoSettings]; if (_resolutionPreset == max) { [settings setHighResolutionPhotoEnabled:YES]; @@ -282,7 +297,8 @@ - (void)captureToFile:(NSString *)path result:(FlutterResult)result { delegate:[[FLTSavePhotoDelegate alloc] initWithPath:path result:result motionManager:_motionManager - cameraPosition:_captureDevice.position]]; + cameraPosition:_captureDevice.position + shouldAutoRotate:shouldAutoRotate]]; } - (void)setCaptureSessionPreset:(ResolutionPreset)resolutionPreset { @@ -882,7 +898,10 @@ - (void)handleMethodCallAsync:(FlutterMethodCall *)call result:(FlutterResult)re NSUInteger textureId = ((NSNumber *)argsMap[@"textureId"]).unsignedIntegerValue; if ([@"takePicture" isEqualToString:call.method]) { - [_camera captureToFile:call.arguments[@"path"] result:result]; + BOOL shouldAutoRotate = [call.arguments[@"shouldAutoRotate"] boolValue]; + [_camera captureToFile:call.arguments[@"path"] + shouldAutoRotate:shouldAutoRotate + result:result]; } else if ([@"dispose" isEqualToString:call.method]) { [_registry unregisterTexture:textureId]; [_camera close]; diff --git a/packages/camera/lib/camera.dart b/packages/camera/lib/camera.dart index ce9fd9430dde..e220e6076c61 100644 --- a/packages/camera/lib/camera.dart +++ b/packages/camera/lib/camera.dart @@ -339,7 +339,7 @@ class CameraController extends ValueNotifier { /// The file can be read as this function returns. /// /// Throws a [CameraException] if the capture fails. - Future takePicture(String path) async { + Future takePicture(String path, {bool shouldAutoRotate = false}) async { if (!value.isInitialized || _isDisposed) { throw CameraException( 'Uninitialized CameraController.', @@ -356,7 +356,11 @@ class CameraController extends ValueNotifier { value = value.copyWith(isTakingPicture: true); await _channel.invokeMethod( 'takePicture', - {'textureId': _textureId, 'path': path}, + { + 'textureId': _textureId, + 'path': path, + 'shouldAutoRotate': shouldAutoRotate, + }, ); value = value.copyWith(isTakingPicture: false); } on PlatformException catch (e) { From e494a4f6746009e5e42d80a7142c9c6bad75b94d Mon Sep 17 00:00:00 2001 From: Vivaldi Ibelio Chandra Date: Wed, 3 Jun 2020 14:04:31 +0800 Subject: [PATCH 2/3] Recalibrate android's media orientation to 90. --- .../android/src/main/java/io/flutter/plugins/camera/Camera.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index d5202ef6b0fe..5d1427d86895 100644 --- a/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -248,7 +248,7 @@ public void takePicture(String filePath, boolean shouldAutoRotate, @NonNull fina final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(pictureImageReader.getSurface()); - int mediaOrientation = shouldAutoRotate ? getMediaOrientation() : 0; + int mediaOrientation = shouldAutoRotate ? getMediaOrientation() : 90; captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mediaOrientation); cameraCaptureSession.capture( From 8bb67c52446ed667db0a062ae47e009281960edd Mon Sep 17 00:00:00 2001 From: Andhieka Putra Date: Wed, 15 Jul 2020 13:31:07 +0800 Subject: [PATCH 3/3] Invert picture rotation when using front camera --- .../src/main/java/io/flutter/plugins/camera/Camera.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java b/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java index 5d1427d86895..abb8cb2a9a55 100644 --- a/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java +++ b/packages/camera/android/src/main/java/io/flutter/plugins/camera/Camera.java @@ -248,7 +248,9 @@ public void takePicture(String filePath, boolean shouldAutoRotate, @NonNull fina final CaptureRequest.Builder captureBuilder = cameraDevice.createCaptureRequest(CameraDevice.TEMPLATE_STILL_CAPTURE); captureBuilder.addTarget(pictureImageReader.getSurface()); - int mediaOrientation = shouldAutoRotate ? getMediaOrientation() : 90; + int mediaOrientation = shouldAutoRotate + ? getMediaOrientation() + : (isFrontFacing ? -90 : 90); captureBuilder.set(CaptureRequest.JPEG_ORIENTATION, mediaOrientation); cameraCaptureSession.capture(