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..23d928a 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,8 @@ @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. 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`. @@ -69,15 +72,18 @@ @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)); + NSString *path = [RNCFileSystem generatePathInDirectory:[[RNCFileSystem cacheDirectoryPath] stringByAppendingPathComponent:@"ReactNative_cropped_image_"] withExtension:@".jpg"]; + + NSData *imageData = UIImageJPEGRepresentation(croppedImage, 1); + NSError *writeError; + NSString *uri = [RNCImageUtils writeImage:imageData toPath:path error:&writeError]; + + if (writeError != nil) { + errorCallback(writeError); return; - } - successCallback(@[croppedImageTag]); - }]; + } + + 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..e771084 --- /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 error:(NSError **)error; + +@end + + +#endif /* RNCImageUtils_h */ diff --git a/ios/RNCImageUtils.m b/ios/RNCImageUtils.m new file mode 100644 index 0000000..7e1f805 --- /dev/null +++ b/ios/RNCImageUtils.m @@ -0,0 +1,24 @@ +// +// 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 error:(NSError **)error +{ + 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]; +} + +@end