[image_picker] GIF files will animate without permissions. PNG and GIF files will retain their image type if missing permissions. (#7084)
* Fix GIF files not animating if permission not given. Fix PNG files getting convert to JPG if permission not given
* updated changelog and pubspec, added a comment
diff --git a/packages/image_picker/image_picker_ios/CHANGELOG.md b/packages/image_picker/image_picker_ios/CHANGELOG.md
index 04bb4df..b75e633 100644
--- a/packages/image_picker/image_picker_ios/CHANGELOG.md
+++ b/packages/image_picker/image_picker_ios/CHANGELOG.md
@@ -1,5 +1,6 @@
-## NEXT
+## 0.8.6+7
+* Fixes issue where GIF file would not animate without `Photo Library Usage` permissions. Fixes issue where PNG and GIF files were converted to JPG, but only when they are do not have `Photo Library Usage` permissions.
* Updates minimum Flutter version to 3.0.
## 0.8.6+6
diff --git a/packages/image_picker/image_picker_ios/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker_ios/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m
index 091755c..027e287 100644
--- a/packages/image_picker/image_picker_ios/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m
+++ b/packages/image_picker/image_picker_ios/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m
@@ -21,7 +21,7 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
}
- (void)testSavePNGImage API_AVAILABLE(ios(14)) {
@@ -30,7 +30,7 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"png"];
}
- (void)testSaveJPGImage API_AVAILABLE(ios(14)) {
@@ -39,7 +39,7 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
}
- (void)testSaveGIFImage API_AVAILABLE(ios(14)) {
@@ -48,7 +48,39 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ NSData *dataGIF = [NSData dataWithContentsOfURL:imageURL];
+ CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)dataGIF, nil);
+ size_t numberOfFrames = CGImageSourceGetCount(imageSource);
+
+ XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"];
+ XCTestExpectation *operationExpectation =
+ [self expectationWithDescription:@"Operation completed"];
+
+ FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc]
+ initWithResult:result
+ maxHeight:@100
+ maxWidth:@100
+ desiredImageQuality:@100
+ fullMetadata:NO
+ savedPathBlock:^(NSString *savedPath, FlutterError *error) {
+ XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:savedPath]);
+
+ // Ensure gif is animated.
+ XCTAssertEqualObjects([NSURL URLWithString:savedPath].pathExtension, @"gif");
+ NSData *newDataGIF = [NSData dataWithContentsOfFile:savedPath];
+ CGImageSourceRef newImageSource =
+ CGImageSourceCreateWithData((__bridge CFDataRef)newDataGIF, nil);
+ size_t newNumberOfFrames = CGImageSourceGetCount(newImageSource);
+ XCTAssertEqual(numberOfFrames, newNumberOfFrames);
+ [pathExpectation fulfill];
+ }];
+ operation.completionBlock = ^{
+ [operationExpectation fulfill];
+ };
+
+ [operation start];
+ [self waitForExpectationsWithTimeout:30 handler:nil];
+ XCTAssertTrue(operation.isFinished);
}
- (void)testSaveBMPImage API_AVAILABLE(ios(14)) {
@@ -57,7 +89,7 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
}
- (void)testSaveHEICImage API_AVAILABLE(ios(14)) {
@@ -66,7 +98,7 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
}
- (void)testSaveICNSImage API_AVAILABLE(ios(14)) {
@@ -75,7 +107,7 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
}
- (void)testSaveICOImage API_AVAILABLE(ios(14)) {
@@ -84,7 +116,7 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
}
- (void)testSaveProRAWImage API_AVAILABLE(ios(14)) {
@@ -93,7 +125,7 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
}
- (void)testSaveSVGImage API_AVAILABLE(ios(14)) {
@@ -102,7 +134,7 @@
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
}
- (void)testSaveTIFFImage API_AVAILABLE(ios(14)) {
@@ -110,7 +142,7 @@
withExtension:@"tiff"];
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
- [self verifySavingImageWithPickerResult:result fullMetadata:YES];
+ [self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
}
- (void)testNonexistentImage API_AVAILABLE(ios(14)) {
@@ -176,7 +208,7 @@
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
OCMReject([photoAssetUtil fetchAssetsWithLocalIdentifiers:OCMOCK_ANY options:OCMOCK_ANY]);
- [self verifySavingImageWithPickerResult:result fullMetadata:NO];
+ [self verifySavingImageWithPickerResult:result fullMetadata:NO withExtension:@"png"];
OCMVerifyAll(photoAssetUtil);
}
@@ -204,7 +236,8 @@
* @param result the picker result
*/
- (void)verifySavingImageWithPickerResult:(PHPickerResult *)result
- fullMetadata:(BOOL)fullMetadata API_AVAILABLE(ios(14)) {
+ fullMetadata:(BOOL)fullMetadata
+ withExtension:(NSString *)extension API_AVAILABLE(ios(14)) {
XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"];
XCTestExpectation *operationExpectation =
[self expectationWithDescription:@"Operation completed"];
@@ -217,6 +250,7 @@
fullMetadata:fullMetadata
savedPathBlock:^(NSString *savedPath, FlutterError *error) {
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:savedPath]);
+ XCTAssertEqualObjects([NSURL URLWithString:savedPath].pathExtension, extension);
[pathExpectation fulfill];
}];
operation.completionBlock = ^{
diff --git a/packages/image_picker/image_picker_ios/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker_ios/ios/Classes/FLTPHPickerSaveImageToPathOperation.m
index 11fedfb..efcbdbe 100644
--- a/packages/image_picker/image_picker_ios/ios/Classes/FLTPHPickerSaveImageToPathOperation.m
+++ b/packages/image_picker/image_picker_ios/ios/Classes/FLTPHPickerSaveImageToPathOperation.m
@@ -98,8 +98,7 @@
completionHandler:^(NSData *_Nullable data,
NSError *_Nullable error) {
if (data != nil) {
- UIImage *image = [[UIImage alloc] initWithData:data];
- [self processImage:image];
+ [self processImage:data];
} else {
FlutterError *flutterError =
[FlutterError errorWithCode:@"invalid_image"
@@ -122,7 +121,9 @@
/**
* Processes the image.
*/
-- (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) {
+- (void)processImage:(NSData *)pickerImageData API_AVAILABLE(ios(14)) {
+ UIImage *localImage = [[UIImage alloc] initWithData:pickerImageData];
+
PHAsset *originalAsset;
// Only if requested, fetch the full "PHAsset" metadata, which requires "Photo Library Usage"
// permissions.
@@ -172,10 +173,13 @@
}
} else {
// Image picked without an original asset (e.g. User pick image without permission)
+ // maxWidth and maxHeight are used only for GIF images.
NSString *savedPath =
- [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil
- image:localImage
- imageQuality:self.desiredImageQuality];
+ [FLTImagePickerPhotoAssetUtil saveImageWithOriginalImageData:pickerImageData
+ image:localImage
+ maxWidth:self.maxWidth
+ maxHeight:self.maxHeight
+ imageQuality:self.desiredImageQuality];
[self completeOperationWithPath:savedPath error:nil];
}
}
diff --git a/packages/image_picker/image_picker_ios/pubspec.yaml b/packages/image_picker/image_picker_ios/pubspec.yaml
index 5bfb885..1f4e2af 100755
--- a/packages/image_picker/image_picker_ios/pubspec.yaml
+++ b/packages/image_picker/image_picker_ios/pubspec.yaml
@@ -2,7 +2,7 @@
description: iOS implementation of the image_picker plugin.
repository: https://github.com/flutter/plugins/tree/main/packages/image_picker/image_picker_ios
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
-version: 0.8.6+6
+version: 0.8.6+7
environment:
sdk: ">=2.14.0 <3.0.0"