Skip to content

Commit 32dcbf3

Browse files
authored
[image_picker] Improve image_picker for iOS to handle more image types (flutter#6812)
* Improve image picker for ios to handle more image types * Update release info * different svg, remove raw test * change pro raw image * change pro raw image * add error log * fix formatting * fix image identifiers in test * get image type identifier from itemProvider in test
1 parent 7efb5e8 commit 32dcbf3

File tree

12 files changed

+133
-27
lines changed

12 files changed

+133
-27
lines changed

packages/image_picker/image_picker_ios/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.8.6+2
2+
3+
* Fixes issue where selectable images of certain types (such as ProRAW images) could not be loaded.
4+
15
## 0.8.6+1
26

37
* Fixes issue with crashing the app when picking images with PHPicker without providing `Photo Library Usage` permission.

packages/image_picker/image_picker_ios/example/ios/Runner.xcodeproj/project.pbxproj

+42
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@
1818
680049382280F2B9006DD6AB /* pngImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 680049352280F2B8006DD6AB /* pngImage.png */; };
1919
680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 680049362280F2B8006DD6AB /* jpgImage.jpg */; };
2020
6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6801C8382555D726009DAF8D /* ImagePickerFromGalleryUITests.m */; };
21+
7865C5E12941326F0010E17F /* bmpImage.bmp in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5E02941326F0010E17F /* bmpImage.bmp */; };
22+
7865C5E22941326F0010E17F /* bmpImage.bmp in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5E02941326F0010E17F /* bmpImage.bmp */; };
23+
7865C5E4294132D50010E17F /* svgImage.svg in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5E3294132D50010E17F /* svgImage.svg */; };
24+
7865C5E5294132D50010E17F /* svgImage.svg in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5E3294132D50010E17F /* svgImage.svg */; };
25+
7865C5E72941374F0010E17F /* heicImage.heic in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5E62941374F0010E17F /* heicImage.heic */; };
26+
7865C5E82941374F0010E17F /* heicImage.heic in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5E62941374F0010E17F /* heicImage.heic */; };
27+
7865C5EA294137960010E17F /* icoImage.ico in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5E9294137960010E17F /* icoImage.ico */; };
28+
7865C5EB294137960010E17F /* icoImage.ico in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5E9294137960010E17F /* icoImage.ico */; };
29+
7865C5ED294137AB0010E17F /* tiffImage.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5EC294137AB0010E17F /* tiffImage.tiff */; };
30+
7865C5EE294137AB0010E17F /* tiffImage.tiff in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5EC294137AB0010E17F /* tiffImage.tiff */; };
31+
7865C5FC294157BC0010E17F /* icnsImage.icns in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5FB294157BB0010E17F /* icnsImage.icns */; };
32+
7865C5FD294157BC0010E17F /* icnsImage.icns in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5FB294157BB0010E17F /* icnsImage.icns */; };
33+
7865C5FF294252A60010E17F /* proRawImage.dng in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5FE294252A60010E17F /* proRawImage.dng */; };
34+
7865C600294252A60010E17F /* proRawImage.dng in Resources */ = {isa = PBXBuildFile; fileRef = 7865C5FE294252A60010E17F /* proRawImage.dng */; };
2135
86430DF9272D71E9002D9D6C /* gifImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */; };
2236
86E9A893272754860017E6E0 /* PickerSaveImageToPathOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 86E9A892272754860017E6E0 /* PickerSaveImageToPathOperationTests.m */; };
2337
86E9A894272754A30017E6E0 /* webpImage.webp in Resources */ = {isa = PBXBuildFile; fileRef = 86E9A88F272747B90017E6E0 /* webpImage.webp */; };
@@ -81,6 +95,13 @@
8195
6801C83A2555D726009DAF8D /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
8296
68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ImagePickerPluginTests.m; sourceTree = "<group>"; };
8397
68F4B463228B3AB500C25614 /* PhotoAssetUtilTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PhotoAssetUtilTests.m; sourceTree = "<group>"; };
98+
7865C5E02941326F0010E17F /* bmpImage.bmp */ = {isa = PBXFileReference; lastKnownFileType = image.bmp; path = bmpImage.bmp; sourceTree = "<group>"; };
99+
7865C5E3294132D50010E17F /* svgImage.svg */ = {isa = PBXFileReference; lastKnownFileType = text; path = svgImage.svg; sourceTree = "<group>"; };
100+
7865C5E62941374F0010E17F /* heicImage.heic */ = {isa = PBXFileReference; lastKnownFileType = file; path = heicImage.heic; sourceTree = "<group>"; };
101+
7865C5E9294137960010E17F /* icoImage.ico */ = {isa = PBXFileReference; lastKnownFileType = image.ico; path = icoImage.ico; sourceTree = "<group>"; };
102+
7865C5EC294137AB0010E17F /* tiffImage.tiff */ = {isa = PBXFileReference; lastKnownFileType = image.tiff; path = tiffImage.tiff; sourceTree = "<group>"; };
103+
7865C5FB294157BB0010E17F /* icnsImage.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = icnsImage.icns; sourceTree = "<group>"; };
104+
7865C5FE294252A60010E17F /* proRawImage.dng */ = {isa = PBXFileReference; lastKnownFileType = file; path = proRawImage.dng; sourceTree = "<group>"; };
84105
7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = "<group>"; };
85106
7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
86107
7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
@@ -152,6 +173,13 @@
152173
9FC8F0E8229FA49E00C8D58F /* gifImage.gif */,
153174
680049362280F2B8006DD6AB /* jpgImage.jpg */,
154175
680049352280F2B8006DD6AB /* pngImage.png */,
176+
7865C5E02941326F0010E17F /* bmpImage.bmp */,
177+
7865C5E62941374F0010E17F /* heicImage.heic */,
178+
7865C5FB294157BB0010E17F /* icnsImage.icns */,
179+
7865C5E9294137960010E17F /* icoImage.ico */,
180+
7865C5FE294252A60010E17F /* proRawImage.dng */,
181+
7865C5E3294132D50010E17F /* svgImage.svg */,
182+
7865C5EC294137AB0010E17F /* tiffImage.tiff */,
155183
);
156184
path = TestImages;
157185
sourceTree = "<group>";
@@ -361,10 +389,17 @@
361389
isa = PBXResourcesBuildPhase;
362390
buildActionMask = 2147483647;
363391
files = (
392+
7865C5E12941326F0010E17F /* bmpImage.bmp in Resources */,
393+
7865C5E4294132D50010E17F /* svgImage.svg in Resources */,
364394
86430DF9272D71E9002D9D6C /* gifImage.gif in Resources */,
395+
7865C5FF294252A60010E17F /* proRawImage.dng in Resources */,
396+
7865C5EA294137960010E17F /* icoImage.ico in Resources */,
397+
7865C5E72941374F0010E17F /* heicImage.heic in Resources */,
365398
86E9A894272754A30017E6E0 /* webpImage.webp in Resources */,
366399
86E9A895272769130017E6E0 /* pngImage.png in Resources */,
400+
7865C5FC294157BC0010E17F /* icnsImage.icns in Resources */,
367401
86E9A896272769150017E6E0 /* jpgImage.jpg in Resources */,
402+
7865C5ED294137AB0010E17F /* tiffImage.tiff in Resources */,
368403
);
369404
runOnlyForDeploymentPostprocessing = 0;
370405
};
@@ -373,8 +408,15 @@
373408
buildActionMask = 2147483647;
374409
files = (
375410
9FC8F0EC229FA68500C8D58F /* gifImage.gif in Resources */,
411+
7865C5EE294137AB0010E17F /* tiffImage.tiff in Resources */,
412+
7865C5E82941374F0010E17F /* heicImage.heic in Resources */,
413+
7865C5FD294157BC0010E17F /* icnsImage.icns in Resources */,
376414
680049382280F2B9006DD6AB /* pngImage.png in Resources */,
377415
680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */,
416+
7865C5EB294137960010E17F /* icoImage.ico in Resources */,
417+
7865C5E22941326F0010E17F /* bmpImage.bmp in Resources */,
418+
7865C600294252A60010E17F /* proRawImage.dng in Resources */,
419+
7865C5E5294132D50010E17F /* svgImage.svg in Resources */,
378420
);
379421
runOnlyForDeploymentPostprocessing = 0;
380422
};

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

+69-12
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ - (void)testSaveWebPImage API_AVAILABLE(ios(14)) {
1919
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"webpImage"
2020
withExtension:@"webp"];
2121
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
22-
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider
23-
withIdentifier:UTTypeWebP.identifier];
22+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
2423

2524
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
2625
}
@@ -29,8 +28,7 @@ - (void)testSavePNGImage API_AVAILABLE(ios(14)) {
2928
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"pngImage"
3029
withExtension:@"png"];
3130
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
32-
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider
33-
withIdentifier:UTTypeWebP.identifier];
31+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
3432

3533
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
3634
}
@@ -39,8 +37,7 @@ - (void)testSaveJPGImage API_AVAILABLE(ios(14)) {
3937
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"jpgImage"
4038
withExtension:@"jpg"];
4139
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
42-
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider
43-
withIdentifier:UTTypeWebP.identifier];
40+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
4441

4542
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
4643
}
@@ -49,20 +46,80 @@ - (void)testSaveGIFImage API_AVAILABLE(ios(14)) {
4946
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"gifImage"
5047
withExtension:@"gif"];
5148
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
52-
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider
53-
withIdentifier:UTTypeWebP.identifier];
49+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
5450

5551
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
5652
}
5753

54+
- (void)testSaveBMPImage API_AVAILABLE(ios(14)) {
55+
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"bmpImage"
56+
withExtension:@"bmp"];
57+
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
58+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
59+
60+
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
61+
}
62+
63+
- (void)testSaveHEICImage API_AVAILABLE(ios(14)) {
64+
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"heicImage"
65+
withExtension:@"heic"];
66+
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
67+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
68+
69+
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
70+
}
71+
72+
- (void)testSaveICNSImage API_AVAILABLE(ios(14)) {
73+
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"icnsImage"
74+
withExtension:@"icns"];
75+
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
76+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
77+
78+
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
79+
}
80+
81+
- (void)testSaveICOImage API_AVAILABLE(ios(14)) {
82+
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"icoImage"
83+
withExtension:@"ico"];
84+
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
85+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
86+
87+
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
88+
}
89+
90+
- (void)testSaveProRAWImage API_AVAILABLE(ios(14)) {
91+
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"proRawImage"
92+
withExtension:@"dng"];
93+
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
94+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
95+
96+
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
97+
}
98+
99+
- (void)testSaveSVGImage API_AVAILABLE(ios(14)) {
100+
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"svgImage"
101+
withExtension:@"svg"];
102+
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
103+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
104+
105+
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
106+
}
107+
108+
- (void)testSaveTIFFImage API_AVAILABLE(ios(14)) {
109+
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"tiffImage"
110+
withExtension:@"tiff"];
111+
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
112+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
113+
[self verifySavingImageWithPickerResult:result fullMetadata:YES];
114+
}
115+
58116
- (void)testSavePNGImageWithoutFullMetadata API_AVAILABLE(ios(14)) {
59117
id photoAssetUtil = OCMClassMock([PHAsset class]);
60118

61119
NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"pngImage"
62120
withExtension:@"png"];
63121
NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL];
64-
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider
65-
withIdentifier:UTTypeWebP.identifier];
122+
PHPickerResult *result = [self createPickerResultWithProvider:itemProvider];
66123

67124
[self verifySavingImageWithPickerResult:result fullMetadata:NO];
68125
OCMVerify(times(0), [photoAssetUtil fetchAssetsWithLocalIdentifiers:[OCMArg any]
@@ -76,11 +133,11 @@ - (void)testSavePNGImageWithoutFullMetadata API_AVAILABLE(ios(14)) {
76133
* @param identifier local identifier of the asset
77134
*/
78135
- (PHPickerResult *)createPickerResultWithProvider:(NSItemProvider *)itemProvider
79-
withIdentifier:(NSString *)identifier API_AVAILABLE(ios(14)) {
136+
API_AVAILABLE(ios(14)) {
80137
PHPickerResult *result = OCMClassMock([PHPickerResult class]);
81138

82139
OCMStub([result itemProvider]).andReturn(itemProvider);
83-
OCMStub([result assetIdentifier]).andReturn(identifier);
140+
OCMStub([result assetIdentifier]).andReturn(itemProvider.registeredTypeIdentifiers.firstObject);
84141

85142
return result;
86143
}
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading
Binary file not shown.

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

+14-14
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@
66

77
#import "FLTPHPickerSaveImageToPathOperation.h"
88

9+
#import <os/log.h>
10+
911
API_AVAILABLE(ios(14))
1012
@interface FLTPHPickerSaveImageToPathOperation ()
1113

@@ -88,25 +90,23 @@ - (void)start {
8890
if (@available(iOS 14, *)) {
8991
[self setExecuting:YES];
9092

91-
if ([self.result.itemProvider hasItemConformingToTypeIdentifier:UTTypeWebP.identifier]) {
93+
// This supports uniform types that conform to UTTypeImage.
94+
// This includes UTTypeHEIC, UTTypeHEIF, UTTypeLivePhoto, UTTypeICO, UTTypeICNS, UTTypePNG
95+
// UTTypeGIF, UTTypeJPEG, UTTypeWebP, UTTypeTIFF, UTTypeBMP, UTTypeSVG, UTTypeRAWImage
96+
if ([self.result.itemProvider hasItemConformingToTypeIdentifier:UTTypeImage.identifier]) {
9297
[self.result.itemProvider
93-
loadDataRepresentationForTypeIdentifier:UTTypeWebP.identifier
98+
loadDataRepresentationForTypeIdentifier:UTTypeImage.identifier
9499
completionHandler:^(NSData *_Nullable data,
95100
NSError *_Nullable error) {
96-
UIImage *image = [[UIImage alloc] initWithData:data];
97-
[self processImage:image];
101+
if (data != nil) {
102+
UIImage *image = [[UIImage alloc] initWithData:data];
103+
[self processImage:image];
104+
} else {
105+
os_log_error(OS_LOG_DEFAULT, "Could not process image: %@",
106+
error);
107+
}
98108
}];
99-
return;
100109
}
101-
102-
[self.result.itemProvider
103-
loadObjectOfClass:[UIImage class]
104-
completionHandler:^(__kindof id<NSItemProviderReading> _Nullable image,
105-
NSError *_Nullable error) {
106-
if ([image isKindOfClass:[UIImage class]]) {
107-
[self processImage:image];
108-
}
109-
}];
110110
} else {
111111
[self setFinished:YES];
112112
}

packages/image_picker/image_picker_ios/pubspec.yaml

+1-1
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+1
5+
version: 0.8.6+2
66

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

0 commit comments

Comments
 (0)