Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions packages/image_picker/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
## 0.6.0+6

* iOS: Picked image now has all the correct meta data from the original image, includes GPS, orientation and etc.

## 0.6.0+5

* iOS: Add missing import.

## 0.6.0+4
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,31 +52,19 @@ - (void)testGetMetaData {
XCTAssertEqual([exif[(NSString *)kCGImagePropertyExifPixelXDimension] integerValue], 12);
}

- (void)testGetEXIFData {
NSData *dataJPG = [NSData dataWithContentsOfFile:[self.testBundle pathForResource:@"jpgImage"
ofType:@"jpg"]];
NSDictionary *exif = [ImagePickerMetaDataUtil getEXIFFromImageData:dataJPG];
XCTAssertNotNil(exif);
// hard coded test case based on the test image file saved in directory.
XCTAssertEqualObjects(exif[@"PixelXDimension"], @(12));
XCTAssertEqualObjects(exif[@"PixelYDimension"], @(7));
}

- (void)testWriteEXIFData {
- (void)testWriteMetaData {
NSData *dataJPG = [NSData dataWithContentsOfFile:[self.testBundle pathForResource:@"jpgImage"
ofType:@"jpg"]];
NSDictionary *metaData = [ImagePickerMetaDataUtil getMetaDataFromImageData:dataJPG];
NSDictionary *exif = [metaData objectForKey:(NSString *)kCGImagePropertyExifDictionary];
NSString *tmpFile = [NSString stringWithFormat:@"image_picker_test.jpg"];
NSString *tmpDirectory = NSTemporaryDirectory();
NSString *tmpPath = [tmpDirectory stringByAppendingPathComponent:tmpFile];
NSData *newData = [ImagePickerMetaDataUtil updateEXIFData:exif toImage:dataJPG];
NSData *newData = [ImagePickerMetaDataUtil updateMetaData:metaData toImage:dataJPG];
if ([[NSFileManager defaultManager] createFileAtPath:tmpPath contents:newData attributes:nil]) {
NSData *savedTmpImageData = [NSData dataWithContentsOfFile:tmpPath];
NSDictionary *tmpMetaData =
[ImagePickerMetaDataUtil getMetaDataFromImageData:savedTmpImageData];
NSDictionary *tmpExif = [tmpMetaData objectForKey:(NSString *)kCGImagePropertyExifDictionary];
XCTAssert([tmpExif isEqualToDictionary:exif]);
XCTAssert([tmpMetaData isEqualToDictionary:metaData]);
} else {
XCTAssert(NO);
}
Expand Down Expand Up @@ -104,4 +92,40 @@ - (void)testConvertImageToData {
quality:@(0.5)],
@"setting quality when converting to PNG throws exception");
}

- (void)testGetNormalizedUIImageOrientationFromCGImagePropertyOrientation {
XCTAssertEqual(
[ImagePickerMetaDataUtil getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
kCGImagePropertyOrientationUp],
UIImageOrientationUp);
XCTAssertEqual(
[ImagePickerMetaDataUtil getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
kCGImagePropertyOrientationDown],
UIImageOrientationDown);
XCTAssertEqual(
[ImagePickerMetaDataUtil getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
kCGImagePropertyOrientationLeft],
UIImageOrientationRight);
XCTAssertEqual(
[ImagePickerMetaDataUtil getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
kCGImagePropertyOrientationRight],
UIImageOrientationLeft);
XCTAssertEqual(
[ImagePickerMetaDataUtil getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
kCGImagePropertyOrientationUpMirrored],
UIImageOrientationUpMirrored);
XCTAssertEqual(
[ImagePickerMetaDataUtil getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
kCGImagePropertyOrientationDownMirrored],
UIImageOrientationDownMirrored);
XCTAssertEqual(
[ImagePickerMetaDataUtil getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
kCGImagePropertyOrientationLeftMirrored],
UIImageOrientationRightMirrored);
XCTAssertEqual(
[ImagePickerMetaDataUtil getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
kCGImagePropertyOrientationRightMirrored],
UIImageOrientationLeftMirrored);
}

@end
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,11 @@ - (void)testSaveImageWithOriginalImageData_ShouldSaveWithTheCorrectExtentionAndM
XCTAssertNotNil(savedPathJPG);
XCTAssertEqualObjects([savedPathJPG substringFromIndex:savedPathJPG.length - 4], @".jpg");

NSDictionary *originalMetaDataJPG = [ImagePickerMetaDataUtil getMetaDataFromImageData:dataJPG];
NSData *newDataJPG = [NSData dataWithContentsOfFile:savedPathJPG];
NSDictionary *newMetaDataJPG = [ImagePickerMetaDataUtil getMetaDataFromImageData:newDataJPG];
XCTAssertEqualObjects(originalMetaDataJPG[@"ProfileName"], newMetaDataJPG[@"ProfileName"]);

// test png
NSData *dataPNG = [NSData dataWithContentsOfFile:[self.testBundle pathForResource:@"pngImage"
ofType:@"png"]];
Expand All @@ -36,6 +41,11 @@ - (void)testSaveImageWithOriginalImageData_ShouldSaveWithTheCorrectExtentionAndM
image:imagePNG];
XCTAssertNotNil(savedPathPNG);
XCTAssertEqualObjects([savedPathPNG substringFromIndex:savedPathPNG.length - 4], @".png");

NSDictionary *originalMetaDataPNG = [ImagePickerMetaDataUtil getMetaDataFromImageData:dataPNG];
NSData *newDataPNG = [NSData dataWithContentsOfFile:savedPathPNG];
NSDictionary *newMetaDataPNG = [ImagePickerMetaDataUtil getMetaDataFromImageData:newDataPNG];
XCTAssertEqualObjects(originalMetaDataPNG[@"ProfileName"], newMetaDataPNG[@"ProfileName"]);
}

- (void)testSaveImageWithPickerInfo_ShouldSaveWithDefaultExtention {
Expand Down Expand Up @@ -63,8 +73,10 @@ - (void)testSaveImageWithPickerInfo_ShouldSaveWithTheCorrectExtentionAndMetaData
NSString *savedPathJPG = [ImagePickerPhotoAssetUtil saveImageWithPickerInfo:dummyInfo
image:imageJPG];
NSData *data = [NSData dataWithContentsOfFile:savedPathJPG];
NSDictionary *exif = [ImagePickerMetaDataUtil getEXIFFromImageData:data];
XCTAssertEqualObjects(exif[(__bridge NSString *)kCGImagePropertyExifMakerNote], @"aNote");
NSDictionary *meta = [ImagePickerMetaDataUtil getMetaDataFromImageData:data];
XCTAssertEqualObjects(meta[(__bridge NSString *)kCGImagePropertyExifDictionary]
[(__bridge NSString *)kCGImagePropertyExifMakerNote],
@"aNote");
}

@end
5 changes: 3 additions & 2 deletions packages/image_picker/ios/Classes/ImagePickerMetaDataUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ extern const FlutterImagePickerMIMEType kFlutterImagePickerMIMETypeDefault;

+ (NSDictionary *)getMetaDataFromImageData:(NSData *)imageData;

+ (NSDictionary *)getEXIFFromImageData:(NSData *)imageData;
+ (NSData *)updateMetaData:(NSDictionary *)metaData toImage:(NSData *)imageData;

+ (NSData *)updateEXIFData:(NSDictionary *)exifData toImage:(NSData *)imageData;
+ (UIImageOrientation)getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
(CGImagePropertyOrientation)cgImageOrientation;

// Converting UIImage to a NSData with the type proveide.
//
Expand Down
36 changes: 27 additions & 9 deletions packages/image_picker/ios/Classes/ImagePickerMetaDataUtil.m
Original file line number Diff line number Diff line change
Expand Up @@ -44,19 +44,12 @@ + (NSDictionary *)getMetaDataFromImageData:(NSData *)imageData {
return metadata;
}

+ (NSDictionary *)getEXIFFromImageData:(NSData *)imageData {
NSDictionary *metaData = [self getMetaDataFromImageData:imageData];
return metaData[(__bridge NSString *)kCGImagePropertyExifDictionary];
}

+ (NSData *)updateEXIFData:(NSDictionary *)exifData toImage:(NSData *)imageData {
+ (NSData *)updateMetaData:(NSDictionary *)metaData toImage:(NSData *)imageData {
NSMutableData *mutableData = [NSMutableData data];
CGImageSourceRef cgImage = CGImageSourceCreateWithData((__bridge CFDataRef)imageData, NULL);
CGImageDestinationRef destination = CGImageDestinationCreateWithData(
(__bridge CFMutableDataRef)mutableData, CGImageSourceGetType(cgImage), 1, nil);
CGImageDestinationAddImageFromSource(
destination, cgImage, 0,
(__bridge CFDictionaryRef) @{(__bridge NSString *)kCGImagePropertyExifDictionary : exifData});
CGImageDestinationAddImageFromSource(destination, cgImage, 0, (__bridge CFDictionaryRef)metaData);
CGImageDestinationFinalize(destination);
CFRelease(cgImage);
CFRelease(destination);
Expand Down Expand Up @@ -90,4 +83,29 @@ + (NSData *)convertImage:(UIImage *)image
}
}

+ (UIImageOrientation)getNormalizedUIImageOrientationFromCGImagePropertyOrientation:
(CGImagePropertyOrientation)cgImageOrientation {
switch (cgImageOrientation) {
case kCGImagePropertyOrientationUp:
return UIImageOrientationUp;
case kCGImagePropertyOrientationDown:
return UIImageOrientationDown;
case kCGImagePropertyOrientationLeft:
return UIImageOrientationRight;
case kCGImagePropertyOrientationRight:
return UIImageOrientationLeft;
case kCGImagePropertyOrientationUpMirrored:
return UIImageOrientationUpMirrored;
case kCGImagePropertyOrientationDownMirrored:
return UIImageOrientationDownMirrored;
case kCGImagePropertyOrientationLeftMirrored:
return UIImageOrientationRightMirrored;
case kCGImagePropertyOrientationRightMirrored:
return UIImageOrientationLeftMirrored;
default:
return UIImageOrientationUp;
}
return UIImageOrientationUp;
}

@end
4 changes: 2 additions & 2 deletions packages/image_picker/ios/Classes/ImagePickerPhotoAssetUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ typedef void (^FetchAssetsCompletion)(PHAuthorizationStatus status,

+ (PHAsset *)getAssetFromImagePickerInfo:(NSDictionary *)info;

// Save image with correct exif data and extention copied from the original asset.
// Save image with correct meta data and extention copied from the original asset.
+ (NSString *)saveImageWithOriginalImageData:(NSData *)originalImageData image:(UIImage *)image;

// Save image with correct exif data and extention copied from image picker result info.
// Save image with correct meta data and extention copied from image picker result info.
+ (NSString *)saveImageWithPickerInfo:(nullable NSDictionary *)info image:(UIImage *)image;

@end
Expand Down
40 changes: 24 additions & 16 deletions packages/image_picker/ios/Classes/ImagePickerPhotoAssetUtil.m
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,41 @@ + (PHAsset *)getAssetFromImagePickerInfo:(NSDictionary *)info {
+ (NSString *)saveImageWithOriginalImageData:(NSData *)originalImageData image:(UIImage *)image {
NSString *suffix = kFlutterImagePickerDefaultSuffix;
FlutterImagePickerMIMEType type = kFlutterImagePickerMIMETypeDefault;
NSDictionary *exifData = nil;
NSDictionary *metaData = nil;
// Getting the image type from the original image data if necessary.
if (originalImageData) {
type = [ImagePickerMetaDataUtil getImageMIMETypeFromImageData:originalImageData];
suffix =
[ImagePickerMetaDataUtil imageTypeSuffixFromType:type] ?: kFlutterImagePickerDefaultSuffix;
exifData = [ImagePickerMetaDataUtil getEXIFFromImageData:originalImageData];
metaData = [ImagePickerMetaDataUtil getMetaDataFromImageData:originalImageData];
}
return [self saveImageWithExif:exifData image:image suffix:suffix type:type];
return [self saveImageWithMetaData:metaData image:image suffix:suffix type:type];
}

+ (NSString *)saveImageWithPickerInfo:(nullable NSDictionary *)info image:(UIImage *)image {
NSDictionary *exif = info[UIImagePickerControllerMediaMetadata]
[(__bridge NSString *)kCGImagePropertyExifDictionary];
return [self saveImageWithExif:exif
image:image
suffix:kFlutterImagePickerDefaultSuffix
type:kFlutterImagePickerMIMETypeDefault];
NSDictionary *metaData = info[UIImagePickerControllerMediaMetadata];
return [self saveImageWithMetaData:metaData
image:image
suffix:kFlutterImagePickerDefaultSuffix
type:kFlutterImagePickerMIMETypeDefault];
}

+ (NSString *)saveImageWithExif:(NSDictionary *)exif
image:(UIImage *)image
suffix:(NSString *)suffix
type:(FlutterImagePickerMIMEType)type {
NSData *data = [ImagePickerMetaDataUtil convertImage:image usingType:type quality:nil];
if (exif) {
data = [ImagePickerMetaDataUtil updateEXIFData:exif toImage:data];
+ (NSString *)saveImageWithMetaData:(NSDictionary *)metaData
image:(UIImage *)image
suffix:(NSString *)suffix
type:(FlutterImagePickerMIMEType)type {
CGImagePropertyOrientation orientation = (CGImagePropertyOrientation)[metaData[(
__bridge NSString *)kCGImagePropertyOrientation] integerValue];
UIImage *newImage = [UIImage
imageWithCGImage:[image CGImage]
scale:1.0
orientation:
[ImagePickerMetaDataUtil
getNormalizedUIImageOrientationFromCGImagePropertyOrientation:orientation]];

NSData *data = [ImagePickerMetaDataUtil convertImage:newImage usingType:type quality:nil];
if (metaData) {
data = [ImagePickerMetaDataUtil updateMetaData:metaData toImage:data];
}

NSString *fileExtension = [@"image_picker_%@" stringByAppendingString:suffix];
Expand Down
2 changes: 1 addition & 1 deletion packages/image_picker/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ authors:
- Flutter Team <flutter-dev@googlegroups.com>
- Rhodes Davis Jr. <rody.davis.jr@gmail.com>
homepage: https://github.com/flutter/plugins/tree/master/packages/image_picker
version: 0.6.0+5
version: 0.6.0+6

flutter:
plugin:
Expand Down