diff --git a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCamera.java b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCamera.java index 44322e3..acc1070 100644 --- a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCamera.java +++ b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCamera.java @@ -132,6 +132,10 @@ public class RCTCamera { return result; } + public int getOrientation() { + return _orientation; + } + public void setOrientation(int orientation) { if (_orientation == orientation) { return; diff --git a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraModule.java b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraModule.java index 02778ab..19b3f44 100644 --- a/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraModule.java +++ b/android/src/main/java/com/lwansbrough/RCTCamera/RCTCameraModule.java @@ -13,6 +13,7 @@ import android.os.Environment; import android.provider.MediaStore; import android.util.Base64; import android.util.Log; +import android.view.Surface; import com.facebook.react.bridge.*; import javax.annotation.Nullable; @@ -36,11 +37,11 @@ public class RCTCameraModule extends ReactContextBaseJavaModule { public static final int RCT_CAMERA_CAPTURE_TARGET_DISK = 1; public static final int RCT_CAMERA_CAPTURE_TARGET_CAMERA_ROLL = 2; public static final int RCT_CAMERA_CAPTURE_TARGET_TEMP = 3; - public static final int RCT_CAMERA_ORIENTATION_AUTO = 0; - public static final int RCT_CAMERA_ORIENTATION_LANDSCAPE_LEFT = 1; - public static final int RCT_CAMERA_ORIENTATION_LANDSCAPE_RIGHT = 2; - public static final int RCT_CAMERA_ORIENTATION_PORTRAIT = 3; - public static final int RCT_CAMERA_ORIENTATION_PORTRAIT_UPSIDE_DOWN = 4; + public static final int RCT_CAMERA_ORIENTATION_AUTO = Integer.MAX_VALUE; + public static final int RCT_CAMERA_ORIENTATION_PORTRAIT = Surface.ROTATION_0; + public static final int RCT_CAMERA_ORIENTATION_PORTRAIT_UPSIDE_DOWN = Surface.ROTATION_180; + public static final int RCT_CAMERA_ORIENTATION_LANDSCAPE_LEFT = Surface.ROTATION_90; + public static final int RCT_CAMERA_ORIENTATION_LANDSCAPE_RIGHT = Surface.ROTATION_270; public static final int RCT_CAMERA_TYPE_FRONT = 1; public static final int RCT_CAMERA_TYPE_BACK = 2; public static final int RCT_CAMERA_FLASH_MODE_OFF = 0; @@ -176,16 +177,21 @@ public class RCTCameraModule extends ReactContextBaseJavaModule { @ReactMethod public void capture(final ReadableMap options, final Promise promise) { - _sensorOrientationChecker.onResume(); - _sensorOrientationChecker.registerOrientationListener(new RCTSensorOrientationListener() { - @Override - public void orientationEvent() { - int deviceOrientation = _sensorOrientationChecker.getOrientation(); - _sensorOrientationChecker.unregisterOrientationListener(); - _sensorOrientationChecker.onPause(); - captureWithOrientation(options, promise, deviceOrientation); - } - }); + int orientation = options.hasKey("orientation") ? options.getInt("orientation") : RCTCamera.getInstance().getOrientation(); + if (orientation == RCT_CAMERA_ORIENTATION_AUTO) { + _sensorOrientationChecker.onResume(); + _sensorOrientationChecker.registerOrientationListener(new RCTSensorOrientationListener() { + @Override + public void orientationEvent() { + int deviceOrientation = _sensorOrientationChecker.getOrientation(); + _sensorOrientationChecker.unregisterOrientationListener(); + _sensorOrientationChecker.onPause(); + captureWithOrientation(options, promise, deviceOrientation); + } + }); + } else { + captureWithOrientation(options, promise, orientation); + } } public void captureWithOrientation(final ReadableMap options, final Promise promise, int deviceOrientation) { @@ -195,8 +201,16 @@ public class RCTCameraModule extends ReactContextBaseJavaModule { return; } + if (options.hasKey("playSoundOnCapture") && options.getBoolean("playSoundOnCapture")) { + MediaActionSound sound = new MediaActionSound(); + sound.play(MediaActionSound.SHUTTER_CLICK); + } + + if (options.hasKey("quality")) { + RCTCamera.getInstance().setCaptureQuality(options.getInt("type"), options.getString("quality")); + } + RCTCamera.getInstance().adjustCameraRotationToDeviceOrientation(options.getInt("type"), deviceOrientation); - 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/RCTSensorOrientationChecker.java b/android/src/main/java/com/lwansbrough/RCTCamera/RCTSensorOrientationChecker.java index c2aadfb..0f57dc8 100644 --- a/android/src/main/java/com/lwansbrough/RCTCamera/RCTSensorOrientationChecker.java +++ b/android/src/main/java/com/lwansbrough/RCTCamera/RCTSensorOrientationChecker.java @@ -9,6 +9,7 @@ import android.hardware.Sensor; import android.hardware.SensorEvent; import android.hardware.SensorEventListener; import android.hardware.SensorManager; +import android.view.Surface; import com.facebook.react.bridge.ReactApplicationContext; @@ -51,13 +52,13 @@ public class RCTSensorOrientationChecker { float y = event.values[1]; if (x<5 && x>-5 && y > 5) - mOrientation = 0; + mOrientation = Surface.ROTATION_0; // portrait else if (x<-5 && y<5 && y>-5) - mOrientation = 3; + mOrientation = Surface.ROTATION_270; // right else if (x<5 && x>-5 && y<-5) - mOrientation = 2; + mOrientation = Surface.ROTATION_180; // upside down else if (x>5 && y<5 && y>-5) - mOrientation = 1; + mOrientation = Surface.ROTATION_90; // left if (mListener != null) { mListener.orientationEvent(); diff --git a/ios/RCTCamera.m b/ios/RCTCamera.m index 84bc33e..74579c4 100644 --- a/ios/RCTCamera.m +++ b/ios/RCTCamera.m @@ -29,13 +29,15 @@ - (void)setOrientation:(NSInteger)orientation { + [self.manager changeOrientation:orientation]; + if (orientation == RCTCameraOrientationAuto) { - [self.manager changeOrientation:[UIApplication sharedApplication].statusBarOrientation]; + [self changePreviewOrientation:[UIApplication sharedApplication].statusBarOrientation]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil]; } else { [[NSNotificationCenter defaultCenter]removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil]; - [self.manager changeOrientation:orientation]; + [self changePreviewOrientation:orientation]; } } @@ -109,7 +111,7 @@ - (void)orientationChanged:(NSNotification *)notification{ UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation]; - [self.manager changeOrientation:orientation]; + [self changePreviewOrientation:orientation]; } @@ -177,5 +179,11 @@ } } +- (void)changePreviewOrientation:(NSInteger)orientation +{ + if (self.manager.previewLayer.connection.isVideoOrientationSupported) { + self.manager.previewLayer.connection.videoOrientation = orientation; + } +} @end diff --git a/ios/RCTCameraManager.m b/ios/RCTCameraManager.m index 74a79df..f8856d7 100644 --- a/ios/RCTCameraManager.m +++ b/ios/RCTCameraManager.m @@ -303,9 +303,6 @@ RCT_EXPORT_METHOD(checkAudioAuthorizationStatus:(RCTPromiseResolveBlock)resolve RCT_EXPORT_METHOD(changeOrientation:(NSInteger)orientation) { [self setOrientation:orientation]; - if (self.previewLayer.connection.isVideoOrientationSupported) { - self.previewLayer.connection.videoOrientation = orientation; - } } RCT_EXPORT_METHOD(capture:(NSDictionary *)options @@ -408,7 +405,6 @@ RCT_EXPORT_METHOD(hasFlash:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRej }); }]]; - [self.previewLayer.connection setVideoOrientation:self.orientation]; [self.session startRunning]; }); } @@ -484,8 +480,20 @@ RCT_EXPORT_METHOD(hasFlash:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRej }); } +- (void)captureStill:(NSInteger)target options:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject +{ + AVCaptureVideoOrientation orientation = options[@"orientation"] != nil ? [options[@"orientation"] integerValue] : self.orientation; + if (orientation == RCTCameraOrientationAuto) { + [self.sensorOrientationChecker getDeviceOrientationWithBlock:^(UIInterfaceOrientation orientation) { + [self captureStill:target options:options orientation:[self.sensorOrientationChecker convertToAVCaptureVideoOrientation: orientation] resolve:resolve reject:reject]; + }]; + } else { + [self captureStill:target options:options orientation:orientation resolve:resolve reject:reject]; + } +} -- (void)captureStill:(NSInteger)target options:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +- (void)captureStill:(NSInteger)target options:(NSDictionary *)options orientation:(AVCaptureVideoOrientation)orientation resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject +{ dispatch_async(self.sessionQueue, ^{ #if TARGET_IPHONE_SIMULATOR CGSize size = CGSizeMake(720, 1280); @@ -513,8 +521,7 @@ RCT_EXPORT_METHOD(hasFlash:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRej NSData *imageData = UIImageJPEGRepresentation(image, 1.0); [self saveImage:imageData target:target metadata:nil resolve:resolve reject:reject]; #else - [self.sensorOrientationChecker getDeviceOrientationWithBlock:^(UIInterfaceOrientation orientation) { - [[self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[self.sensorOrientationChecker convertToAVCaptureVideoOrientation: orientation]]; + [[self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:orientation]; [self.stillImageOutput captureStillImageAsynchronouslyFromConnection:[self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo] completionHandler:^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) { @@ -577,7 +584,6 @@ RCT_EXPORT_METHOD(hasFlash:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRej reject(RCTErrorUnspecified, nil, RCTErrorWithMessage(error.description)); } }]; - }]; #endif }); } @@ -659,8 +665,20 @@ RCT_EXPORT_METHOD(hasFlash:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRej return rotatedImage; } --(void)captureVideo:(NSInteger)target options:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject { +-(void)captureVideo:(NSInteger)target options:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject +{ + AVCaptureVideoOrientation orientation = options[@"orientation"] != nil ? [options[@"orientation"] integerValue] : self.orientation; + if (orientation == RCTCameraOrientationAuto) { + [self.sensorOrientationChecker getDeviceOrientationWithBlock:^(UIInterfaceOrientation orientation) { + [self captureVideo:target options:options orientation:[self.sensorOrientationChecker convertToAVCaptureVideoOrientation: orientation] resolve:resolve reject:reject]; + }]; + } else { + [self captureVideo:target options:options orientation:orientation resolve:resolve reject:reject]; + } +} +-(void)captureVideo:(NSInteger)target options:(NSDictionary *)options orientation:(AVCaptureVideoOrientation)orientation resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject +{ if (self.movieFileOutput.recording) { reject(RCTErrorUnspecified, nil, RCTErrorWithMessage(@"Already recording")); return; @@ -678,18 +696,18 @@ RCT_EXPORT_METHOD(hasFlash:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRej } dispatch_async(self.sessionQueue, ^{ - [[self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:self.previewLayer.connection.videoOrientation]; + [[self.movieFileOutput connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:orientation]; //Create temporary URL to record to NSString *outputPath = [[NSString alloc] initWithFormat:@"%@%@", NSTemporaryDirectory(), @"output.mov"]; NSURL *outputURL = [[NSURL alloc] initFileURLWithPath:outputPath]; NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:outputPath]) { - NSError *error; - if ([fileManager removeItemAtPath:outputPath error:&error] == NO) { - reject(RCTErrorUnspecified, nil, RCTErrorWithMessage(error.description)); - return; - } + NSError *error; + if ([fileManager removeItemAtPath:outputPath error:&error] == NO) { + reject(RCTErrorUnspecified, nil, RCTErrorWithMessage(error.description)); + return; + } } //Start recording