From fa3a42b6a886eb0fc479ae65d2fd183db5fe8b0a Mon Sep 17 00:00:00 2001 From: Trancever Date: Thu, 30 May 2019 19:29:44 +0200 Subject: [PATCH 1/2] feat: use own implementation to save image on ios --- ios/RNCFileSystem.h | 22 +++++++++++ ios/RNCFileSystem.m | 40 ++++++++++++++++++++ ios/RNCImageEditor.m | 19 +++++----- ios/RNCImageEditor.xcodeproj/project.pbxproj | 12 ++++++ ios/RNCImageUtils.h | 21 ++++++++++ ios/RNCImageUtils.m | 20 ++++++++++ 6 files changed, 124 insertions(+), 10 deletions(-) create mode 100644 ios/RNCFileSystem.h create mode 100644 ios/RNCFileSystem.m create mode 100644 ios/RNCImageUtils.h create mode 100644 ios/RNCImageUtils.m diff --git a/ios/RNCFileSystem.h b/ios/RNCFileSystem.h new file mode 100644 index 0000000..ab5a50e --- /dev/null +++ b/ios/RNCFileSystem.h @@ -0,0 +1,22 @@ +// +// RNFileSystem.h +// RNCImageEditor +// +// Created by Dawid Urbaniak on 30/05/2019. +// Copyright © 2019 Facebook. All rights reserved. +// + +#ifndef RNCFileSystem_h +#define RNCFileSystem_h + +#import + +@interface RNCFileSystem : NSObject + ++ (BOOL)ensureDirExistsWithPath:(NSString *)path; ++ (NSString *)generatePathInDirectory:(NSString *)directory withExtension:(NSString *)extension; ++ (NSString *)cacheDirectoryPath; + +@end + +#endif /* RNCFileSystem_h */ diff --git a/ios/RNCFileSystem.m b/ios/RNCFileSystem.m new file mode 100644 index 0000000..d7ee5c5 --- /dev/null +++ b/ios/RNCFileSystem.m @@ -0,0 +1,40 @@ +// +// RNFileSystem.m +// RNCImageEditor +// +// Created by Dawid Urbaniak on 30/05/2019. +// Copyright © 2019 Facebook. All rights reserved. +// + +#import "RNCFileSystem.h" + +@implementation RNCFileSystem + ++ (BOOL)ensureDirExistsWithPath:(NSString *)path +{ + BOOL isDir = NO; + NSError *error; + BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:path isDirectory:&isDir]; + if (!(exists && isDir)) { + [[NSFileManager defaultManager] createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:&error]; + if (error) { + return NO; + } + } + return YES; +} + ++ (NSString *)generatePathInDirectory:(NSString *)directory withExtension:(NSString *)extension +{ + NSString *fileName = [[[NSUUID UUID] UUIDString] stringByAppendingString:extension]; + [RNCFileSystem ensureDirExistsWithPath:directory]; + return [directory stringByAppendingPathComponent:fileName]; +} + ++ (NSString *)cacheDirectoryPath +{ + NSArray *array = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); + return [array objectAtIndex:0]; +} + +@end diff --git a/ios/RNCImageEditor.m b/ios/RNCImageEditor.m index ec9979a..a674005 100644 --- a/ios/RNCImageEditor.m +++ b/ios/RNCImageEditor.m @@ -15,6 +15,8 @@ #import #import +#import "RNCFileSystem.h" +#import "RNCImageUtils.h" #if __has_include() #import #else @@ -28,7 +30,7 @@ @implementation RNCImageEditor @synthesize bridge = _bridge; /** - * Crops an image and adds the result to the image store. + * Crops an image and saves the result to temporary file. * * @param imageRequest An image URL * @param cropData Dictionary with `offset`, `size` and `displaySize`. @@ -69,15 +71,12 @@ @implementation RNCImageEditor } // Store image - [self->_bridge.imageStoreManager storeImage:croppedImage withBlock:^(NSString *croppedImageTag) { - if (!croppedImageTag) { - NSString *errorMessage = @"Error storing cropped image in RCTImageStoreManager"; - RCTLogWarn(@"%@", errorMessage); - errorCallback(RCTErrorWithMessage(errorMessage)); - return; - } - successCallback(@[croppedImageTag]); - }]; + NSString *path = [RNCFileSystem generatePathInDirectory:[[RNCFileSystem cacheDirectoryPath] stringByAppendingPathComponent:@"ReactNative_cropped_image_"] withExtension:@".jpg"]; + + NSData *imageData = UIImageJPEGRepresentation(croppedImage, 1); + NSString *uri = [RNCImageUtils writeImage:imageData toPath:path]; + + successCallback(@[uri]); }]; } diff --git a/ios/RNCImageEditor.xcodeproj/project.pbxproj b/ios/RNCImageEditor.xcodeproj/project.pbxproj index b89c9e4..9e121f3 100755 --- a/ios/RNCImageEditor.xcodeproj/project.pbxproj +++ b/ios/RNCImageEditor.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 1478DE2B22A0403F00D818FA /* RNCFileSystem.m in Sources */ = {isa = PBXBuildFile; fileRef = 1478DE2A22A0403F00D818FA /* RNCFileSystem.m */; }; + 1478DE2E22A044E500D818FA /* RNCImageUtils.m in Sources */ = {isa = PBXBuildFile; fileRef = 1478DE2D22A044E500D818FA /* RNCImageUtils.m */; }; B3E7B58A1CC2AC0600A0062D /* RNCImageEditor.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNCImageEditor.m */; }; /* End PBXBuildFile section */ @@ -24,6 +26,10 @@ /* Begin PBXFileReference section */ 134814201AA4EA6300B7C361 /* libRNCImageEditor.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNCImageEditor.a; sourceTree = BUILT_PRODUCTS_DIR; }; + 1478DE2A22A0403F00D818FA /* RNCFileSystem.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNCFileSystem.m; sourceTree = ""; }; + 1478DE2C22A0406800D818FA /* RNCFileSystem.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNCFileSystem.h; sourceTree = ""; }; + 1478DE2D22A044E500D818FA /* RNCImageUtils.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = RNCImageUtils.m; sourceTree = ""; }; + 1478DE2F22A0450800D818FA /* RNCImageUtils.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RNCImageUtils.h; sourceTree = ""; }; B3E7B5881CC2AC0600A0062D /* RNCImageEditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNCImageEditor.h; sourceTree = ""; }; B3E7B5891CC2AC0600A0062D /* RNCImageEditor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNCImageEditor.m; sourceTree = ""; }; /* End PBXFileReference section */ @@ -50,6 +56,10 @@ 58B511D21A9E6C8500147676 = { isa = PBXGroup; children = ( + 1478DE2A22A0403F00D818FA /* RNCFileSystem.m */, + 1478DE2D22A044E500D818FA /* RNCImageUtils.m */, + 1478DE2F22A0450800D818FA /* RNCImageUtils.h */, + 1478DE2C22A0406800D818FA /* RNCFileSystem.h */, B3E7B5881CC2AC0600A0062D /* RNCImageEditor.h */, B3E7B5891CC2AC0600A0062D /* RNCImageEditor.m */, 134814211AA4EA7D00B7C361 /* Products */, @@ -112,6 +122,8 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + 1478DE2E22A044E500D818FA /* RNCImageUtils.m in Sources */, + 1478DE2B22A0403F00D818FA /* RNCFileSystem.m in Sources */, B3E7B58A1CC2AC0600A0062D /* RNCImageEditor.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/ios/RNCImageUtils.h b/ios/RNCImageUtils.h new file mode 100644 index 0000000..d3034fa --- /dev/null +++ b/ios/RNCImageUtils.h @@ -0,0 +1,21 @@ +// +// RNCImageUtils.h +// RNCImageEditor +// +// Created by Dawid Urbaniak on 30/05/2019. +// Copyright © 2019 Facebook. All rights reserved. +// + +#ifndef RNCImageUtils_h +#define RNCImageUtils_h + +#import + +@interface RNCImageUtils : NSObject + ++ (NSString *)writeImage:(NSData *)image toPath:(NSString *)path; + +@end + + +#endif /* RNCImageUtils_h */ diff --git a/ios/RNCImageUtils.m b/ios/RNCImageUtils.m new file mode 100644 index 0000000..e5191aa --- /dev/null +++ b/ios/RNCImageUtils.m @@ -0,0 +1,20 @@ +// +// RNCImageUtils.m +// RNCImageEditor +// +// Created by Dawid Urbaniak on 30/05/2019. +// Copyright © 2019 Facebook. All rights reserved. +// + +#import "RNCImageUtils.h" + +@implementation RNCImageUtils + ++ (id)writeImage:(id)image toPath:(id)path +{ + [image writeToFile:path atomically:YES]; + NSURL *fileURL = [NSURL fileURLWithPath:path]; + return [fileURL absoluteString]; +} + +@end From b2eb1f3696de394a3fecd3a09c4d51529c960e12 Mon Sep 17 00:00:00 2001 From: Trancever Date: Tue, 4 Jun 2019 09:19:19 +0200 Subject: [PATCH 2/2] feat: add better error handling --- ios/RNCImageEditor.m | 11 +++++++++-- ios/RNCImageUtils.h | 2 +- ios/RNCImageUtils.m | 8 ++++++-- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/ios/RNCImageEditor.m b/ios/RNCImageEditor.m index a674005..23d928a 100644 --- a/ios/RNCImageEditor.m +++ b/ios/RNCImageEditor.m @@ -30,7 +30,8 @@ @implementation RNCImageEditor @synthesize bridge = _bridge; /** - * Crops an image and saves the result to temporary file. + * Crops an image and saves the result to temporary file. Consider using + * CameraRoll API or other third-party module to save it in gallery. * * @param imageRequest An image URL * @param cropData Dictionary with `offset`, `size` and `displaySize`. @@ -74,7 +75,13 @@ @implementation RNCImageEditor NSString *path = [RNCFileSystem generatePathInDirectory:[[RNCFileSystem cacheDirectoryPath] stringByAppendingPathComponent:@"ReactNative_cropped_image_"] withExtension:@".jpg"]; NSData *imageData = UIImageJPEGRepresentation(croppedImage, 1); - NSString *uri = [RNCImageUtils writeImage:imageData toPath:path]; + NSError *writeError; + NSString *uri = [RNCImageUtils writeImage:imageData toPath:path error:&writeError]; + + if (writeError != nil) { + errorCallback(writeError); + return; + } successCallback(@[uri]); }]; diff --git a/ios/RNCImageUtils.h b/ios/RNCImageUtils.h index d3034fa..e771084 100644 --- a/ios/RNCImageUtils.h +++ b/ios/RNCImageUtils.h @@ -13,7 +13,7 @@ @interface RNCImageUtils : NSObject -+ (NSString *)writeImage:(NSData *)image toPath:(NSString *)path; ++ (NSString *)writeImage:(NSData *)image toPath:(NSString *)path error:(NSError **)error; @end diff --git a/ios/RNCImageUtils.m b/ios/RNCImageUtils.m index e5191aa..7e1f805 100644 --- a/ios/RNCImageUtils.m +++ b/ios/RNCImageUtils.m @@ -10,9 +10,13 @@ @implementation RNCImageUtils -+ (id)writeImage:(id)image toPath:(id)path ++ (id)writeImage:(id)image toPath:(id)path error:(NSError **)error { - [image writeToFile:path atomically:YES]; + BOOL res = [image writeToFile:path atomically:YES]; + if (res == NO) { + *error = [NSError errorWithDomain:@"org.reactnativecommunity.imageeditor.writeToFileError" code:101 userInfo:[NSDictionary dictionary]]; + return nil; + } NSURL *fileURL = [NSURL fileURLWithPath:path]; return [fileURL absoluteString]; }