From a35b4bbcdacf4c29ec75f5fa7855404e76038c69 Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Sun, 24 Oct 2021 00:11:00 +0200 Subject: [PATCH 01/16] support WebP for iOS --- .../FLTPHPickerSaveImageToPathOperation.m | 92 ++++++++++--------- 1 file changed, 51 insertions(+), 41 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m index 30da22774d07..7b67efdc702b 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m @@ -82,51 +82,61 @@ - (void)start { } if (@available(iOS 14, *)) { [self setExecuting:YES]; - [self.result.itemProvider - loadObjectOfClass:[UIImage class] - completionHandler:^(__kindof id _Nullable image, - NSError *_Nullable error) { - if ([image isKindOfClass:[UIImage class]]) { - __block UIImage *localImage = image; - PHAsset *originalAsset = - [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; - - if (self.maxWidth != (id)[NSNull null] || self.maxHeight != (id)[NSNull null]) { - localImage = [FLTImagePickerImageUtil scaledImage:localImage - maxWidth:self.maxWidth - maxHeight:self.maxHeight - isMetadataAvailable:originalAsset != nil]; - } - __block NSString *savedPath; - if (!originalAsset) { - // Image picked without an original asset (e.g. User pick image without permission) - savedPath = - [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil - image:localImage - imageQuality:self.desiredImageQuality]; - [self completeOperationWithPath:savedPath]; - } else { - [[PHImageManager defaultManager] - requestImageDataForAsset:originalAsset - options:nil - resultHandler:^( - NSData *_Nullable imageData, NSString *_Nullable dataUTI, - UIImageOrientation orientation, NSDictionary *_Nullable info) { - // maxWidth and maxHeight are used only for GIF images. - savedPath = [FLTImagePickerPhotoAssetUtil - saveImageWithOriginalImageData:imageData - image:localImage - maxWidth:self.maxWidth - maxHeight:self.maxHeight - imageQuality:self.desiredImageQuality]; - [self completeOperationWithPath:savedPath]; - }]; - } - } + NSString *webpIdentifier = @"org.webmproject.webp"; + if ([self.result.itemProvider hasItemConformingToTypeIdentifier:webpIdentifier]) { + [self.result.itemProvider loadDataRepresentationForTypeIdentifier:webpIdentifier completionHandler:^(NSData * _Nullable data, NSError * _Nullable error) { + __block UIImage *image = [[UIImage alloc] initWithData:data]; + [self processImage:image]; }]; + return; + } + + [self.result.itemProvider loadObjectOfClass:[UIImage class] completionHandler:^(__kindof id _Nullable image, NSError *_Nullable error) { + if ([image isKindOfClass:[UIImage class]]) { + [self processImage:image]; + } + }]; } else { [self setFinished:YES]; } } +- (void)processImage:(UIImage *)image API_AVAILABLE(ios(14)); { + __block UIImage *localImage = image; + PHAsset *originalAsset = + [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; + + if (self.maxWidth != (id)[NSNull null] || self.maxHeight != (id)[NSNull null]) { + localImage = [FLTImagePickerImageUtil scaledImage:localImage + maxWidth:self.maxWidth + maxHeight:self.maxHeight + isMetadataAvailable:originalAsset != nil]; + } + __block NSString *savedPath; + if (!originalAsset) { + // Image picked without an original asset (e.g. User pick image without permission) + savedPath = + [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil + image:localImage + imageQuality:self.desiredImageQuality]; + [self completeOperationWithPath:savedPath]; + } else { + [[PHImageManager defaultManager] + requestImageDataForAsset:originalAsset + options:nil + resultHandler:^( + NSData *_Nullable imageData, NSString *_Nullable dataUTI, + UIImageOrientation orientation, NSDictionary *_Nullable info) { + // maxWidth and maxHeight are used only for GIF images. + savedPath = [FLTImagePickerPhotoAssetUtil + saveImageWithOriginalImageData:imageData + image:localImage + maxWidth:self.maxWidth + maxHeight:self.maxHeight + imageQuality:self.desiredImageQuality]; + [self completeOperationWithPath:savedPath]; + }]; + } +} + @end From 6ceddd670c3221c3740da4582c02d1205305e8f6 Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Sun, 24 Oct 2021 00:16:38 +0200 Subject: [PATCH 02/16] update CHANGELOG --- packages/image_picker/image_picker/CHANGELOG.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 90829cc7ae6a..c95397d0a6c5 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.8.4+4 + +* Support adding WebP for iOS + ## 0.8.4+3 * Suppress a unchecked cast build warning. From c7e886dd298097af91e38ec5f5bb90e1b9dfb861 Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Sun, 24 Oct 2021 00:18:24 +0200 Subject: [PATCH 03/16] update Pubspec --- packages/image_picker/image_picker/pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/pubspec.yaml b/packages/image_picker/image_picker/pubspec.yaml index 99766702cfdf..44a7c9b80749 100755 --- a/packages/image_picker/image_picker/pubspec.yaml +++ b/packages/image_picker/image_picker/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for selecting images from the Android and iOS image library, and taking new pictures with the camera. repository: https://github.com/flutter/plugins/tree/master/packages/image_picker/image_picker issue_tracker: https://github.com/flutter/flutter/issues?q=is%3Aissue+is%3Aopen+label%3A%22p%3A+image_picker%22 -version: 0.8.4+3 +version: 0.8.4+4 environment: sdk: ">=2.14.0 <3.0.0" From c15c261d8cfcd3a86f6706dbbfbe626d25cc9f04 Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Mon, 25 Oct 2021 20:38:49 +0200 Subject: [PATCH 04/16] use const insteed of self-defined string --- .../ios/Classes/FLTPHPickerSaveImageToPathOperation.h | 1 + .../ios/Classes/FLTPHPickerSaveImageToPathOperation.m | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h index 7ba3d28ef3dd..683948b2312e 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h @@ -4,6 +4,7 @@ #import #import +#import #import "FLTImagePickerImageUtil.h" #import "FLTImagePickerMetaDataUtil.h" diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m index 7b67efdc702b..ab89a33e8189 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m @@ -82,9 +82,9 @@ - (void)start { } if (@available(iOS 14, *)) { [self setExecuting:YES]; - NSString *webpIdentifier = @"org.webmproject.webp"; - if ([self.result.itemProvider hasItemConformingToTypeIdentifier:webpIdentifier]) { - [self.result.itemProvider loadDataRepresentationForTypeIdentifier:webpIdentifier completionHandler:^(NSData * _Nullable data, NSError * _Nullable error) { + + if ([self.result.itemProvider hasItemConformingToTypeIdentifier:UTTypeWebP.identifier]) { + [self.result.itemProvider loadDataRepresentationForTypeIdentifier:UTTypeWebP.identifier completionHandler:^(NSData * _Nullable data, NSError * _Nullable error) { __block UIImage *image = [[UIImage alloc] initWithData:data]; [self processImage:image]; }]; From 88b25f7b43d87f099a338d3176dd85c266011fe9 Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Tue, 26 Oct 2021 00:54:12 +0200 Subject: [PATCH 05/16] add test --- .../ios/Runner.xcodeproj/project.pbxproj | 18 ++++++ .../PickerSaveImageToPathOperationTests.m | 56 ++++++++++++++++++ .../example/ios/TestImages/webpImage.webp | Bin 0 -> 2622 bytes 3 files changed, 74 insertions(+) create mode 100644 packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m create mode 100644 packages/image_picker/image_picker/example/ios/TestImages/webpImage.webp diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj index 192962839b24..c3e962efa1ae 100644 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -19,6 +19,12 @@ 680049382280F2B9006DD6AB /* pngImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 680049352280F2B8006DD6AB /* pngImage.png */; }; 680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 680049362280F2B8006DD6AB /* jpgImage.jpg */; }; 6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6801C8382555D726009DAF8D /* ImagePickerFromGalleryUITests.m */; }; + 86E9A890272747C00017E6E0 /* webpImage.webp in Resources */ = {isa = PBXBuildFile; fileRef = 86E9A88F272747B90017E6E0 /* webpImage.webp */; }; + 86E9A89127274A360017E6E0 /* webpImage.webp in Resources */ = {isa = PBXBuildFile; fileRef = 86E9A88F272747B90017E6E0 /* webpImage.webp */; }; + 86E9A893272754860017E6E0 /* PickerSaveImageToPathOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 86E9A892272754860017E6E0 /* PickerSaveImageToPathOperationTests.m */; }; + 86E9A894272754A30017E6E0 /* webpImage.webp in Resources */ = {isa = PBXBuildFile; fileRef = 86E9A88F272747B90017E6E0 /* webpImage.webp */; }; + 86E9A895272769130017E6E0 /* pngImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 680049352280F2B8006DD6AB /* pngImage.png */; }; + 86E9A896272769150017E6E0 /* jpgImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 680049362280F2B8006DD6AB /* jpgImage.jpg */; }; 978B8F6F1D3862AE00F588F7 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */; }; 97C146F31CF9000F007C117D /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 97C146F21CF9000F007C117D /* main.m */; }; 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 97C146FA1CF9000F007C117D /* Main.storyboard */; }; @@ -82,6 +88,8 @@ 7AFA3C8E1D35360C0083082E /* Release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = Release.xcconfig; path = Flutter/Release.xcconfig; sourceTree = ""; }; 7AFFD8ED1D35381100E5BB4D /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 7AFFD8EE1D35381100E5BB4D /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; + 86E9A88F272747B90017E6E0 /* webpImage.webp */ = {isa = PBXFileReference; lastKnownFileType = file; path = webpImage.webp; sourceTree = ""; }; + 86E9A892272754860017E6E0 /* PickerSaveImageToPathOperationTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = PickerSaveImageToPathOperationTests.m; sourceTree = ""; }; 9740EEB21CF90195004384FC /* Debug.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Debug.xcconfig; path = Flutter/Debug.xcconfig; sourceTree = ""; }; 9740EEB31CF90195004384FC /* Generated.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = Generated.xcconfig; path = Flutter/Generated.xcconfig; sourceTree = ""; }; 97C146EE1CF9000F007C117D /* Runner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Runner.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -139,6 +147,7 @@ F78AF3172342D9D7008449C7 /* ImagePickerTestImages.h */, F78AF3182342D9D7008449C7 /* ImagePickerTestImages.m */, 68B9AF71243E4B3F00927CE4 /* ImagePickerPluginTests.m */, + 86E9A892272754860017E6E0 /* PickerSaveImageToPathOperationTests.m */, 334733F62668136400DCC49E /* Info.plist */, ); path = RunnerTests; @@ -147,6 +156,7 @@ 680049282280E33D006DD6AB /* TestImages */ = { isa = PBXGroup; children = ( + 86E9A88F272747B90017E6E0 /* webpImage.webp */, 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */, 680049362280F2B8006DD6AB /* jpgImage.jpg */, 680049352280F2B8006DD6AB /* pngImage.png */, @@ -373,6 +383,9 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 86E9A894272754A30017E6E0 /* webpImage.webp in Resources */, + 86E9A895272769130017E6E0 /* pngImage.png in Resources */, + 86E9A896272769150017E6E0 /* jpgImage.jpg in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -383,6 +396,7 @@ 9FC8F0EC229FA68500C8D58F /* gifImage.gif in Resources */, 680049382280F2B9006DD6AB /* pngImage.png in Resources */, 680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */, + 86E9A890272747C00017E6E0 /* webpImage.webp in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -391,6 +405,7 @@ buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, + 86E9A89127274A360017E6E0 /* webpImage.webp in Resources */, 9FC8F0E9229FA49E00C8D58F /* gifImage.gif in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, @@ -499,6 +514,7 @@ files = ( 334733FD266813F100DCC49E /* MetaDataUtilTests.m in Sources */, 334733FF266813FA00DCC49E /* ImagePickerTestImages.m in Sources */, + 86E9A893272754860017E6E0 /* PickerSaveImageToPathOperationTests.m in Sources */, 334733FC266813EE00DCC49E /* ImageUtilTests.m in Sources */, 33473400266813FD00DCC49E /* ImagePickerPluginTests.m in Sources */, 334733FE266813F400DCC49E /* PhotoAssetUtilTests.m in Sources */, @@ -565,6 +581,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = RunnerTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; @@ -579,6 +596,7 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = RunnerTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m new file mode 100644 index 000000000000..dc53c8c2de7a --- /dev/null +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -0,0 +1,56 @@ +// +// PickerSaveImageToPathOperationTests.m +// RunnerTests +// +// Created by Giang Long Tran on 25.10.21. +// Copyright © 2021 The Flutter Authors. All rights reserved. +// + +#import +#import + +@import image_picker; + +@interface PickerSaveImageToPathOperationTests : XCTestCase + +@end + +@implementation PickerSaveImageToPathOperationTests + +- (void)testSaveWebPImage API_AVAILABLE(ios(14)); { + // Read item from bundle + NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"webpImage" withExtension:@"webp"]]; + + PHPickerResult *result = [self createPickerResult:itemProvider withIdentifier:UTTypeWebP.identifier]; + + [self testOperationWithPickerResult:result]; +} + +- (PHPickerResult *)createPickerResult:(NSItemProvider*)itemProvider withIdentifier:(NSString*)identifier API_AVAILABLE(ios(14)); { + PHPickerResult *result = OCMClassMock([PHPickerResult class]); + + OCMStub([result itemProvider]).andReturn(itemProvider); + OCMStub([result assetIdentifier]).andReturn(identifier); + + return result; +} + +- (void)testOperationWithPickerResult:(PHPickerResult *)result API_AVAILABLE(ios(14)); { + XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"]; + + FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] + initWithResult:result + maxHeight:@100 + maxWidth:@100 + desiredImageQuality:@100 + savedPathBlock:^(NSString *savedPath) { + if (savedPath != nil) { + [pathExpectation fulfill]; + } + }]; + + [operation start]; + [self waitForExpectations:@[pathExpectation] timeout:30]; +} + +@end diff --git a/packages/image_picker/image_picker/example/ios/TestImages/webpImage.webp b/packages/image_picker/image_picker/example/ios/TestImages/webpImage.webp new file mode 100644 index 0000000000000000000000000000000000000000..ab7d40d839681c96a745fbed51d81709efc5b222 GIT binary patch literal 2622 zcmeHJF>ljA6n>XbQXmr}WjI}hget}722v5LZl$IPw31PjA{wzd_BFAR_$>P>n@kKy z42&HZ5K>mQ&LFiCzkq*HHY6sH5al^C?vKD{o!xR%wtz?d!#H?p%> zo|7xZc`2{1&dWKjq_n=(r3W_vHn)?&cE&={ff#ze$-aL+XVh~|cG$3VD`<(4_hc4| zgW1z(&TQ;7UADbNHxnb722-JInoK8tWF#iDT{#d2;`Ep^x+qa&lci6!WGHAud#LFQ z*`a%6^maQL7c-NMlnM;a<2csh2bv6re7)Iha=p&$^%_>xqL;q1lbRo`{!`c$krR4> z@}y5wMSCERmC5ksMN7d*DjAJrkc<0~wrEmwRDE`tp%JmU1`| qjAPF{YdVGb-*3@k6%G^*6b=*)6b=*){C^Hy%}>I|p()1c2>t?)0hB5L literal 0 HcmV?d00001 From 53f531938a731f65403b30fa594c021d15b960db Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Sat, 30 Oct 2021 14:42:15 +0200 Subject: [PATCH 06/16] fix style and add more tests --- .../ios/Runner.xcodeproj/project.pbxproj | 8 +--- .../PickerSaveImageToPathOperationTests.m | 48 +++++++++++++------ .../FLTPHPickerSaveImageToPathOperation.h | 1 - .../FLTPHPickerSaveImageToPathOperation.m | 12 ++--- 4 files changed, 42 insertions(+), 27 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj index c3e962efa1ae..791eb8115b14 100644 --- a/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj +++ b/packages/image_picker/image_picker/example/ios/Runner.xcodeproj/project.pbxproj @@ -19,8 +19,7 @@ 680049382280F2B9006DD6AB /* pngImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 680049352280F2B8006DD6AB /* pngImage.png */; }; 680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */ = {isa = PBXBuildFile; fileRef = 680049362280F2B8006DD6AB /* jpgImage.jpg */; }; 6801C8392555D726009DAF8D /* ImagePickerFromGalleryUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 6801C8382555D726009DAF8D /* ImagePickerFromGalleryUITests.m */; }; - 86E9A890272747C00017E6E0 /* webpImage.webp in Resources */ = {isa = PBXBuildFile; fileRef = 86E9A88F272747B90017E6E0 /* webpImage.webp */; }; - 86E9A89127274A360017E6E0 /* webpImage.webp in Resources */ = {isa = PBXBuildFile; fileRef = 86E9A88F272747B90017E6E0 /* webpImage.webp */; }; + 86430DF9272D71E9002D9D6C /* gifImage.gif in Resources */ = {isa = PBXBuildFile; fileRef = 9FC8F0E8229FA49E00C8D58F /* gifImage.gif */; }; 86E9A893272754860017E6E0 /* PickerSaveImageToPathOperationTests.m in Sources */ = {isa = PBXBuildFile; fileRef = 86E9A892272754860017E6E0 /* PickerSaveImageToPathOperationTests.m */; }; 86E9A894272754A30017E6E0 /* webpImage.webp in Resources */ = {isa = PBXBuildFile; fileRef = 86E9A88F272747B90017E6E0 /* webpImage.webp */; }; 86E9A895272769130017E6E0 /* pngImage.png in Resources */ = {isa = PBXBuildFile; fileRef = 680049352280F2B8006DD6AB /* pngImage.png */; }; @@ -383,6 +382,7 @@ isa = PBXResourcesBuildPhase; buildActionMask = 2147483647; files = ( + 86430DF9272D71E9002D9D6C /* gifImage.gif in Resources */, 86E9A894272754A30017E6E0 /* webpImage.webp in Resources */, 86E9A895272769130017E6E0 /* pngImage.png in Resources */, 86E9A896272769150017E6E0 /* jpgImage.jpg in Resources */, @@ -396,7 +396,6 @@ 9FC8F0EC229FA68500C8D58F /* gifImage.gif in Resources */, 680049382280F2B9006DD6AB /* pngImage.png in Resources */, 680049392280F2B9006DD6AB /* jpgImage.jpg in Resources */, - 86E9A890272747C00017E6E0 /* webpImage.webp in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -405,7 +404,6 @@ buildActionMask = 2147483647; files = ( 97C147011CF9000F007C117D /* LaunchScreen.storyboard in Resources */, - 86E9A89127274A360017E6E0 /* webpImage.webp in Resources */, 9FC8F0E9229FA49E00C8D58F /* gifImage.gif in Resources */, 3B3967161E833CAA004F5970 /* AppFrameworkInfo.plist in Resources */, 97C146FC1CF9000F007C117D /* Main.storyboard in Resources */, @@ -581,7 +579,6 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = RunnerTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; @@ -596,7 +593,6 @@ buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; CODE_SIGN_STYLE = Automatic; - DEVELOPMENT_TEAM = ""; INFOPLIST_FILE = RunnerTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = dev.flutter.plugins.RunnerTests; diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m index dc53c8c2de7a..2724e52c14cc 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -1,13 +1,10 @@ -// -// PickerSaveImageToPathOperationTests.m -// RunnerTests -// -// Created by Giang Long Tran on 25.10.21. -// Copyright © 2021 The Flutter Authors. All rights reserved. -// +// Copyright 2013 The Flutter Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. #import #import +#import @import image_picker; @@ -17,16 +14,39 @@ @interface PickerSaveImageToPathOperationTests : XCTestCase @implementation PickerSaveImageToPathOperationTests -- (void)testSaveWebPImage API_AVAILABLE(ios(14)); { - // Read item from bundle - NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:[[NSBundle mainBundle] URLForResource:@"webpImage" withExtension:@"webp"]]; +- (void)testSaveWebPImage API_AVAILABLE(ios(14)) { + NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"webpImage" withExtension:@"webp"]; + NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL: imageURL]; + PHPickerResult *result = [self createPickerResult:itemProvider withIdentifier:UTTypeWebP.identifier]; + + [self saveImageToPath:result]; +} + +- (void)testSavePNGImage API_AVAILABLE(ios(14)) { + NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"pngImage" withExtension:@"png"]; + NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL: imageURL]; + PHPickerResult *result = [self createPickerResult:itemProvider withIdentifier:UTTypeWebP.identifier]; + [self saveImageToPath:result]; +} + +- (void)testSaveJPGImage API_AVAILABLE(ios(14)) { + NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"jpgImage" withExtension:@"jpg"]; + NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL: imageURL]; + PHPickerResult *result = [self createPickerResult:itemProvider withIdentifier:UTTypeWebP.identifier]; + + [self saveImageToPath:result]; +} + +- (void)testSaveGIFImage API_AVAILABLE(ios(14)) { + NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"gifImage" withExtension:@"gif"]; + NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL: imageURL]; PHPickerResult *result = [self createPickerResult:itemProvider withIdentifier:UTTypeWebP.identifier]; - [self testOperationWithPickerResult:result]; + [self saveImageToPath:result]; } -- (PHPickerResult *)createPickerResult:(NSItemProvider*)itemProvider withIdentifier:(NSString*)identifier API_AVAILABLE(ios(14)); { +- (PHPickerResult *)createPickerResult:(NSItemProvider*)itemProvider withIdentifier:(NSString*)identifier API_AVAILABLE(ios(14)) { PHPickerResult *result = OCMClassMock([PHPickerResult class]); OCMStub([result itemProvider]).andReturn(itemProvider); @@ -35,7 +55,7 @@ - (PHPickerResult *)createPickerResult:(NSItemProvider*)itemProvider withIdentif return result; } -- (void)testOperationWithPickerResult:(PHPickerResult *)result API_AVAILABLE(ios(14)); { +- (void)saveImageToPath:(PHPickerResult *)result API_AVAILABLE(ios(14)) { XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"]; FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] @@ -44,7 +64,7 @@ - (void)testOperationWithPickerResult:(PHPickerResult *)result API_AVAILABLE(ios maxWidth:@100 desiredImageQuality:@100 savedPathBlock:^(NSString *savedPath) { - if (savedPath != nil) { + if ([[NSFileManager defaultManager] fileExistsAtPath:savedPath]) { [pathExpectation fulfill]; } }]; diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h index 683948b2312e..7ba3d28ef3dd 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h @@ -4,7 +4,6 @@ #import #import -#import #import "FLTImagePickerImageUtil.h" #import "FLTImagePickerMetaDataUtil.h" diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m index ab89a33e8189..684efe71620e 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m @@ -2,6 +2,8 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. +#import + #import "FLTPHPickerSaveImageToPathOperation.h" API_AVAILABLE(ios(14)) @@ -85,7 +87,7 @@ - (void)start { if ([self.result.itemProvider hasItemConformingToTypeIdentifier:UTTypeWebP.identifier]) { [self.result.itemProvider loadDataRepresentationForTypeIdentifier:UTTypeWebP.identifier completionHandler:^(NSData * _Nullable data, NSError * _Nullable error) { - __block UIImage *image = [[UIImage alloc] initWithData:data]; + UIImage *image = [[UIImage alloc] initWithData:data]; [self processImage:image]; }]; return; @@ -101,8 +103,7 @@ - (void)start { } } -- (void)processImage:(UIImage *)image API_AVAILABLE(ios(14)); { - __block UIImage *localImage = image; +- (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; @@ -112,10 +113,9 @@ - (void)processImage:(UIImage *)image API_AVAILABLE(ios(14)); { maxHeight:self.maxHeight isMetadataAvailable:originalAsset != nil]; } - __block NSString *savedPath; if (!originalAsset) { // Image picked without an original asset (e.g. User pick image without permission) - savedPath = + NSString *savedPath = [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil image:localImage imageQuality:self.desiredImageQuality]; @@ -128,7 +128,7 @@ - (void)processImage:(UIImage *)image API_AVAILABLE(ios(14)); { NSData *_Nullable imageData, NSString *_Nullable dataUTI, UIImageOrientation orientation, NSDictionary *_Nullable info) { // maxWidth and maxHeight are used only for GIF images. - savedPath = [FLTImagePickerPhotoAssetUtil + NSString* savedPath = [FLTImagePickerPhotoAssetUtil saveImageWithOriginalImageData:imageData image:localImage maxWidth:self.maxWidth From aa57cf454713ac987a06170a509bcbde2b124faa Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Sat, 30 Oct 2021 14:45:30 +0200 Subject: [PATCH 07/16] fix style --- .../PickerSaveImageToPathOperationTests.m | 97 ++++++++++--------- .../FLTPHPickerSaveImageToPathOperation.m | 86 ++++++++-------- 2 files changed, 98 insertions(+), 85 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m index 2724e52c14cc..7f1465713b55 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -2,9 +2,9 @@ // Use of this source code is governed by a BSD-style license that can be // found in the LICENSE file. -#import #import #import +#import @import image_picker; @@ -14,63 +14,72 @@ @interface PickerSaveImageToPathOperationTests : XCTestCase @implementation PickerSaveImageToPathOperationTests -- (void)testSaveWebPImage API_AVAILABLE(ios(14)) { - NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"webpImage" withExtension:@"webp"]; - NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL: imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider withIdentifier:UTTypeWebP.identifier]; - - [self saveImageToPath:result]; +- (void)testSaveWebPImage API_AVAILABLE(ios(14)) { + NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"webpImage" + withExtension:@"webp"]; + NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; + PHPickerResult *result = [self createPickerResult:itemProvider + withIdentifier:UTTypeWebP.identifier]; + + [self saveImageToPath:result]; } - (void)testSavePNGImage API_AVAILABLE(ios(14)) { - NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"pngImage" withExtension:@"png"]; - NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL: imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider withIdentifier:UTTypeWebP.identifier]; - - [self saveImageToPath:result]; + NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"pngImage" + withExtension:@"png"]; + NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; + PHPickerResult *result = [self createPickerResult:itemProvider + withIdentifier:UTTypeWebP.identifier]; + + [self saveImageToPath:result]; } - (void)testSaveJPGImage API_AVAILABLE(ios(14)) { - NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"jpgImage" withExtension:@"jpg"]; - NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL: imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider withIdentifier:UTTypeWebP.identifier]; - - [self saveImageToPath:result]; + NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"jpgImage" + withExtension:@"jpg"]; + NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; + PHPickerResult *result = [self createPickerResult:itemProvider + withIdentifier:UTTypeWebP.identifier]; + + [self saveImageToPath:result]; } - (void)testSaveGIFImage API_AVAILABLE(ios(14)) { - NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"gifImage" withExtension:@"gif"]; - NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL: imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider withIdentifier:UTTypeWebP.identifier]; - - [self saveImageToPath:result]; + NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"gifImage" + withExtension:@"gif"]; + NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; + PHPickerResult *result = [self createPickerResult:itemProvider + withIdentifier:UTTypeWebP.identifier]; + + [self saveImageToPath:result]; } -- (PHPickerResult *)createPickerResult:(NSItemProvider*)itemProvider withIdentifier:(NSString*)identifier API_AVAILABLE(ios(14)) { - PHPickerResult *result = OCMClassMock([PHPickerResult class]); - - OCMStub([result itemProvider]).andReturn(itemProvider); - OCMStub([result assetIdentifier]).andReturn(identifier); - - return result; +- (PHPickerResult *)createPickerResult:(NSItemProvider *)itemProvider + withIdentifier:(NSString *)identifier API_AVAILABLE(ios(14)) { + PHPickerResult *result = OCMClassMock([PHPickerResult class]); + + OCMStub([result itemProvider]).andReturn(itemProvider); + OCMStub([result assetIdentifier]).andReturn(identifier); + + return result; } - (void)saveImageToPath:(PHPickerResult *)result API_AVAILABLE(ios(14)) { - XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"]; - - FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] - initWithResult:result - maxHeight:@100 - maxWidth:@100 - desiredImageQuality:@100 - savedPathBlock:^(NSString *savedPath) { - if ([[NSFileManager defaultManager] fileExistsAtPath:savedPath]) { - [pathExpectation fulfill]; - } - }]; - - [operation start]; - [self waitForExpectations:@[pathExpectation] timeout:30]; + XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"]; + + FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] + initWithResult:result + maxHeight:@100 + maxWidth:@100 + desiredImageQuality:@100 + savedPathBlock:^(NSString *savedPath) { + if ([[NSFileManager defaultManager] fileExistsAtPath:savedPath]) { + [pathExpectation fulfill]; + } + }]; + + [operation start]; + [self waitForExpectations:@[ pathExpectation ] timeout:30]; } @end diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m index 684efe71620e..df87e380f35b 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m @@ -84,59 +84,63 @@ - (void)start { } if (@available(iOS 14, *)) { [self setExecuting:YES]; - + if ([self.result.itemProvider hasItemConformingToTypeIdentifier:UTTypeWebP.identifier]) { - [self.result.itemProvider loadDataRepresentationForTypeIdentifier:UTTypeWebP.identifier completionHandler:^(NSData * _Nullable data, NSError * _Nullable error) { - UIImage *image = [[UIImage alloc] initWithData:data]; - [self processImage:image]; - }]; - return; + [self.result.itemProvider + loadDataRepresentationForTypeIdentifier:UTTypeWebP.identifier + completionHandler:^(NSData *_Nullable data, + NSError *_Nullable error) { + UIImage *image = [[UIImage alloc] initWithData:data]; + [self processImage:image]; + }]; + return; } - - [self.result.itemProvider loadObjectOfClass:[UIImage class] completionHandler:^(__kindof id _Nullable image, NSError *_Nullable error) { - if ([image isKindOfClass:[UIImage class]]) { + + [self.result.itemProvider + loadObjectOfClass:[UIImage class] + completionHandler:^(__kindof id _Nullable image, + NSError *_Nullable error) { + if ([image isKindOfClass:[UIImage class]]) { [self processImage:image]; - } - }]; + } + }]; } else { [self setFinished:YES]; } } - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { - PHAsset *originalAsset = - [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; - - if (self.maxWidth != (id)[NSNull null] || self.maxHeight != (id)[NSNull null]) { - localImage = [FLTImagePickerImageUtil scaledImage:localImage - maxWidth:self.maxWidth - maxHeight:self.maxHeight - isMetadataAvailable:originalAsset != nil]; - } - if (!originalAsset) { - // Image picked without an original asset (e.g. User pick image without permission) - NSString *savedPath = + PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; + + if (self.maxWidth != (id)[NSNull null] || self.maxHeight != (id)[NSNull null]) { + localImage = [FLTImagePickerImageUtil scaledImage:localImage + maxWidth:self.maxWidth + maxHeight:self.maxHeight + isMetadataAvailable:originalAsset != nil]; + } + if (!originalAsset) { + // Image picked without an original asset (e.g. User pick image without permission) + NSString *savedPath = [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil image:localImage imageQuality:self.desiredImageQuality]; - [self completeOperationWithPath:savedPath]; - } else { - [[PHImageManager defaultManager] - requestImageDataForAsset:originalAsset - options:nil - resultHandler:^( - NSData *_Nullable imageData, NSString *_Nullable dataUTI, - UIImageOrientation orientation, NSDictionary *_Nullable info) { - // maxWidth and maxHeight are used only for GIF images. - NSString* savedPath = [FLTImagePickerPhotoAssetUtil - saveImageWithOriginalImageData:imageData - image:localImage - maxWidth:self.maxWidth - maxHeight:self.maxHeight - imageQuality:self.desiredImageQuality]; - [self completeOperationWithPath:savedPath]; - }]; - } + [self completeOperationWithPath:savedPath]; + } else { + [[PHImageManager defaultManager] + requestImageDataForAsset:originalAsset + options:nil + resultHandler:^(NSData *_Nullable imageData, NSString *_Nullable dataUTI, + UIImageOrientation orientation, NSDictionary *_Nullable info) { + // maxWidth and maxHeight are used only for GIF images. + NSString *savedPath = [FLTImagePickerPhotoAssetUtil + saveImageWithOriginalImageData:imageData + image:localImage + maxWidth:self.maxWidth + maxHeight:self.maxHeight + imageQuality:self.desiredImageQuality]; + [self completeOperationWithPath:savedPath]; + }]; + } } @end From 96e358d4ea8225d232a15650702d39f307c02158 Mon Sep 17 00:00:00 2001 From: Tran Giang Long Date: Sat, 22 Jan 2022 03:38:20 +0300 Subject: [PATCH 08/16] improve method name and add documentation --- .../image_picker/image_picker/CHANGELOG.md | 4 +- .../PickerSaveImageToPathOperationTests.m | 44 ++++++++++++------- .../ios/Classes/FLTImagePickerPlugin.m | 37 +++++++++++----- .../FLTPHPickerSaveImageToPathOperation.h | 3 +- .../FLTPHPickerSaveImageToPathOperation.m | 42 ++++++++++++------ 5 files changed, 89 insertions(+), 41 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index c95397d0a6c5..28ae49487a3f 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,6 +1,6 @@ -## 0.8.4+4 +## 0.8.5 -* Support adding WebP for iOS +* iOS: allow picking images with WebP format. ## 0.8.4+3 diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m index 7f1465713b55..b11e6c252e36 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -18,44 +18,50 @@ - (void)testSaveWebPImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"webpImage" withExtension:@"webp"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider - withIdentifier:UTTypeWebP.identifier]; + PHPickerResult *result = [self createPickerResultWithProvider:itemProvider + withIdentifier:UTTypeWebP.identifier]; - [self saveImageToPath:result]; + [self verifySavingImageWithPickerResult:result]; } - (void)testSavePNGImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"pngImage" withExtension:@"png"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider - withIdentifier:UTTypeWebP.identifier]; + PHPickerResult *result = [self createPickerResultWithProvider:itemProvider + withIdentifier:UTTypeWebP.identifier]; - [self saveImageToPath:result]; + [self verifySavingImageWithPickerResult:result]; } - (void)testSaveJPGImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"jpgImage" withExtension:@"jpg"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider - withIdentifier:UTTypeWebP.identifier]; + PHPickerResult *result = [self createPickerResultWithProvider:itemProvider + withIdentifier:UTTypeWebP.identifier]; - [self saveImageToPath:result]; + [self verifySavingImageWithPickerResult:result]; } - (void)testSaveGIFImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"gifImage" withExtension:@"gif"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider - withIdentifier:UTTypeWebP.identifier]; + PHPickerResult *result = [self createPickerResultWithProvider:itemProvider + withIdentifier:UTTypeWebP.identifier]; - [self saveImageToPath:result]; + [self verifySavingImageWithPickerResult:result]; } -- (PHPickerResult *)createPickerResult:(NSItemProvider *)itemProvider - withIdentifier:(NSString *)identifier API_AVAILABLE(ios(14)) { +/** + * Create a mock picker result using NSItemProvider. + * + * @param itemProvider an item provider that will be used as picker result + * @param identifier local identifier of the asset + */ +- (PHPickerResult *)createPickerResultWithProvider:(NSItemProvider *)itemProvider + withIdentifier:(NSString *)identifier API_AVAILABLE(ios(14)) { PHPickerResult *result = OCMClassMock([PHPickerResult class]); OCMStub([result itemProvider]).andReturn(itemProvider); @@ -64,7 +70,15 @@ - (PHPickerResult *)createPickerResult:(NSItemProvider *)itemProvider return result; } -- (void)saveImageToPath:(PHPickerResult *)result API_AVAILABLE(ios(14)) { +/** + * Validate a saving process of FLTPHPickerSaveImageToPathOperation. + * + * FLTPHPickerSaveImageToPathOperation is responsible for saving a picked image to the disk for + * later use. It is expected that the saving is always successful. + * + * @param result the picker result + */ +- (void)verifySavingImageWithPickerResult:(PHPickerResult *)result API_AVAILABLE(ios(14)) { XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"]; FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index cf3103195482..47cc8069da33 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -402,23 +402,27 @@ - (void)picker:(PHPickerViewController *)picker NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; NSNumber *desiredImageQuality = [self getDesiredImageQuality:imageQuality]; NSOperationQueue *operationQueue = [NSOperationQueue new]; - NSMutableArray *pathList = [self createNSMutableArrayWithSize:results.count]; + NSMutableArray *pickResult = [self createNSMutableArrayWithSize:results.count]; for (int i = 0; i < results.count; i++) { PHPickerResult *result = results[i]; - FLTPHPickerSaveImageToPathOperation *operation = - [[FLTPHPickerSaveImageToPathOperation alloc] initWithResult:result - maxHeight:maxHeight - maxWidth:maxWidth - desiredImageQuality:desiredImageQuality - savedPathBlock:^(NSString *savedPath) { - pathList[i] = savedPath; - }]; + FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] + initWithResult:result + maxHeight:maxHeight + maxWidth:maxWidth + desiredImageQuality:desiredImageQuality + savedPathBlock:^(NSString *savedPath, NSError *error) { + if (error == nil) { + pickResult[i] = savedPath; + } else { + pickResult[i] = error; + } + }]; [operationQueue addOperation:operation]; } [operationQueue waitUntilAllOperationsAreFinished]; dispatch_async(dispatch_get_main_queue(), ^{ - [self handleSavedPathList:pathList]; + [self handleSavedPathList:pickResult]; }); }); } @@ -567,6 +571,19 @@ - (void)handleSavedPathList:(NSArray *)pathList { if (pathList) { if (![pathList containsObject:[NSNull null]]) { + NSMutableArray *formattedPathList = [[NSMutableArray alloc] initWithCapacity:pathList.count]; + for (int x = 0; x < pathList.count; x++) { + if ([pathList[x] isKindOfClass:[NSString class]]) { + formattedPathList[x] = @{ + @"type" : @"path", + @"value" : pathList[x], + }; + } else if ([pathList[x] isKindOfClass:[NSError class]]) { + formattedPathList[x] = + @{@"type" : @"error", @"value" : ((NSError *)pathList[x]).localizedDescription}; + } + } + if ((self.maxImagesAllowed == 1)) { self.result(pathList.firstObject); } else { diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h index 7ba3d28ef3dd..d5a78200abef 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h @@ -26,6 +26,7 @@ maxHeight:(NSNumber *)maxHeight maxWidth:(NSNumber *)maxWidth desiredImageQuality:(NSNumber *)desiredImageQuality - savedPathBlock:(void (^)(NSString *))savedPathBlock API_AVAILABLE(ios(14)); + savedPathBlock:(void (^)(NSString *, NSError *))savedPathBlock + API_AVAILABLE(ios(14)); @end diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m index df87e380f35b..303bc9b9c099 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m @@ -16,7 +16,7 @@ @interface FLTPHPickerSaveImageToPathOperation () @end -typedef void (^GetSavedPath)(NSString *); +typedef void (^GetSavedPath)(NSString *, NSError *Error); @implementation FLTPHPickerSaveImageToPathOperation { BOOL executing; @@ -74,7 +74,13 @@ - (void)setExecuting:(BOOL)isExecuting { - (void)completeOperationWithPath:(NSString *)savedPath { [self setExecuting:NO]; [self setFinished:YES]; - getSavedPath(savedPath); + getSavedPath(savedPath, nil); +} + +- (void)terminateOperationWithError:(NSError *)error { + [self setExecuting:NO]; + [self setFinished:YES]; + getSavedPath(nil, error); } - (void)start { @@ -90,8 +96,13 @@ - (void)start { loadDataRepresentationForTypeIdentifier:UTTypeWebP.identifier completionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { - UIImage *image = [[UIImage alloc] initWithData:data]; - [self processImage:image]; + if (error != nil) { + [self terminateOperationWithError:error]; + return; + } else { + UIImage *image = [[UIImage alloc] initWithData:data]; + [self processImage:image]; + } }]; return; } @@ -100,7 +111,9 @@ - (void)start { loadObjectOfClass:[UIImage class] completionHandler:^(__kindof id _Nullable image, NSError *_Nullable error) { - if ([image isKindOfClass:[UIImage class]]) { + if (error != nil) { + [self terminateOperationWithError:error]; + } else if ([image isKindOfClass:[UIImage class]]) { [self processImage:image]; } }]; @@ -109,6 +122,9 @@ - (void)start { } } +/* + * This method processes the image and save it to the file. + */ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; @@ -118,14 +134,7 @@ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { maxHeight:self.maxHeight isMetadataAvailable:originalAsset != nil]; } - if (!originalAsset) { - // Image picked without an original asset (e.g. User pick image without permission) - NSString *savedPath = - [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil - image:localImage - imageQuality:self.desiredImageQuality]; - [self completeOperationWithPath:savedPath]; - } else { + if (originalAsset) { [[PHImageManager defaultManager] requestImageDataForAsset:originalAsset options:nil @@ -140,6 +149,13 @@ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { imageQuality:self.desiredImageQuality]; [self completeOperationWithPath:savedPath]; }]; + } else { + // Image picked without an original asset (e.g. User pick image without permission) + NSString *savedPath = + [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil + image:localImage + imageQuality:self.desiredImageQuality]; + [self completeOperationWithPath:savedPath]; } } From 6dcb8a9f0c07c9a366a95813226d9a7588086e3a Mon Sep 17 00:00:00 2001 From: Giang Long Tran Date: Tue, 1 Feb 2022 22:51:14 +0300 Subject: [PATCH 09/16] fix changelog --- packages/image_picker/image_picker/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index 28ae49487a3f..a4a2e14ccc72 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,6 +1,6 @@ ## 0.8.5 -* iOS: allow picking images with WebP format. +* iOS: allows picking images with WebP format. ## 0.8.4+3 From c28ccf72e9cf186440f5c12baee7f64912f4d1c3 Mon Sep 17 00:00:00 2001 From: Giang Long Tran Date: Tue, 1 Feb 2022 22:53:34 +0300 Subject: [PATCH 10/16] revert FLTImagePickerPlugin --- .../image_picker/ios/Classes/FLTImagePickerPlugin.m | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 47cc8069da33..096204938b88 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -571,19 +571,6 @@ - (void)handleSavedPathList:(NSArray *)pathList { if (pathList) { if (![pathList containsObject:[NSNull null]]) { - NSMutableArray *formattedPathList = [[NSMutableArray alloc] initWithCapacity:pathList.count]; - for (int x = 0; x < pathList.count; x++) { - if ([pathList[x] isKindOfClass:[NSString class]]) { - formattedPathList[x] = @{ - @"type" : @"path", - @"value" : pathList[x], - }; - } else if ([pathList[x] isKindOfClass:[NSError class]]) { - formattedPathList[x] = - @{@"type" : @"error", @"value" : ((NSError *)pathList[x]).localizedDescription}; - } - } - if ((self.maxImagesAllowed == 1)) { self.result(pathList.firstObject); } else { From 864e5dbe1fec31e8900bfbf77b5c5766da397bb2 Mon Sep 17 00:00:00 2001 From: Giang Long Tran Date: Tue, 1 Feb 2022 23:46:59 +0300 Subject: [PATCH 11/16] revert --- .../image_picker/image_picker/CHANGELOG.md | 2 +- .../PickerSaveImageToPathOperationTests.m | 44 +++++++------------ .../ios/Classes/FLTImagePickerPlugin.m | 24 +++++----- .../FLTPHPickerSaveImageToPathOperation.h | 3 +- .../FLTPHPickerSaveImageToPathOperation.m | 42 ++++++------------ 5 files changed, 40 insertions(+), 75 deletions(-) diff --git a/packages/image_picker/image_picker/CHANGELOG.md b/packages/image_picker/image_picker/CHANGELOG.md index a4a2e14ccc72..056e334c305b 100644 --- a/packages/image_picker/image_picker/CHANGELOG.md +++ b/packages/image_picker/image_picker/CHANGELOG.md @@ -1,4 +1,4 @@ -## 0.8.5 +## 0.8.4+4 * iOS: allows picking images with WebP format. diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m index b11e6c252e36..7f1465713b55 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -18,50 +18,44 @@ - (void)testSaveWebPImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"webpImage" withExtension:@"webp"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResultWithProvider:itemProvider - withIdentifier:UTTypeWebP.identifier]; + PHPickerResult *result = [self createPickerResult:itemProvider + withIdentifier:UTTypeWebP.identifier]; - [self verifySavingImageWithPickerResult:result]; + [self saveImageToPath:result]; } - (void)testSavePNGImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"pngImage" withExtension:@"png"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResultWithProvider:itemProvider - withIdentifier:UTTypeWebP.identifier]; + PHPickerResult *result = [self createPickerResult:itemProvider + withIdentifier:UTTypeWebP.identifier]; - [self verifySavingImageWithPickerResult:result]; + [self saveImageToPath:result]; } - (void)testSaveJPGImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"jpgImage" withExtension:@"jpg"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResultWithProvider:itemProvider - withIdentifier:UTTypeWebP.identifier]; + PHPickerResult *result = [self createPickerResult:itemProvider + withIdentifier:UTTypeWebP.identifier]; - [self verifySavingImageWithPickerResult:result]; + [self saveImageToPath:result]; } - (void)testSaveGIFImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"gifImage" withExtension:@"gif"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResultWithProvider:itemProvider - withIdentifier:UTTypeWebP.identifier]; + PHPickerResult *result = [self createPickerResult:itemProvider + withIdentifier:UTTypeWebP.identifier]; - [self verifySavingImageWithPickerResult:result]; + [self saveImageToPath:result]; } -/** - * Create a mock picker result using NSItemProvider. - * - * @param itemProvider an item provider that will be used as picker result - * @param identifier local identifier of the asset - */ -- (PHPickerResult *)createPickerResultWithProvider:(NSItemProvider *)itemProvider - withIdentifier:(NSString *)identifier API_AVAILABLE(ios(14)) { +- (PHPickerResult *)createPickerResult:(NSItemProvider *)itemProvider + withIdentifier:(NSString *)identifier API_AVAILABLE(ios(14)) { PHPickerResult *result = OCMClassMock([PHPickerResult class]); OCMStub([result itemProvider]).andReturn(itemProvider); @@ -70,15 +64,7 @@ - (PHPickerResult *)createPickerResultWithProvider:(NSItemProvider *)itemProvide return result; } -/** - * Validate a saving process of FLTPHPickerSaveImageToPathOperation. - * - * FLTPHPickerSaveImageToPathOperation is responsible for saving a picked image to the disk for - * later use. It is expected that the saving is always successful. - * - * @param result the picker result - */ -- (void)verifySavingImageWithPickerResult:(PHPickerResult *)result API_AVAILABLE(ios(14)) { +- (void)saveImageToPath:(PHPickerResult *)result API_AVAILABLE(ios(14)) { XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"]; FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] diff --git a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m index 096204938b88..cf3103195482 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTImagePickerPlugin.m @@ -402,27 +402,23 @@ - (void)picker:(PHPickerViewController *)picker NSNumber *imageQuality = [self->_arguments objectForKey:@"imageQuality"]; NSNumber *desiredImageQuality = [self getDesiredImageQuality:imageQuality]; NSOperationQueue *operationQueue = [NSOperationQueue new]; - NSMutableArray *pickResult = [self createNSMutableArrayWithSize:results.count]; + NSMutableArray *pathList = [self createNSMutableArrayWithSize:results.count]; for (int i = 0; i < results.count; i++) { PHPickerResult *result = results[i]; - FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] - initWithResult:result - maxHeight:maxHeight - maxWidth:maxWidth - desiredImageQuality:desiredImageQuality - savedPathBlock:^(NSString *savedPath, NSError *error) { - if (error == nil) { - pickResult[i] = savedPath; - } else { - pickResult[i] = error; - } - }]; + FLTPHPickerSaveImageToPathOperation *operation = + [[FLTPHPickerSaveImageToPathOperation alloc] initWithResult:result + maxHeight:maxHeight + maxWidth:maxWidth + desiredImageQuality:desiredImageQuality + savedPathBlock:^(NSString *savedPath) { + pathList[i] = savedPath; + }]; [operationQueue addOperation:operation]; } [operationQueue waitUntilAllOperationsAreFinished]; dispatch_async(dispatch_get_main_queue(), ^{ - [self handleSavedPathList:pickResult]; + [self handleSavedPathList:pathList]; }); }); } diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h index d5a78200abef..7ba3d28ef3dd 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.h @@ -26,7 +26,6 @@ maxHeight:(NSNumber *)maxHeight maxWidth:(NSNumber *)maxWidth desiredImageQuality:(NSNumber *)desiredImageQuality - savedPathBlock:(void (^)(NSString *, NSError *))savedPathBlock - API_AVAILABLE(ios(14)); + savedPathBlock:(void (^)(NSString *))savedPathBlock API_AVAILABLE(ios(14)); @end diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m index 303bc9b9c099..df87e380f35b 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m @@ -16,7 +16,7 @@ @interface FLTPHPickerSaveImageToPathOperation () @end -typedef void (^GetSavedPath)(NSString *, NSError *Error); +typedef void (^GetSavedPath)(NSString *); @implementation FLTPHPickerSaveImageToPathOperation { BOOL executing; @@ -74,13 +74,7 @@ - (void)setExecuting:(BOOL)isExecuting { - (void)completeOperationWithPath:(NSString *)savedPath { [self setExecuting:NO]; [self setFinished:YES]; - getSavedPath(savedPath, nil); -} - -- (void)terminateOperationWithError:(NSError *)error { - [self setExecuting:NO]; - [self setFinished:YES]; - getSavedPath(nil, error); + getSavedPath(savedPath); } - (void)start { @@ -96,13 +90,8 @@ - (void)start { loadDataRepresentationForTypeIdentifier:UTTypeWebP.identifier completionHandler:^(NSData *_Nullable data, NSError *_Nullable error) { - if (error != nil) { - [self terminateOperationWithError:error]; - return; - } else { - UIImage *image = [[UIImage alloc] initWithData:data]; - [self processImage:image]; - } + UIImage *image = [[UIImage alloc] initWithData:data]; + [self processImage:image]; }]; return; } @@ -111,9 +100,7 @@ - (void)start { loadObjectOfClass:[UIImage class] completionHandler:^(__kindof id _Nullable image, NSError *_Nullable error) { - if (error != nil) { - [self terminateOperationWithError:error]; - } else if ([image isKindOfClass:[UIImage class]]) { + if ([image isKindOfClass:[UIImage class]]) { [self processImage:image]; } }]; @@ -122,9 +109,6 @@ - (void)start { } } -/* - * This method processes the image and save it to the file. - */ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; @@ -134,7 +118,14 @@ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { maxHeight:self.maxHeight isMetadataAvailable:originalAsset != nil]; } - if (originalAsset) { + if (!originalAsset) { + // Image picked without an original asset (e.g. User pick image without permission) + NSString *savedPath = + [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil + image:localImage + imageQuality:self.desiredImageQuality]; + [self completeOperationWithPath:savedPath]; + } else { [[PHImageManager defaultManager] requestImageDataForAsset:originalAsset options:nil @@ -149,13 +140,6 @@ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { imageQuality:self.desiredImageQuality]; [self completeOperationWithPath:savedPath]; }]; - } else { - // Image picked without an original asset (e.g. User pick image without permission) - NSString *savedPath = - [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil - image:localImage - imageQuality:self.desiredImageQuality]; - [self completeOperationWithPath:savedPath]; } } From 5839c19a9c40ae2f19a1a4e95b56342d2ad4126b Mon Sep 17 00:00:00 2001 From: Giang Long Tran Date: Tue, 1 Feb 2022 23:53:09 +0300 Subject: [PATCH 12/16] improve method name and add documentation --- .../PickerSaveImageToPathOperationTests.m | 34 +++++++++++++------ .../FLTPHPickerSaveImageToPathOperation.m | 19 ++++++----- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m index 7f1465713b55..43cc360d729f 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -18,43 +18,49 @@ - (void)testSaveWebPImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"webpImage" withExtension:@"webp"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider + PHPickerResult *result = [self createPickerResultWithProvider:itemProvider withIdentifier:UTTypeWebP.identifier]; - [self saveImageToPath:result]; + [self verifySavingImageWithPickerResult:result]; } - (void)testSavePNGImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"pngImage" withExtension:@"png"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider + PHPickerResult *result = [self createPickerResultWithProvider:itemProvider withIdentifier:UTTypeWebP.identifier]; - [self saveImageToPath:result]; + [self verifySavingImageWithPickerResult:result]; } - (void)testSaveJPGImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"jpgImage" withExtension:@"jpg"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider + PHPickerResult *result = [self createPickerResultWithProvider:itemProvider withIdentifier:UTTypeWebP.identifier]; - [self saveImageToPath:result]; + [self verifySavingImageWithPickerResult:result]; } - (void)testSaveGIFImage API_AVAILABLE(ios(14)) { NSURL *imageURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"gifImage" withExtension:@"gif"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; - PHPickerResult *result = [self createPickerResult:itemProvider + PHPickerResult *result = [self createPickerResultWithProvider:itemProvider withIdentifier:UTTypeWebP.identifier]; - [self saveImageToPath:result]; + [self verifySavingImageWithPickerResult:result]; } -- (PHPickerResult *)createPickerResult:(NSItemProvider *)itemProvider +/** + * Create a mock picker result using NSItemProvider. + * + * @param itemProvider an item provider that will be used as picker result + * @param identifier local identifier of the asset + */ +- (PHPickerResult *)createPickerResultWithProvider:(NSItemProvider *)itemProvider withIdentifier:(NSString *)identifier API_AVAILABLE(ios(14)) { PHPickerResult *result = OCMClassMock([PHPickerResult class]); @@ -64,7 +70,15 @@ - (PHPickerResult *)createPickerResult:(NSItemProvider *)itemProvider return result; } -- (void)saveImageToPath:(PHPickerResult *)result API_AVAILABLE(ios(14)) { +/** + * Validate a saving process of FLTPHPickerSaveImageToPathOperation. + * + * FLTPHPickerSaveImageToPathOperation is responsible for saving a picked image to the disk for + * later use. It is expected that the saving is always successful. + * + * @param result the picker result + */ +- (void)verifySavingImageWithPickerResult:(PHPickerResult *)result API_AVAILABLE(ios(14)) { XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"]; FLTPHPickerSaveImageToPathOperation *operation = [[FLTPHPickerSaveImageToPathOperation alloc] diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m index df87e380f35b..fc28c56a2a43 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m @@ -109,6 +109,9 @@ - (void)start { } } +/* + * This method processes the image and save it to the file. + */ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; @@ -118,14 +121,7 @@ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { maxHeight:self.maxHeight isMetadataAvailable:originalAsset != nil]; } - if (!originalAsset) { - // Image picked without an original asset (e.g. User pick image without permission) - NSString *savedPath = - [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil - image:localImage - imageQuality:self.desiredImageQuality]; - [self completeOperationWithPath:savedPath]; - } else { + if (originalAsset) { [[PHImageManager defaultManager] requestImageDataForAsset:originalAsset options:nil @@ -140,6 +136,13 @@ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { imageQuality:self.desiredImageQuality]; [self completeOperationWithPath:savedPath]; }]; + } else { + // Image picked without an original asset (e.g. User pick image without permission) + NSString *savedPath = + [FLTImagePickerPhotoAssetUtil saveImageWithPickerInfo:nil + image:localImage + imageQuality:self.desiredImageQuality]; + [self completeOperationWithPath:savedPath]; } } From 479d6b678e90fef9484d39b520d52623e8ea86b5 Mon Sep 17 00:00:00 2001 From: Giang Long Tran Date: Wed, 9 Feb 2022 01:17:40 +0300 Subject: [PATCH 13/16] fix --- .../ios/RunnerTests/PickerSaveImageToPathOperationTests.m | 4 ++-- .../ios/Classes/FLTPHPickerSaveImageToPathOperation.m | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m index 43cc360d729f..b2cbf772b9b7 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -55,7 +55,7 @@ - (void)testSaveGIFImage API_AVAILABLE(ios(14)) { } /** - * Create a mock picker result using NSItemProvider. + * Creates a mock picker result using NSItemProvider. * * @param itemProvider an item provider that will be used as picker result * @param identifier local identifier of the asset @@ -71,7 +71,7 @@ - (PHPickerResult *)createPickerResultWithProvider:(NSItemProvider *)itemProvide } /** - * Validate a saving process of FLTPHPickerSaveImageToPathOperation. + * Validates a saving process of FLTPHPickerSaveImageToPathOperation. * * FLTPHPickerSaveImageToPathOperation is responsible for saving a picked image to the disk for * later use. It is expected that the saving is always successful. diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m index fc28c56a2a43..4e164f13f641 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m @@ -109,8 +109,8 @@ - (void)start { } } -/* - * This method processes the image and save it to the file. +/** + * Processes the image. */ - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; From 16ae49b6e37dcc26b4c8951538122575c2ee17df Mon Sep 17 00:00:00 2001 From: Giang Long Tran Date: Fri, 11 Feb 2022 01:45:02 +0300 Subject: [PATCH 14/16] fix code style --- .../PickerSaveImageToPathOperationTests.m | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m index b2cbf772b9b7..f77f82a34159 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -19,7 +19,7 @@ - (void)testSaveWebPImage API_AVAILABLE(ios(14)) { withExtension:@"webp"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; PHPickerResult *result = [self createPickerResultWithProvider:itemProvider - withIdentifier:UTTypeWebP.identifier]; + withIdentifier:UTTypeWebP.identifier]; [self verifySavingImageWithPickerResult:result]; } @@ -29,7 +29,7 @@ - (void)testSavePNGImage API_AVAILABLE(ios(14)) { withExtension:@"png"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; PHPickerResult *result = [self createPickerResultWithProvider:itemProvider - withIdentifier:UTTypeWebP.identifier]; + withIdentifier:UTTypeWebP.identifier]; [self verifySavingImageWithPickerResult:result]; } @@ -39,7 +39,7 @@ - (void)testSaveJPGImage API_AVAILABLE(ios(14)) { withExtension:@"jpg"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; PHPickerResult *result = [self createPickerResultWithProvider:itemProvider - withIdentifier:UTTypeWebP.identifier]; + withIdentifier:UTTypeWebP.identifier]; [self verifySavingImageWithPickerResult:result]; } @@ -49,19 +49,19 @@ - (void)testSaveGIFImage API_AVAILABLE(ios(14)) { withExtension:@"gif"]; NSItemProvider *itemProvider = [[NSItemProvider alloc] initWithContentsOfURL:imageURL]; PHPickerResult *result = [self createPickerResultWithProvider:itemProvider - withIdentifier:UTTypeWebP.identifier]; + withIdentifier:UTTypeWebP.identifier]; [self verifySavingImageWithPickerResult:result]; } /** - * Creates a mock picker result using NSItemProvider. - * - * @param itemProvider an item provider that will be used as picker result - * @param identifier local identifier of the asset - */ + * Creates a mock picker result using NSItemProvider. + * + * @param itemProvider an item provider that will be used as picker result + * @param identifier local identifier of the asset + */ - (PHPickerResult *)createPickerResultWithProvider:(NSItemProvider *)itemProvider - withIdentifier:(NSString *)identifier API_AVAILABLE(ios(14)) { + withIdentifier:(NSString *)identifier API_AVAILABLE(ios(14)) { PHPickerResult *result = OCMClassMock([PHPickerResult class]); OCMStub([result itemProvider]).andReturn(itemProvider); @@ -71,13 +71,13 @@ - (PHPickerResult *)createPickerResultWithProvider:(NSItemProvider *)itemProvide } /** - * Validates a saving process of FLTPHPickerSaveImageToPathOperation. - * - * FLTPHPickerSaveImageToPathOperation is responsible for saving a picked image to the disk for - * later use. It is expected that the saving is always successful. - * - * @param result the picker result - */ + * Validates a saving process of FLTPHPickerSaveImageToPathOperation. + * + * FLTPHPickerSaveImageToPathOperation is responsible for saving a picked image to the disk for + * later use. It is expected that the saving is always successful. + * + * @param result the picker result + */ - (void)verifySavingImageWithPickerResult:(PHPickerResult *)result API_AVAILABLE(ios(14)) { XCTestExpectation *pathExpectation = [self expectationWithDescription:@"Path was created"]; From b283bf7ae2177262888edb2f5f7557e5ed00e603 Mon Sep 17 00:00:00 2001 From: Giang Long Tran Date: Fri, 11 Feb 2022 01:57:04 +0300 Subject: [PATCH 15/16] fix null checking --- .../ios/Classes/FLTPHPickerSaveImageToPathOperation.m | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m index 4e164f13f641..9e7e7e87a30c 100644 --- a/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m +++ b/packages/image_picker/image_picker/ios/Classes/FLTPHPickerSaveImageToPathOperation.m @@ -115,7 +115,7 @@ - (void)start { - (void)processImage:(UIImage *)localImage API_AVAILABLE(ios(14)) { PHAsset *originalAsset = [FLTImagePickerPhotoAssetUtil getAssetFromPHPickerResult:self.result]; - if (self.maxWidth != (id)[NSNull null] || self.maxHeight != (id)[NSNull null]) { + if (self.maxWidth != nil || self.maxHeight != nil) { localImage = [FLTImagePickerImageUtil scaledImage:localImage maxWidth:self.maxWidth maxHeight:self.maxHeight From 3e9d37214d9df77879221f2c12f3bdde9d69a8eb Mon Sep 17 00:00:00 2001 From: Giang Long Tran Date: Fri, 11 Feb 2022 02:45:24 +0300 Subject: [PATCH 16/16] fix test --- .../ios/RunnerTests/PickerSaveImageToPathOperationTests.m | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m index f77f82a34159..f94db83d5696 100644 --- a/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m +++ b/packages/image_picker/image_picker/example/ios/RunnerTests/PickerSaveImageToPathOperationTests.m @@ -4,9 +4,10 @@ #import #import -#import @import image_picker; +@import image_picker.Test; +@import XCTest; @interface PickerSaveImageToPathOperationTests : XCTestCase