From 6555f9bee865af03a4db09beb9216b8b61e182b8 Mon Sep 17 00:00:00 2001 From: Aleksei Androsov Date: Mon, 24 Jul 2017 21:39:02 -0700 Subject: [PATCH] Fix photo orientation from ImagePickerIOS Summary: Original PR: https://github.com/facebook/react-native/pull/12249 ImagePickerIOS saves photos to ImageStoreManager without meta information. So photo has wrong orientation. **Test plan** 1. Take the 2 photos (in landspape and portrait orientation) with this code: ``` ImagePickerIOS.openCameraDialog( {}, (uri) => CameraRoll.saveToCameraRoll(uri), () => {} ); ``` 2. Ensure that photos in Photos app have right orientation. Closes https://github.com/facebook/react-native/pull/15060 Differential Revision: D5487595 Pulled By: shergin fbshipit-source-id: ce1a47f4d5ba33e03070f318f3d6a8dd0df5ab88 --- Libraries/Image/RCTImageStoreManager.m | 4 ++-- Libraries/Image/RCTImageUtils.h | 2 +- Libraries/Image/RCTImageUtils.m | 29 +++++++++++++++++++++----- 3 files changed, 27 insertions(+), 8 deletions(-) diff --git a/Libraries/Image/RCTImageStoreManager.m b/Libraries/Image/RCTImageStoreManager.m index 7df7a3a39..9d89ca0f4 100644 --- a/Libraries/Image/RCTImageStoreManager.m +++ b/Libraries/Image/RCTImageStoreManager.m @@ -76,7 +76,7 @@ RCT_EXPORT_MODULE() { RCTAssertParam(block); dispatch_async(_methodQueue, ^{ - NSString *imageTag = [self _storeImageData:RCTGetImageData(image.CGImage, 0.75)]; + NSString *imageTag = [self _storeImageData:RCTGetImageData(image, 0.75)]; dispatch_async(dispatch_get_main_queue(), ^{ block(imageTag); }); @@ -197,7 +197,7 @@ RCT_EXPORT_METHOD(addImageFromBase64:(NSString *)base64String RCTLogWarn(@"RCTImageStoreManager.storeImage() is deprecated and has poor performance. Use an alternative method instead."); __block NSString *imageTag; dispatch_sync(_methodQueue, ^{ - imageTag = [self _storeImageData:RCTGetImageData(image.CGImage, 0.75)]; + imageTag = [self _storeImageData:RCTGetImageData(image, 0.75)]; }); return imageTag; } diff --git a/Libraries/Image/RCTImageUtils.h b/Libraries/Image/RCTImageUtils.h index 5012a66d2..371770cb1 100644 --- a/Libraries/Image/RCTImageUtils.h +++ b/Libraries/Image/RCTImageUtils.h @@ -76,7 +76,7 @@ RCT_EXTERN NSDictionary *__nullable RCTGetImageMetadata(NSData * * conversion, with 1.0 being maximum quality. It has no effect for images * using PNG compression. */ -RCT_EXTERN NSData *__nullable RCTGetImageData(CGImageRef image, float quality); +RCT_EXTERN NSData *__nullable RCTGetImageData(UIImage *image, float quality); /** * This function transforms an image. `destSize` is the size of the final image, diff --git a/Libraries/Image/RCTImageUtils.m b/Libraries/Image/RCTImageUtils.m index 1fdf11e90..f64f1f7b6 100644 --- a/Libraries/Image/RCTImageUtils.m +++ b/Libraries/Image/RCTImageUtils.m @@ -35,6 +35,22 @@ static CGSize RCTCeilSize(CGSize size, CGFloat scale) }; } +static CGImagePropertyOrientation CGImagePropertyOrientationFromUIImageOrientation(UIImageOrientation imageOrientation) +{ + // see https://stackoverflow.com/a/6699649/496389 + switch (imageOrientation) { + case UIImageOrientationUp: return kCGImagePropertyOrientationUp; + case UIImageOrientationDown: return kCGImagePropertyOrientationDown; + case UIImageOrientationLeft: return kCGImagePropertyOrientationLeft; + case UIImageOrientationRight: return kCGImagePropertyOrientationRight; + case UIImageOrientationUpMirrored: return kCGImagePropertyOrientationUpMirrored; + case UIImageOrientationDownMirrored: return kCGImagePropertyOrientationDownMirrored; + case UIImageOrientationLeftMirrored: return kCGImagePropertyOrientationLeftMirrored; + case UIImageOrientationRightMirrored: return kCGImagePropertyOrientationRightMirrored; + default: return kCGImagePropertyOrientationUp; + } +} + CGRect RCTTargetRect(CGSize sourceSize, CGSize destSize, CGFloat destScale, RCTResizeMode resizeMode) { @@ -314,20 +330,23 @@ NSDictionary *__nullable RCTGetImageMetadata(NSData *data) return (__bridge_transfer id)imageProperties; } -NSData *__nullable RCTGetImageData(CGImageRef image, float quality) +NSData *__nullable RCTGetImageData(UIImage *image, float quality) { - NSDictionary *properties; + NSMutableDictionary *properties = [[NSMutableDictionary alloc] initWithDictionary:@{ + (id)kCGImagePropertyOrientation : @(CGImagePropertyOrientationFromUIImageOrientation(image.imageOrientation)) + }]; CGImageDestinationRef destination; CFMutableDataRef imageData = CFDataCreateMutable(NULL, 0); - if (RCTImageHasAlpha(image)) { + CGImageRef cgImage = image.CGImage; + if (RCTImageHasAlpha(cgImage)) { // get png data destination = CGImageDestinationCreateWithData(imageData, kUTTypePNG, 1, NULL); } else { // get jpeg data destination = CGImageDestinationCreateWithData(imageData, kUTTypeJPEG, 1, NULL); - properties = @{(NSString *)kCGImageDestinationLossyCompressionQuality: @(quality)}; + [properties setValue:@(quality) forKey:(id)kCGImageDestinationLossyCompressionQuality]; } - CGImageDestinationAddImage(destination, image, (__bridge CFDictionaryRef)properties); + CGImageDestinationAddImage(destination, cgImage, (__bridge CFDictionaryRef)properties); if (!CGImageDestinationFinalize(destination)) { CFRelease(imageData);