fix(ios): wrap captureStillImageAsynchronouslyFromConnection with try/catch (#2056)
* wrap captureStillImageAsynchronouslyFromConnection with try/catch the diff may look pretty big but the only change made here is try/catch block added for captureStillImageAsynchronouslyFromConnection call. For some reason, this method may throw an exception saying about inconsistent state. * make sure null in cameraHandle isn't passed to Native code
This commit is contained in:
parent
90225a96f0
commit
adac26f5cf
@ -378,93 +378,102 @@ static NSDictionary *defaultFaceDetectorOptions = nil;
|
||||
|
||||
AVCaptureConnection *connection = [self.stillImageOutput connectionWithMediaType:AVMediaTypeVideo];
|
||||
[connection setVideoOrientation:orientation];
|
||||
[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
|
||||
if (imageSampleBuffer && !error) {
|
||||
if ([options[@"pauseAfterCapture"] boolValue]) {
|
||||
[[self.previewLayer connection] setEnabled:NO];
|
||||
}
|
||||
|
||||
BOOL useFastMode = [options valueForKey:@"fastMode"] != nil && [options[@"fastMode"] boolValue];
|
||||
if (useFastMode) {
|
||||
resolve(nil);
|
||||
}
|
||||
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
|
||||
|
||||
UIImage *takenImage = [UIImage imageWithData:imageData];
|
||||
|
||||
CGImageRef takenCGImage = takenImage.CGImage;
|
||||
CGSize previewSize;
|
||||
if (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])) {
|
||||
previewSize = CGSizeMake(self.previewLayer.frame.size.height, self.previewLayer.frame.size.width);
|
||||
} else {
|
||||
previewSize = CGSizeMake(self.previewLayer.frame.size.width, self.previewLayer.frame.size.height);
|
||||
}
|
||||
CGRect cropRect = CGRectMake(0, 0, CGImageGetWidth(takenCGImage), CGImageGetHeight(takenCGImage));
|
||||
CGRect croppedSize = AVMakeRectWithAspectRatioInsideRect(previewSize, cropRect);
|
||||
takenImage = [RNImageUtils cropImage:takenImage toRect:croppedSize];
|
||||
|
||||
if ([options[@"mirrorImage"] boolValue]) {
|
||||
takenImage = [RNImageUtils mirrorImage:takenImage];
|
||||
}
|
||||
if ([options[@"forceUpOrientation"] boolValue]) {
|
||||
takenImage = [RNImageUtils forceUpOrientation:takenImage];
|
||||
}
|
||||
|
||||
if ([options[@"width"] integerValue]) {
|
||||
takenImage = [RNImageUtils scaleImage:takenImage toWidth:[options[@"width"] integerValue]];
|
||||
}
|
||||
|
||||
NSMutableDictionary *response = [[NSMutableDictionary alloc] init];
|
||||
float quality = [options[@"quality"] floatValue];
|
||||
NSData *takenImageData = UIImageJPEGRepresentation(takenImage, quality);
|
||||
NSString *path = [RNFileSystem generatePathInDirectory:[[RNFileSystem cacheDirectoryPath] stringByAppendingPathComponent:@"Camera"] withExtension:@".jpg"];
|
||||
if (![options[@"doNotSave"] boolValue]) {
|
||||
response[@"uri"] = [RNImageUtils writeImage:takenImageData toPath:path];
|
||||
}
|
||||
response[@"width"] = @(takenImage.size.width);
|
||||
response[@"height"] = @(takenImage.size.height);
|
||||
|
||||
if ([options[@"base64"] boolValue]) {
|
||||
response[@"base64"] = [takenImageData base64EncodedStringWithOptions:0];
|
||||
}
|
||||
|
||||
if ([options[@"exif"] boolValue]) {
|
||||
int imageRotation;
|
||||
switch (takenImage.imageOrientation) {
|
||||
case UIImageOrientationLeft:
|
||||
case UIImageOrientationRightMirrored:
|
||||
imageRotation = 90;
|
||||
break;
|
||||
case UIImageOrientationRight:
|
||||
case UIImageOrientationLeftMirrored:
|
||||
imageRotation = -90;
|
||||
break;
|
||||
case UIImageOrientationDown:
|
||||
case UIImageOrientationDownMirrored:
|
||||
imageRotation = 180;
|
||||
break;
|
||||
case UIImageOrientationUpMirrored:
|
||||
default:
|
||||
imageRotation = 0;
|
||||
break;
|
||||
@try {
|
||||
[self.stillImageOutput captureStillImageAsynchronouslyFromConnection:connection completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) {
|
||||
if (imageSampleBuffer && !error) {
|
||||
if ([options[@"pauseAfterCapture"] boolValue]) {
|
||||
[[self.previewLayer connection] setEnabled:NO];
|
||||
}
|
||||
|
||||
BOOL useFastMode = [options valueForKey:@"fastMode"] != nil && [options[@"fastMode"] boolValue];
|
||||
if (useFastMode) {
|
||||
resolve(nil);
|
||||
}
|
||||
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer];
|
||||
|
||||
UIImage *takenImage = [UIImage imageWithData:imageData];
|
||||
|
||||
CGImageRef takenCGImage = takenImage.CGImage;
|
||||
CGSize previewSize;
|
||||
if (UIInterfaceOrientationIsPortrait([[UIApplication sharedApplication] statusBarOrientation])) {
|
||||
previewSize = CGSizeMake(self.previewLayer.frame.size.height, self.previewLayer.frame.size.width);
|
||||
} else {
|
||||
previewSize = CGSizeMake(self.previewLayer.frame.size.width, self.previewLayer.frame.size.height);
|
||||
}
|
||||
CGRect cropRect = CGRectMake(0, 0, CGImageGetWidth(takenCGImage), CGImageGetHeight(takenCGImage));
|
||||
CGRect croppedSize = AVMakeRectWithAspectRatioInsideRect(previewSize, cropRect);
|
||||
takenImage = [RNImageUtils cropImage:takenImage toRect:croppedSize];
|
||||
|
||||
if ([options[@"mirrorImage"] boolValue]) {
|
||||
takenImage = [RNImageUtils mirrorImage:takenImage];
|
||||
}
|
||||
if ([options[@"forceUpOrientation"] boolValue]) {
|
||||
takenImage = [RNImageUtils forceUpOrientation:takenImage];
|
||||
}
|
||||
|
||||
if ([options[@"width"] integerValue]) {
|
||||
takenImage = [RNImageUtils scaleImage:takenImage toWidth:[options[@"width"] integerValue]];
|
||||
}
|
||||
|
||||
NSMutableDictionary *response = [[NSMutableDictionary alloc] init];
|
||||
float quality = [options[@"quality"] floatValue];
|
||||
NSData *takenImageData = UIImageJPEGRepresentation(takenImage, quality);
|
||||
NSString *path = [RNFileSystem generatePathInDirectory:[[RNFileSystem cacheDirectoryPath] stringByAppendingPathComponent:@"Camera"] withExtension:@".jpg"];
|
||||
if (![options[@"doNotSave"] boolValue]) {
|
||||
response[@"uri"] = [RNImageUtils writeImage:takenImageData toPath:path];
|
||||
}
|
||||
response[@"width"] = @(takenImage.size.width);
|
||||
response[@"height"] = @(takenImage.size.height);
|
||||
|
||||
if ([options[@"base64"] boolValue]) {
|
||||
response[@"base64"] = [takenImageData base64EncodedStringWithOptions:0];
|
||||
}
|
||||
|
||||
if ([options[@"exif"] boolValue]) {
|
||||
int imageRotation;
|
||||
switch (takenImage.imageOrientation) {
|
||||
case UIImageOrientationLeft:
|
||||
case UIImageOrientationRightMirrored:
|
||||
imageRotation = 90;
|
||||
break;
|
||||
case UIImageOrientationRight:
|
||||
case UIImageOrientationLeftMirrored:
|
||||
imageRotation = -90;
|
||||
break;
|
||||
case UIImageOrientationDown:
|
||||
case UIImageOrientationDownMirrored:
|
||||
imageRotation = 180;
|
||||
break;
|
||||
case UIImageOrientationUpMirrored:
|
||||
default:
|
||||
imageRotation = 0;
|
||||
break;
|
||||
}
|
||||
[RNImageUtils updatePhotoMetadata:imageSampleBuffer withAdditionalData:@{ @"Orientation": @(imageRotation) } inResponse:response]; // TODO
|
||||
}
|
||||
|
||||
response[@"pictureOrientation"] = @([self.orientation integerValue]);
|
||||
response[@"deviceOrientation"] = @([self.deviceOrientation integerValue]);
|
||||
self.orientation = nil;
|
||||
self.deviceOrientation = nil;
|
||||
|
||||
if (useFastMode) {
|
||||
[self onPictureSaved:@{@"data": response, @"id": options[@"id"]}];
|
||||
} else {
|
||||
resolve(response);
|
||||
}
|
||||
[RNImageUtils updatePhotoMetadata:imageSampleBuffer withAdditionalData:@{ @"Orientation": @(imageRotation) } inResponse:response]; // TODO
|
||||
}
|
||||
|
||||
response[@"pictureOrientation"] = @([self.orientation integerValue]);
|
||||
response[@"deviceOrientation"] = @([self.deviceOrientation integerValue]);
|
||||
self.orientation = nil;
|
||||
self.deviceOrientation = nil;
|
||||
|
||||
if (useFastMode) {
|
||||
[self onPictureSaved:@{@"data": response, @"id": options[@"id"]}];
|
||||
} else {
|
||||
resolve(response);
|
||||
reject(@"E_IMAGE_CAPTURE_FAILED", @"Image could not be captured", error);
|
||||
}
|
||||
} else {
|
||||
reject(@"E_IMAGE_CAPTURE_FAILED", @"Image could not be captured", error);
|
||||
}
|
||||
}];
|
||||
}];
|
||||
} @catch (NSException *exception) {
|
||||
reject(
|
||||
@"E_IMAGE_CAPTURE_FAILED",
|
||||
@"Got exception while taking picture",
|
||||
[NSError errorWithDomain:@"E_IMAGE_CAPTURE_FAILED" code: 500 userInfo:@{NSLocalizedDescriptionKey:exception.reason}]
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
- (void)recordWithOrientation:(NSDictionary *)options resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject{
|
||||
[self.sensorOrientationChecker getDeviceOrientationWithBlock:^(UIInterfaceOrientation orientation) {
|
||||
|
||||
@ -492,6 +492,10 @@ export default class Camera extends React.Component<PropsType, StateType> {
|
||||
options.pauseAfterCapture = false;
|
||||
}
|
||||
|
||||
if (!this._cameraHandle) {
|
||||
throw 'Camera handle cannot be null';
|
||||
}
|
||||
|
||||
return await CameraManager.takePicture(options, this._cameraHandle);
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user