diff --git a/android/build.gradle b/android/build.gradle
index 1f7d7b6..c94841e 100755
--- a/android/build.gradle
+++ b/android/build.gradle
@@ -1,21 +1,30 @@
-
buildscript {
- repositories {
- google()
- mavenCentral()
- }
+ repositories {
+ google()
+ mavenCentral()
+ }
- dependencies {
- classpath 'com.android.tools.build:gradle:3.2.1'
- }
+ dependencies {
+ classpath "com.android.tools.build:gradle:7.2.1"
+ }
+}
+
+def isNewArchitectureEnabled() {
+ return rootProject.hasProperty("newArchEnabled") && rootProject.getProperty("newArchEnabled") == "true"
+}
+
+apply plugin: "com.android.library"
+
+if (isNewArchitectureEnabled()) {
+ apply plugin: "com.facebook.react"
}
def getExtOrDefault(name) {
- return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties['RNImageEditor_' + name]
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : project.properties["RNImageEditor_" + name]
}
def getExtOrIntegerDefault(name) {
- return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties['RNImageEditor_' + name]).toInteger()
+ return rootProject.ext.has(name) ? rootProject.ext.get(name) : (project.properties["RNImageEditor_" + name]).toInteger()
}
def supportsNamespace() {
@@ -27,34 +36,60 @@ def supportsNamespace() {
return (major == 7 && minor >= 3) || major >= 8
}
-
-apply plugin: 'com.android.library'
-
android {
- compileSdkVersion getExtOrIntegerDefault('compileSdkVersion')
- buildToolsVersion getExtOrDefault('buildToolsVersion')
+ if (supportsNamespace()) {
+ namespace "com.reactnativecommunity.imageeditor"
- if (supportsNamespace()) {
- namespace "com.reactnativecommunity.imageeditor"
+ sourceSets {
+ main {
+ manifest.srcFile "src/main/AndroidManifestNew.xml"
+ }
+ }
+ }
+ compileSdkVersion getExtOrIntegerDefault("compileSdkVersion")
+ defaultConfig {
+ minSdkVersion getExtOrIntegerDefault("minSdkVersion")
+ targetSdkVersion getExtOrIntegerDefault("targetSdkVersion")
+ buildConfigField "boolean", "IS_NEW_ARCHITECTURE_ENABLED", isNewArchitectureEnabled().toString()
+ }
+ buildFeatures {
+ buildConfig true
+ }
- sourceSets {
- main {
- manifest.srcFile "src/main/AndroidManifestNew.xml"
- }
- }
+ buildTypes {
+ release {
+ minifyEnabled false
}
+ }
- defaultConfig {
- minSdkVersion getExtOrIntegerDefault('minSdkVersion')
- targetSdkVersion getExtOrIntegerDefault('targetSdkVersion')
+ lintOptions {
+ disable "GradleCompatible"
+ }
+
+ compileOptions {
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+
+ sourceSets {
+ main {
+ if (isNewArchitectureEnabled()) {
+ java.srcDirs += ["src/newarch", "${project.buildDir}/generated/source/codegen/java"]
+ } else {
+ java.srcDirs += ["src/oldarch"]
+ }
}
+ }
}
repositories {
- mavenCentral()
+ mavenCentral()
+ google()
}
dependencies {
- api 'com.facebook.react:react-native:+'
+ // For < 0.71, this will be from the local maven repo
+ // For > 0.71, this will be replaced by `com.facebook.react:react-android:$version` by react gradle plugin
+ //noinspection GradleDynamicVersion
+ implementation "com.facebook.react:react-native:+"
}
-
\ No newline at end of file
diff --git a/android/gradle.properties b/android/gradle.properties
index a24577a..b66fc42 100755
--- a/android/gradle.properties
+++ b/android/gradle.properties
@@ -1,4 +1,3 @@
-RNImageEditor_compileSdkVersion=28
-RNImageEditor_buildToolsVersion=28.0.3
-RNImageEditor_targetSdkVersion=28
-RNImageEditor_minSdkVersion=19
\ No newline at end of file
+RNImageEditor_compileSdkVersion=34
+RNImageEditor_targetSdkVersion=34
+RNImageEditor_minSdkVersion=21
diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties
index 9a4163a..df31ce3 100644
--- a/android/gradle/wrapper/gradle-wrapper.properties
+++ b/android/gradle/wrapper/gradle-wrapper.properties
@@ -1,5 +1,6 @@
+#Sat Nov 04 23:34:44 CET 2023
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.6-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-7.3.3-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/android/src/main/AndroidManifest.xml b/android/src/main/AndroidManifest.xml
index 8797405..28ddd50 100755
--- a/android/src/main/AndroidManifest.xml
+++ b/android/src/main/AndroidManifest.xml
@@ -1,6 +1,3 @@
-
-
-
\ No newline at end of file
diff --git a/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java b/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModuleImpl.java
similarity index 88%
rename from android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java
rename to android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModuleImpl.java
index c053ab4..6ea4d32 100644
--- a/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java
+++ b/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModuleImpl.java
@@ -4,7 +4,6 @@
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
-
package com.reactnativecommunity.imageeditor;
import javax.annotation.Nullable;
@@ -18,9 +17,7 @@
import java.net.URL;
import java.net.URLConnection;
import java.util.Arrays;
-import java.util.Collections;
import java.util.List;
-import java.util.Map;
import android.annotation.SuppressLint;
import android.content.ContentResolver;
@@ -43,23 +40,20 @@
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
-import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.JSApplicationIllegalArgumentException;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.infer.annotation.Assertions;
import com.facebook.react.common.ReactConstants;
-/**
- * Native module that provides image cropping functionality.
- */
-public class ImageEditorModule extends ReactContextBaseJavaModule {
+public class ImageEditorModuleImpl {
+ private ReactApplicationContext reactContext;
protected static final String NAME = "RNCImageEditor";
private static final List LOCAL_URI_PREFIXES = Arrays.asList(
- ContentResolver.SCHEME_FILE,
- ContentResolver.SCHEME_CONTENT,
- ContentResolver.SCHEME_ANDROID_RESOURCE
+ ContentResolver.SCHEME_FILE,
+ ContentResolver.SCHEME_CONTENT,
+ ContentResolver.SCHEME_ANDROID_RESOURCE
);
private static final String TEMP_FILE_PREFIX = "ReactNative_cropped_image_";
@@ -95,24 +89,13 @@ public class ImageEditorModule extends ReactContextBaseJavaModule {
ExifInterface.TAG_WHITE_BALANCE
};
- public ImageEditorModule(ReactApplicationContext reactContext) {
- super(reactContext);
- new CleanTask(getReactApplicationContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
- }
-
- @Override
- public String getName() {
- return NAME;
- }
-
- @Override
- public Map getConstants() {
- return Collections.emptyMap();
+ public ImageEditorModuleImpl(ReactApplicationContext context) {
+ reactContext = context;
+ new CleanTask(reactContext).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
- @Override
public void onCatalystInstanceDestroy() {
- new CleanTask(getReactApplicationContext()).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
+ new CleanTask(reactContext).executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
/**
@@ -139,12 +122,12 @@ protected void doInBackgroundGuarded(Void... params) {
private void cleanDirectory(File directory) {
File[] toDelete = directory.listFiles(
- new FilenameFilter() {
- @Override
- public boolean accept(File dir, String filename) {
- return filename.startsWith(TEMP_FILE_PREFIX);
- }
- });
+ new FilenameFilter() {
+ @Override
+ public boolean accept(File dir, String filename) {
+ return filename.startsWith(TEMP_FILE_PREFIX);
+ }
+ });
if (toDelete != null) {
for (File file: toDelete) {
file.delete();
@@ -166,16 +149,15 @@ public boolean accept(File dir, String filename) {
* @param promise Promise to be resolved when the image has been cropped; the only argument that
* is passed to this is the file:// URI of the new image
*/
- @ReactMethod
public void cropImage(
- String uri,
- ReadableMap options,
- Promise promise) {
+ String uri,
+ ReadableMap options,
+ Promise promise) {
ReadableMap offset = options.hasKey("offset") ? options.getMap("offset") : null;
ReadableMap size = options.hasKey("size") ? options.getMap("size") : null;
if (offset == null || size == null ||
- !offset.hasKey("x") || !offset.hasKey("y") ||
- !size.hasKey("width") || !size.hasKey("height")) {
+ !offset.hasKey("x") || !offset.hasKey("y") ||
+ !size.hasKey("width") || !size.hasKey("height")) {
throw new JSApplicationIllegalArgumentException("Please specify offset and size");
}
if (uri == null || uri.isEmpty()) {
@@ -183,13 +165,13 @@ public void cropImage(
}
CropTask cropTask = new CropTask(
- getReactApplicationContext(),
- uri,
- (int) offset.getDouble("x"),
- (int) offset.getDouble("y"),
- (int) size.getDouble("width"),
- (int) size.getDouble("height"),
- promise);
+ reactContext,
+ uri,
+ (int) offset.getDouble("x"),
+ (int) offset.getDouble("y"),
+ (int) size.getDouble("width"),
+ (int) size.getDouble("height"),
+ promise);
if (options.hasKey("displaySize")) {
ReadableMap targetSize = options.getMap("displaySize");
cropTask.setTargetSize(
@@ -211,17 +193,17 @@ private static class CropTask extends GuardedAsyncTask {
final Promise mPromise;
private CropTask(
- ReactContext context,
- String uri,
- int x,
- int y,
- int width,
- int height,
- Promise promise) {
+ ReactContext context,
+ String uri,
+ int x,
+ int y,
+ int width,
+ int height,
+ Promise promise) {
super(context);
if (x < 0 || y < 0 || width <= 0 || height <= 0) {
throw new JSApplicationIllegalArgumentException(String.format(
- "Invalid crop rectangle: [%d, %d, %d, %d]", x, y, width, height));
+ "Invalid crop rectangle: [%d, %d, %d, %d]", x, y, width, height));
}
mContext = context;
mUri = uri;
@@ -235,7 +217,7 @@ private CropTask(
public void setTargetSize(int width, int height) {
if (width <= 0 || height <= 0) {
throw new JSApplicationIllegalArgumentException(String.format(
- "Invalid target size: [%d, %d]", width, height));
+ "Invalid target size: [%d, %d]", width, height));
}
mTargetWidth = width;
mTargetHeight = height;
@@ -314,10 +296,10 @@ private Bitmap crop(BitmapFactory.Options outOptions) throws IOException {
* @param outOptions Bitmap options, useful to determine {@code outMimeType}.
*/
private Bitmap cropAndResize(
- int targetWidth,
- int targetHeight,
- BitmapFactory.Options outOptions)
- throws IOException {
+ int targetWidth,
+ int targetHeight,
+ BitmapFactory.Options outOptions)
+ throws IOException {
Assertions.assertNotNull(outOptions);
// Loading large bitmaps efficiently:
@@ -450,7 +432,7 @@ private static Bitmap.CompressFormat getCompressFormatForType(String type) {
}
private static void writeCompressedBitmapToFile(Bitmap cropped, String mimeType, File tempFile)
- throws IOException {
+ throws IOException {
OutputStream out = new FileOutputStream(tempFile);
try {
cropped.compress(getCompressFormatForType(mimeType), COMPRESS_QUALITY, out);
@@ -468,7 +450,7 @@ private static void writeCompressedBitmapToFile(Bitmap cropped, String mimeType,
* @param mimeType the MIME type of the file to create (image/*)
*/
private static File createTempFile(Context context, @Nullable String mimeType)
- throws IOException {
+ throws IOException {
File externalCacheDir = context.getExternalCacheDir();
File internalCacheDir = context.getCacheDir();
File cacheDir;
@@ -482,7 +464,7 @@ else if (internalCacheDir == null) {
cacheDir = externalCacheDir;
} else {
cacheDir = externalCacheDir.getFreeSpace() > internalCacheDir.getFreeSpace() ?
- externalCacheDir : internalCacheDir;
+ externalCacheDir : internalCacheDir;
}
return File.createTempFile(TEMP_FILE_PREFIX, getFileExtensionForType(mimeType), cacheDir);
}
@@ -499,7 +481,7 @@ private static int getDecodeSampleSize(int width, int height, int targetWidth, i
int halfHeight = height / 2;
int halfWidth = width / 2;
while ((halfWidth / inSampleSize) >= targetWidth
- && (halfHeight / inSampleSize) >= targetHeight) {
+ && (halfHeight / inSampleSize) >= targetHeight) {
inSampleSize *= 2;
}
}
diff --git a/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorPackage.java b/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorPackage.java
index a2b51ea..334447e 100644
--- a/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorPackage.java
+++ b/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorPackage.java
@@ -7,30 +7,59 @@
package com.reactnativecommunity.imageeditor;
-import java.util.Arrays;
-import java.util.Collections;
-import java.util.List;
+import androidx.annotation.Nullable;
-import com.facebook.react.ReactPackage;
+import com.facebook.react.TurboReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
-import com.facebook.react.uimanager.ViewManager;
-import com.facebook.react.bridge.JavaScriptModule;
+import com.facebook.react.module.annotations.ReactModule;
+import com.facebook.react.module.model.ReactModuleInfo;
+import com.facebook.react.module.model.ReactModuleInfoProvider;
+import com.facebook.react.turbomodule.core.interfaces.TurboModule;
-public class ImageEditorPackage implements ReactPackage {
- @Override
- public List createNativeModules(ReactApplicationContext reactContext) {
- return Arrays.asList(new ImageEditorModule(reactContext));
- }
+import java.util.HashMap;
+import java.util.Map;
+
+public class ImageEditorPackage extends TurboReactPackage {
- // Deprecated from RN 0.47
- public List> createJSModules() {
- return Collections.emptyList();
+ @Nullable
+ @Override
+ public NativeModule getModule(String name, ReactApplicationContext reactContext) {
+ if (name.equals(ImageEditorModule.NAME)) {
+ return new ImageEditorModule(reactContext);
+ } else {
+ return null;
}
+ }
- @Override
- @SuppressWarnings("rawtypes")
- public List createViewManagers(ReactApplicationContext reactContext) {
- return Collections.emptyList();
+ @Override
+ public ReactModuleInfoProvider getReactModuleInfoProvider() {
+ Class extends NativeModule>[] moduleList = new Class[] {
+ ImageEditorModule.class
+ };
+ final Map reactModuleInfoMap = new HashMap<>();
+
+ for (Class extends NativeModule> moduleClass : moduleList) {
+ ReactModule reactModule = moduleClass.getAnnotation(ReactModule.class);
+ reactModuleInfoMap.put(
+ reactModule.name(),
+ new ReactModuleInfo(
+ reactModule.name(),
+ moduleClass.getName(),
+ true,
+ reactModule.needsEagerInit(),
+ reactModule.hasConstants(),
+ reactModule.isCxxModule(),
+ TurboModule.class.isAssignableFrom(moduleClass)
+ )
+ );
}
-}
\ No newline at end of file
+
+ return new ReactModuleInfoProvider() {
+ @Override
+ public Map getReactModuleInfos() {
+ return reactModuleInfoMap;
+ }
+ };
+ }
+}
diff --git a/android/src/newarch/com/reactnativecommunity/imageeditor/ImageEditorModule.java b/android/src/newarch/com/reactnativecommunity/imageeditor/ImageEditorModule.java
new file mode 100644
index 0000000..5fc0fe6
--- /dev/null
+++ b/android/src/newarch/com/reactnativecommunity/imageeditor/ImageEditorModule.java
@@ -0,0 +1,36 @@
+package com.reactnativecommunity.imageeditor;
+
+import androidx.annotation.NonNull;
+
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.module.annotations.ReactModule;
+
+@ReactModule(name = ImageEditorModule.NAME)
+public class ImageEditorModule extends NativeRNCImageEditorSpec {
+ private ImageEditorModuleImpl moduleImpl;
+
+ ImageEditorModule(ReactApplicationContext context) {
+ super(context);
+ moduleImpl = new ImageEditorModuleImpl(context);
+ }
+
+ public static final String NAME = ImageEditorModuleImpl.NAME;
+
+ @Override
+ @NonNull
+ public String getName() {
+ return ImageEditorModuleImpl.NAME;
+ }
+
+ @Override
+ public void onCatalystInstanceDestroy() {
+ moduleImpl.onCatalystInstanceDestroy();
+ }
+
+ @Override
+ public void cropImage(String uri, ReadableMap cropData, Promise promise) {
+ moduleImpl.cropImage(uri, cropData, promise);
+ }
+}
diff --git a/android/src/oldarch/com/reactnativecommunity/imageeditor/ImageEditorModule.java b/android/src/oldarch/com/reactnativecommunity/imageeditor/ImageEditorModule.java
new file mode 100644
index 0000000..fbe518f
--- /dev/null
+++ b/android/src/oldarch/com/reactnativecommunity/imageeditor/ImageEditorModule.java
@@ -0,0 +1,44 @@
+package com.reactnativecommunity.imageeditor;
+
+import java.util.Collections;
+import java.util.Map;
+
+import com.facebook.react.bridge.Promise;
+import com.facebook.react.bridge.ReactApplicationContext;
+import com.facebook.react.bridge.ReactContextBaseJavaModule;
+import com.facebook.react.bridge.ReactMethod;
+import com.facebook.react.bridge.ReadableMap;
+import com.facebook.react.module.annotations.ReactModule;
+
+@ReactModule(name = ImageEditorModule.NAME)
+public class ImageEditorModule extends ReactContextBaseJavaModule {
+ private ImageEditorModuleImpl moduleImpl;
+
+ public ImageEditorModule(ReactApplicationContext reactContext) {
+ super(reactContext);
+ moduleImpl = new ImageEditorModuleImpl(reactContext);
+ }
+
+ public static final String NAME = ImageEditorModuleImpl.NAME;
+
+ @Override
+ public String getName() {
+ return ImageEditorModuleImpl.NAME;
+ }
+
+
+ @Override
+ public Map getConstants() {
+ return Collections.emptyMap();
+ }
+
+ @Override
+ public void onCatalystInstanceDestroy() {
+ moduleImpl.onCatalystInstanceDestroy();
+ }
+
+ @ReactMethod
+ public void cropImage(String uri, ReadableMap options, Promise promise) {
+ moduleImpl.cropImage(uri, options, promise);
+ }
+}
diff --git a/ios/RNCFileSystem.m b/ios/RNCFileSystem.mm
similarity index 100%
rename from ios/RNCFileSystem.m
rename to ios/RNCFileSystem.mm
diff --git a/ios/RNCImageEditor.h b/ios/RNCImageEditor.h
index 2fb37e8..fe094ab 100644
--- a/ios/RNCImageEditor.h
+++ b/ios/RNCImageEditor.h
@@ -5,8 +5,14 @@
* LICENSE file in the root directory of this source tree.
*/
+#ifdef RCT_NEW_ARCH_ENABLED
+#import "RNCImageEditorSpec.h"
+
+@interface RNCImageEditor : NSObject
+#else
#import
@interface RNCImageEditor : NSObject
+#endif
@end
diff --git a/ios/RNCImageEditor.m b/ios/RNCImageEditor.mm
similarity index 66%
rename from ios/RNCImageEditor.m
rename to ios/RNCImageEditor.mm
index 7c2bede..749a354 100644
--- a/ios/RNCImageEditor.m
+++ b/ios/RNCImageEditor.mm
@@ -40,15 +40,37 @@ @implementation RNCImageEditor
* be scaled down to `displaySize` rather than `size`.
* All units are in px (not points).
*/
+#ifdef RCT_NEW_ARCH_ENABLED
+- (void) cropImage:(NSString *)uri
+ cropData:(JS::NativeRNCImageEditor::SpecCropImageCropData &)data
+ resolve:(RCTPromiseResolveBlock)resolve
+ reject:(RCTPromiseRejectBlock)reject
+{
+ CGSize size = [RCTConvert CGSize:@{ @"width": @(data.size().width()), @"height": @(data.size().height()) }];
+ CGPoint offset = [RCTConvert CGPoint:@{ @"x": @(data.offset().x()), @"y": @(data.offset().y()) }];
+ CGSize targetSize = size;
+ if (data.displaySize().has_value()) {
+ JS::NativeRNCImageEditor::SpecCropImageCropDataDisplaySize displaySize = *data.displaySize(); // Extract the value from the optional
+ // in pixels
+ targetSize = [RCTConvert CGSize:@{ @"width": @(displaySize.width()), @"height": @(displaySize.height()) }];
+ }
+ NSString *displaySize = data.resizeMode();
+ NSURLRequest *imageRequest = [NSURLRequest requestWithURL:[NSURL URLWithString: uri]];
+#else
RCT_EXPORT_METHOD(cropImage:(NSURLRequest *)imageRequest
cropData:(NSDictionary *)cropData
resolve:(RCTPromiseResolveBlock)resolve
reject:(RCTPromiseRejectBlock)reject)
{
- CGRect rect = {
- [RCTConvert CGPoint:cropData[@"offset"]],
- [RCTConvert CGSize:cropData[@"size"]]
- };
+ CGSize size = [RCTConvert CGSize:cropData[@"size"]];
+ CGPoint offset = [RCTConvert CGPoint:cropData[@"offset"]];
+ CGSize targetSize = size;
+ NSString *displaySize = cropData[@"resizeMode"];
+ if(displaySize){
+ targetSize = [RCTConvert CGSize:cropData[@"displaySize"]];
+ }
+#endif
+ CGRect rect = {offset,size};
NSURL *url = [imageRequest URL];
NSString *urlPath = [url path];
NSString *extension = [urlPath pathExtension];
@@ -60,15 +82,13 @@ @implementation RNCImageEditor
}
// Crop image
- CGSize targetSize = rect.size;
CGRect targetRect = {{-rect.origin.x, -rect.origin.y}, image.size};
CGAffineTransform transform = RCTTransformFromTargetRect(image.size, targetRect);
UIImage *croppedImage = RCTTransformImage(image, targetSize, image.scale, transform);
// Scale image
- if (cropData[@"displaySize"]) {
- targetSize = [RCTConvert CGSize:cropData[@"displaySize"]]; // in pixels
- RCTResizeMode resizeMode = [RCTConvert RCTResizeMode:cropData[@"resizeMode"] ?: @"contain"];
+ if (displaySize) {
+ RCTResizeMode resizeMode = [RCTConvert RCTResizeMode:displaySize ?: @"contain"];
targetRect = RCTTargetRect(croppedImage.size, targetSize, 1, resizeMode);
transform = RCTTransformFromTargetRect(croppedImage.size, targetRect);
croppedImage = RCTTransformImage(croppedImage, targetSize, image.scale, transform);
@@ -77,7 +97,7 @@ @implementation RNCImageEditor
// Store image
NSString *path = NULL;
NSData *imageData = NULL;
-
+
if([extension isEqualToString:@"png"]){
imageData = UIImagePNGRepresentation(croppedImage);
path = [RNCFileSystem generatePathInDirectory:[[RNCFileSystem cacheDirectoryPath] stringByAppendingPathComponent:@"ReactNative_cropped_image_"] withExtension:@".png"];
@@ -90,14 +110,22 @@ @implementation RNCImageEditor
NSError *writeError;
NSString *uri = [RNCImageUtils writeImage:imageData toPath:path error:&writeError];
-
+
if (writeError != nil) {
reject(@(writeError.code).stringValue, writeError.description, writeError);
return;
}
-
+
resolve(uri);
}];
}
+#ifdef RCT_NEW_ARCH_ENABLED
+- (std::shared_ptr)getTurboModule:
+ (const facebook::react::ObjCTurboModule::InitParams &)params
+{
+ return std::make_shared(params);
+}
+#endif
+
@end
diff --git a/ios/RNCImageEditor.xcodeproj/project.pbxproj b/ios/RNCImageEditor.xcodeproj/project.pbxproj
deleted file mode 100755
index 7433613..0000000
--- a/ios/RNCImageEditor.xcodeproj/project.pbxproj
+++ /dev/null
@@ -1,273 +0,0 @@
-// !$*UTF8*$!
-{
- archiveVersion = 1;
- classes = {
- };
- objectVersion = 46;
- 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 */
-
-/* Begin PBXCopyFilesBuildPhase section */
- 58B511D91A9E6C8500147676 /* CopyFiles */ = {
- isa = PBXCopyFilesBuildPhase;
- buildActionMask = 2147483647;
- dstPath = "include/$(PRODUCT_NAME)";
- dstSubfolderSpec = 16;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXCopyFilesBuildPhase section */
-
-/* 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 */
-
-/* Begin PBXFrameworksBuildPhase section */
- 58B511D81A9E6C8500147676 /* Frameworks */ = {
- isa = PBXFrameworksBuildPhase;
- buildActionMask = 2147483647;
- files = (
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXFrameworksBuildPhase section */
-
-/* Begin PBXGroup section */
- 134814211AA4EA7D00B7C361 /* Products */ = {
- isa = PBXGroup;
- children = (
- 134814201AA4EA6300B7C361 /* libRNCImageEditor.a */,
- );
- name = Products;
- sourceTree = "";
- };
- 58B511D21A9E6C8500147676 = {
- isa = PBXGroup;
- children = (
- 1478DE2A22A0403F00D818FA /* RNCFileSystem.m */,
- 1478DE2D22A044E500D818FA /* RNCImageUtils.m */,
- 1478DE2F22A0450800D818FA /* RNCImageUtils.h */,
- 1478DE2C22A0406800D818FA /* RNCFileSystem.h */,
- B3E7B5881CC2AC0600A0062D /* RNCImageEditor.h */,
- B3E7B5891CC2AC0600A0062D /* RNCImageEditor.m */,
- 134814211AA4EA7D00B7C361 /* Products */,
- );
- sourceTree = "";
- };
-/* End PBXGroup section */
-
-/* Begin PBXNativeTarget section */
- 58B511DA1A9E6C8500147676 /* RNCImageEditor */ = {
- isa = PBXNativeTarget;
- buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNCImageEditor" */;
- buildPhases = (
- 58B511D71A9E6C8500147676 /* Sources */,
- 58B511D81A9E6C8500147676 /* Frameworks */,
- 58B511D91A9E6C8500147676 /* CopyFiles */,
- );
- buildRules = (
- );
- dependencies = (
- );
- name = RNCImageEditor;
- productName = RCTDataManager;
- productReference = 134814201AA4EA6300B7C361 /* libRNCImageEditor.a */;
- productType = "com.apple.product-type.library.static";
- };
-/* End PBXNativeTarget section */
-
-/* Begin PBXProject section */
- 58B511D31A9E6C8500147676 /* Project object */ = {
- isa = PBXProject;
- attributes = {
- LastUpgradeCheck = 0830;
- ORGANIZATIONNAME = Facebook;
- TargetAttributes = {
- 58B511DA1A9E6C8500147676 = {
- CreatedOnToolsVersion = 6.1.1;
- };
- };
- };
- buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNCImageEditor" */;
- compatibilityVersion = "Xcode 3.2";
- developmentRegion = English;
- hasScannedForEncodings = 0;
- knownRegions = (
- en,
- );
- mainGroup = 58B511D21A9E6C8500147676;
- productRefGroup = 58B511D21A9E6C8500147676;
- projectDirPath = "";
- projectRoot = "";
- targets = (
- 58B511DA1A9E6C8500147676 /* RNCImageEditor */,
- );
- };
-/* End PBXProject section */
-
-/* Begin PBXSourcesBuildPhase section */
- 58B511D71A9E6C8500147676 /* Sources */ = {
- isa = PBXSourcesBuildPhase;
- buildActionMask = 2147483647;
- files = (
- 1478DE2E22A044E500D818FA /* RNCImageUtils.m in Sources */,
- 1478DE2B22A0403F00D818FA /* RNCFileSystem.m in Sources */,
- B3E7B58A1CC2AC0600A0062D /* RNCImageEditor.m in Sources */,
- );
- runOnlyForDeploymentPostprocessing = 0;
- };
-/* End PBXSourcesBuildPhase section */
-
-/* Begin XCBuildConfiguration section */
- 58B511ED1A9E6C8500147676 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- ENABLE_TESTABILITY = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_DYNAMIC_NO_PIC = NO;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_OPTIMIZATION_LEVEL = 0;
- GCC_PREPROCESSOR_DEFINITIONS = (
- "DEBUG=1",
- "$(inherited)",
- );
- GCC_SYMBOLS_PRIVATE_EXTERN = NO;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
- MTL_ENABLE_DEBUG_INFO = YES;
- ONLY_ACTIVE_ARCH = YES;
- SDKROOT = iphoneos;
- };
- name = Debug;
- };
- 58B511EE1A9E6C8500147676 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- ALWAYS_SEARCH_USER_PATHS = NO;
- CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
- CLANG_CXX_LIBRARY = "libc++";
- CLANG_ENABLE_MODULES = YES;
- CLANG_ENABLE_OBJC_ARC = YES;
- CLANG_WARN_BOOL_CONVERSION = YES;
- CLANG_WARN_CONSTANT_CONVERSION = YES;
- CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
- CLANG_WARN_EMPTY_BODY = YES;
- CLANG_WARN_ENUM_CONVERSION = YES;
- CLANG_WARN_INFINITE_RECURSION = YES;
- CLANG_WARN_INT_CONVERSION = YES;
- CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
- CLANG_WARN_SUSPICIOUS_MOVE = YES;
- CLANG_WARN_UNREACHABLE_CODE = YES;
- CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
- COPY_PHASE_STRIP = YES;
- ENABLE_NS_ASSERTIONS = NO;
- ENABLE_STRICT_OBJC_MSGSEND = YES;
- GCC_C_LANGUAGE_STANDARD = gnu99;
- GCC_NO_COMMON_BLOCKS = YES;
- GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
- GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
- GCC_WARN_UNDECLARED_SELECTOR = YES;
- GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
- GCC_WARN_UNUSED_FUNCTION = YES;
- GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 8.0;
- MTL_ENABLE_DEBUG_INFO = NO;
- SDKROOT = iphoneos;
- VALIDATE_PRODUCT = YES;
- };
- name = Release;
- };
- 58B511F01A9E6C8500147676 /* Debug */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- HEADER_SEARCH_PATHS = (
- "$(inherited)",
- /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
- "$(SRCROOT)/../../../React/**",
- "$(SRCROOT)/../../react-native/React/**",
- "$(SRCROOT)/../../../react-native/Libraries/Image/**",
- );
- LIBRARY_SEARCH_PATHS = "$(inherited)";
- OTHER_LDFLAGS = "-ObjC";
- PRODUCT_NAME = RNCImageEditor;
- SKIP_INSTALL = YES;
- };
- name = Debug;
- };
- 58B511F11A9E6C8500147676 /* Release */ = {
- isa = XCBuildConfiguration;
- buildSettings = {
- HEADER_SEARCH_PATHS = (
- "$(inherited)",
- /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
- "$(SRCROOT)/../../../React/**",
- "$(SRCROOT)/../../react-native/React/**",
- "$(SRCROOT)/../../../react-native/Libraries/Image/**",
- );
- LIBRARY_SEARCH_PATHS = "$(inherited)";
- OTHER_LDFLAGS = "-ObjC";
- PRODUCT_NAME = RNCImageEditor;
- SKIP_INSTALL = YES;
- };
- name = Release;
- };
-/* End XCBuildConfiguration section */
-
-/* Begin XCConfigurationList section */
- 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNCImageEditor" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 58B511ED1A9E6C8500147676 /* Debug */,
- 58B511EE1A9E6C8500147676 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
- 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNCImageEditor" */ = {
- isa = XCConfigurationList;
- buildConfigurations = (
- 58B511F01A9E6C8500147676 /* Debug */,
- 58B511F11A9E6C8500147676 /* Release */,
- );
- defaultConfigurationIsVisible = 0;
- defaultConfigurationName = Release;
- };
-/* End XCConfigurationList section */
- };
- rootObject = 58B511D31A9E6C8500147676 /* Project object */;
-}
diff --git a/ios/RNCImageUtils.m b/ios/RNCImageUtils.mm
similarity index 100%
rename from ios/RNCImageUtils.m
rename to ios/RNCImageUtils.mm
diff --git a/package.json b/package.json
index 8767026..0558d5b 100755
--- a/package.json
+++ b/package.json
@@ -83,6 +83,14 @@
"access": "public",
"registry": "https://registry.npmjs.org/"
},
+ "codegenConfig": {
+ "name": "RNCImageEditorSpec",
+ "type": "modules",
+ "jsSrcsDir": "src",
+ "android": {
+ "javaPackageName": "com.reactnativecommunity.imageeditor"
+ }
+ },
"react-native-builder-bob": {
"source": "src",
"output": "lib",
diff --git a/react-native-image-editor.podspec b/react-native-image-editor.podspec
index 6cf4969..0f18b21 100644
--- a/react-native-image-editor.podspec
+++ b/react-native-image-editor.podspec
@@ -1,6 +1,7 @@
require 'json'
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
+folly_compiler_flags = '-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1 -Wno-comma -Wno-shorten-64-to-32'
Pod::Spec.new do |s|
s.name = "react-native-image-editor"
@@ -13,8 +14,30 @@ Pod::Spec.new do |s|
s.platform = :ios, "9.0"
s.source = { :git => "https://github.com/callstack/react-native-image-editor.git", :tag => "#{s.version}" }
- s.source_files = "ios/**/*.{h,m}"
+ s.source_files = "ios/**/*.{h,m,mm}"
- s.dependency 'React'
s.dependency 'React-RCTImage'
+
+ # Use install_modules_dependencies helper to install the dependencies if React Native version >=0.71.0.
+ # See https://github.com/facebook/react-native/blob/febf6b7f33fdb4904669f99d795eba4c0f95d7bf/scripts/cocoapods/new_architecture.rb#L79.
+ if respond_to?(:install_modules_dependencies, true)
+ install_modules_dependencies(s)
+ else
+ s.dependency "React-Core"
+
+ # Don't install the dependencies when we run `pod install` in the old architecture.
+ if ENV['RCT_NEW_ARCH_ENABLED'] == '1' then
+ s.compiler_flags = folly_compiler_flags + " -DRCT_NEW_ARCH_ENABLED=1"
+ s.pod_target_xcconfig = {
+ "HEADER_SEARCH_PATHS" => "\"$(PODS_ROOT)/boost\"",
+ "OTHER_CPLUSPLUSFLAGS" => "-DFOLLY_NO_CONFIG -DFOLLY_MOBILE=1 -DFOLLY_USE_LIBCPP=1",
+ "CLANG_CXX_LANGUAGE_STANDARD" => "c++17"
+ }
+ s.dependency "React-Codegen"
+ s.dependency "RCT-Folly"
+ s.dependency "RCTRequired"
+ s.dependency "RCTTypeSafety"
+ s.dependency "ReactCommon/turbomodule/core"
+ end
+ end
end
diff --git a/src/NativeRNCImageEditor.ts b/src/NativeRNCImageEditor.ts
new file mode 100644
index 0000000..5d7b21c
--- /dev/null
+++ b/src/NativeRNCImageEditor.ts
@@ -0,0 +1,42 @@
+import type { TurboModule } from 'react-native';
+import type { Double } from 'react-native/Libraries/Types/CodegenTypes';
+import { TurboModuleRegistry } from 'react-native';
+
+export interface Spec extends TurboModule {
+ cropImage(
+ uri: string,
+ cropData: {
+ // inlined `ImageCropData` type (for older RN versions 71 and below)
+ /**
+ * The top-left corner of the cropped image, specified in the original
+ * image's coordinate space.
+ */
+ offset: {
+ x: Double;
+ y: Double;
+ };
+ /**
+ * The size (dimensions) of the cropped image, specified in the original
+ * image's coordinate space.
+ */
+ size: {
+ width: Double;
+ height: Double;
+ };
+ /**
+ * (Optional) size to scale the cropped image to.
+ */
+ displaySize?: {
+ width: Double;
+ height: Double;
+ };
+ /**
+ * (Optional) the resizing mode to use when scaling the image. If the
+ * `displaySize` param is not specified, this has no effect.
+ */
+ resizeMode?: string;
+ }
+ ): Promise;
+}
+
+export default TurboModuleRegistry.getEnforcing('RNCImageEditor');
diff --git a/src/index.ts b/src/index.ts
index 5bc574b..db97f24 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -5,42 +5,31 @@
* LICENSE file in the root directory of this source tree.
*
*/
+import { Platform } from 'react-native';
+import NativeRNCImageEditor from './NativeRNCImageEditor';
+import type { Spec } from './NativeRNCImageEditor';
-import { NativeModules } from 'react-native';
+const LINKING_ERROR =
+ `The package '@react-native-community/image-editor' doesn't seem to be linked. Make sure: \n\n` +
+ Platform.select({ ios: "- You have run 'pod install'\n", default: '' }) +
+ '- You rebuilt the app after installing the package\n' +
+ '- You are not using Expo Go\n';
-const { RNCImageEditor } = NativeModules;
+const RNCImageEditor: Spec = NativeRNCImageEditor
+ ? NativeRNCImageEditor
+ : new Proxy({} as Spec, {
+ get() {
+ throw new Error(LINKING_ERROR);
+ },
+ });
-type $Maybe = T | null | undefined;
+type ImageCropDataFromSpec = Parameters[1];
-export interface ImageCropData {
- /**
- * The top-left corner of the cropped image, specified in the original
- * image's coordinate space.
- */
- offset: {
- x: number;
- y: number;
- };
- /**
- * The size (dimensions) of the cropped image, specified in the original
- * image's coordinate space.
- */
- size: {
- width: number;
- height: number;
- };
- /**
- * (Optional) size to scale the cropped image to.
- */
- displaySize?: $Maybe<{
- width: number;
- height: number;
- }>;
- /**
- * (Optional) the resizing mode to use when scaling the image. If the
- * `displaySize` param is not specified, this has no effect.
- */
- resizeMode?: $Maybe<'contain' | 'cover' | 'stretch'>;
+export interface ImageCropData
+ extends Pick {
+ resizeMode?: 'contain' | 'cover' | 'stretch';
+ // ^^^ codegen doesn't support union types yet
+ // so to provide more type safety we override the type here
}
class ImageEditor {