Skip to content
This repository was archived by the owner on Feb 22, 2023. It is now read-only.

Commit 8838645

Browse files
authored
[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
1 parent d065e4e commit 8838645

File tree

4 files changed

+60
-21
lines changed

4 files changed

+60
-21
lines changed

packages/image_picker/image_picker_ios/CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1-
## NEXT
1+
## 0.8.6+7
22

3+
* 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.
34
* Updates minimum Flutter version to 3.0.
45

56
## 0.8.6+6

packages/image_picker/image_picker_ios/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m

Lines changed: 47 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ - (void)testSaveWebPImage API_AVAILABLE(ios(14)) {
2121
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
2222
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
2323

24-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
24+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
2525
}
2626

2727
- (void)testSavePNGImage API_AVAILABLE(ios(14)) {
@@ -30,7 +30,7 @@ - (void)testSavePNGImage API_AVAILABLE(ios(14)) {
3030
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
3131
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
3232

33-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
33+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"png"];
3434
}
3535

3636
- (void)testSaveJPGImage API_AVAILABLE(ios(14)) {
@@ -39,7 +39,7 @@ - (void)testSaveJPGImage API_AVAILABLE(ios(14)) {
3939
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
4040
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
4141

42-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
42+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
4343
}
4444

4545
- (void)testSaveGIFImage API_AVAILABLE(ios(14)) {
@@ -48,7 +48,39 @@ - (void)testSaveGIFImage API_AVAILABLE(ios(14)) {
4848
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
4949
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
5050

51-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
51+
NSData *dataGIF = [NSData dataWithContentsOfURL:imageURL];
52+
CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)dataGIF, nil);
53+
size_t numberOfFrames = CGImageSourceGetCount(imageSource);
54+
55+
XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"];
56+
XCTestExpectation *operationExpectation =
57+
[self expectationWithDescription:@"Operation completed"];
58+
59+
FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc]
60+
initWithResult:result
61+
maxHeight:@100
62+
maxWidth:@100
63+
desiredImageQuality:@100
64+
fullMetadata:NO
65+
savedPathBlock:^(NSString *savedPath, FlutterError *error) {
66+
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:savedPath]);
67+
68+
// Ensure gif is animated.
69+
XCTAssertEqualObjects([NSURL URLWithString:savedPath].pathExtension, @"gif");
70+
NSData *newDataGIF = [NSData dataWithContentsOfFile:savedPath];
71+
CGImageSourceRef newImageSource =
72+
CGImageSourceCreateWithData((__bridge CFDataRef)newDataGIF, nil);
73+
size_t newNumberOfFrames = CGImageSourceGetCount(newImageSource);
74+
XCTAssertEqual(numberOfFrames, newNumberOfFrames);
75+
[pathExpectation fulfill];
76+
}];
77+
operation.completionBlock = ^{
78+
[operationExpectation fulfill];
79+
};
80+
81+
[operation start];
82+
[self waitForExpectationsWithTimeout:30 handler:nil];
83+
XCTAssertTrue(operation.isFinished);
5284
}
5385

5486
- (void)testSaveBMPImage API_AVAILABLE(ios(14)) {
@@ -57,7 +89,7 @@ - (void)testSaveBMPImage API_AVAILABLE(ios(14)) {
5789
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
5890
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
5991

60-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
92+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
6193
}
6294

6395
- (void)testSaveHEICImage API_AVAILABLE(ios(14)) {
@@ -66,7 +98,7 @@ - (void)testSaveHEICImage API_AVAILABLE(ios(14)) {
6698
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
6799
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
68100

69-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
101+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
70102
}
71103

72104
- (void)testSaveICNSImage API_AVAILABLE(ios(14)) {
@@ -75,7 +107,7 @@ - (void)testSaveICNSImage API_AVAILABLE(ios(14)) {
75107
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
76108
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
77109

78-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
110+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
79111
}
80112

81113
- (void)testSaveICOImage API_AVAILABLE(ios(14)) {
@@ -84,7 +116,7 @@ - (void)testSaveICOImage API_AVAILABLE(ios(14)) {
84116
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
85117
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
86118

87-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
119+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
88120
}
89121

90122
- (void)testSaveProRAWImage API_AVAILABLE(ios(14)) {
@@ -93,7 +125,7 @@ - (void)testSaveProRAWImage API_AVAILABLE(ios(14)) {
93125
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
94126
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
95127

96-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
128+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
97129
}
98130

99131
- (void)testSaveSVGImage API_AVAILABLE(ios(14)) {
@@ -102,15 +134,15 @@ - (void)testSaveSVGImage API_AVAILABLE(ios(14)) {
102134
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
103135
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
104136

105-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
137+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
106138
}
107139

108140
- (void)testSaveTIFFImage API_AVAILABLE(ios(14)) {
109141
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"tiffImage"
110142
withExtension:@"tiff"];
111143
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
112144
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
113-
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
145+
[self verifySavingImageWithPickerResult:result fullMetadata:YES withExtension:@"jpg"];
114146
}
115147

116148
- (void)testNonexistentImage API_AVAILABLE(ios(14)) {
@@ -176,7 +208,7 @@ - (void)testSavePNGImageWithoutFullMetadata API_AVAILABLE(ios(14)) {
176208
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
177209
OCMReject([photoAssetUtil fetchAssetsWithLocalIdentifiers:OCMOCK_ANY options:OCMOCK_ANY]);
178210

179-
[self verifySavingImageWithPickerResult:result fullMetadata:NO];
211+
[self verifySavingImageWithPickerResult:result fullMetadata:NO withExtension:@"png"];
180212
OCMVerifyAll(photoAssetUtil);
181213
}
182214

@@ -204,7 +236,8 @@ - (PHPickerResult *)createPickerResultWithProvider:(NSItemProvider *)itemProvide
204236
* @param result the picker result
205237
*/
206238
- (void)verifySavingImageWithPickerResult:(PHPickerResult *)result
207-
fullMetadata:(BOOL)fullMetadata API_AVAILABLE(ios(14)) {
239+
fullMetadata:(BOOL)fullMetadata
240+
withExtension:(NSString *)extension API_AVAILABLE(ios(14)) {
208241
XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"];
209242
XCTestExpectation *operationExpectation =
210243
[self expectationWithDescription:@"Operation completed"];
@@ -217,6 +250,7 @@ - (void)verifySavingImageWithPickerResult:(PHPickerResult *)result
217250
fullMetadata:fullMetadata
218251
savedPathBlock:^(NSString *savedPath, FlutterError *error) {
219252
XCTAssertTrue([[NSFileManager defaultManager] fileExistsAtPath:savedPath]);
253+
XCTAssertEqualObjects([NSURL URLWithString:savedPath].pathExtension, extension);
220254
[pathExpectation fulfill];
221255
}];
222256
operation.completionBlock = ^{

packages/image_picker/image_picker_ios/ios/Classes/FLTPHPickerSaveImageToPathOperation.m

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -98,8 +98,7 @@ - (void)start {
9898
completionHandler:^(NSData *_Nullable data,
9999
NSError *_Nullable error) {
100100
if (data != nil) {
101-
UIImage *image = [[UIImage alloc] initWithData:data];
102-
[self processImage:image];
101+
[self processImage:data];
103102
} else {
104103
FlutterError *flutterError =
105104
[FlutterError errorWithCode:@"invalid_image"
@@ -122,7 +121,9 @@ - (void)start {
122121
/**
123122
* Processes the image.
124123
*/
125-
- (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) {
124+
- (void)processImage:(NSData *)pickerImageData API_AVAILABLE(ios(14)) {
125+
UIImage *localImage = [[UIImage alloc] initWithData:pickerImageData];
126+
126127
PHAsset *originalAsset;
127128
// Only if requested, fetch the full "PHAsset" metadata, which requires "Photo Library Usage"
128129
// permissions.
@@ -172,10 +173,13 @@ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) {
172173
}
173174
} else {
174175
// Image picked without an original asset (e.g. User pick image without permission)
176+
// maxWidth and maxHeight are used only for GIF images.
175177
NSString *savedPath =
176-
[FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil
177-
image:localImage
178-
imageQuality:self.desiredImageQuality];
178+
[FLTImagePickerPhotoAssetUtil saveImageWithOriginalImageData:pickerImageData
179+
image:localImage
180+
maxWidth:self.maxWidth
181+
maxHeight:self.maxHeight
182+
imageQuality:self.desiredImageQuality];
179183
[self completeOperationWithPath:savedPath error:nil];
180184
}
181185
}

packages/image_picker/image_picker_ios/pubspec.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: image_picker_ios
22
description: iOS implementation of the image_picker plugin.
33
repository: https://github.com/flutter/plugins/tree/main/packages/image_picker/image_picker_ios
44
issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22
5-
version: 0.8.6+6
5+
version: 0.8.6+7
66

77
environment:
88
sdk: ">=2.14.0 <3.0.0"

0 commit comments

Comments
 (0)