diff --git a/README.md b/README.md index 1104905..3414918 100755 --- a/README.md +++ b/README.md @@ -21,15 +21,25 @@ or `react-native link @react-native-community/image-editor` -## Api reference +## Usage + +Start by importing the library: ```javascript - static cropImage(uri, cropData, success, failure) +import ImageEditor from "@react-native-community/image-editor"; ``` -Crop the image specified by the URI param. If URI points to a remote image, it will be downloaded automatically. If the image cannot be loaded/downloaded, the failure callback will be called. +### Crop image + +Crop the image specified by the URI param. If URI points to a remote image, it will be downloaded automatically. If the image cannot be loaded/downloaded, the promise will be rejected. + +If the cropping process is successful, the resultant cropped image will be stored in the cache path, and the URI returned in the promise will point to the image in the cache path. Remember to delete the cropped image from the cache path when you are done with it. -If the cropping process is successful, the resultant cropped image will be stored in the ImageStore, and the URI returned in the success callback will point to the image in the store. Remember to delete the cropped image from the ImageStore when you are done with it. +```javascript + ImageEditor.cropImage(uri, cropData).then(url => { + console.log("Cropped image uri", url); + }) +``` ### cropData | Property | Required | Description | diff --git a/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java b/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java index ccba0f4..0c3378f 100644 --- a/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java +++ b/android/src/main/java/com/reactnativecommunity/imageeditor/ImageEditorModule.java @@ -37,8 +37,8 @@ import android.text.TextUtils; import com.facebook.common.logging.FLog; -import com.facebook.react.bridge.Callback; import com.facebook.react.bridge.GuardedAsyncTask; +import com.facebook.react.bridge.Promise; import com.facebook.react.bridge.ReactApplicationContext; import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.ReactContextBaseJavaModule; @@ -150,25 +150,23 @@ public boolean accept(File dir, String filename) { } /** - * Crop an image. If all goes well, the success callback will be called with the file:// URI of + * Crop an image. If all goes well, the promise will be resolved with the file:// URI of * the new image as the only argument. This is a temporary file - consider using * CameraRollManager.saveImageWithTag to save it in the gallery. * - * @param uri the MediaStore URI of the image to crop + * @param uri the URI of the image to crop * @param options crop parameters specified as {@code {offset: {x, y}, size: {width, height}}}. * Optionally this also contains {@code {targetSize: {width, height}}}. If this is * specified, the cropped image will be resized to that size. * All units are in pixels (not DPs). - * @param success callback to be invoked when the image has been cropped; the only argument that - * is passed to this callback is the file:// URI of the new image - * @param error callback to be invoked when an error occurs (e.g. can't create file etc.) + * @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, - final Callback success, - final Callback error) { + 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 || @@ -187,8 +185,7 @@ public void cropImage( (int) offset.getDouble("y"), (int) size.getDouble("width"), (int) size.getDouble("height"), - success, - error); + promise); if (options.hasKey("displaySize")) { ReadableMap targetSize = options.getMap("displaySize"); cropTask.setTargetSize( @@ -207,8 +204,7 @@ private static class CropTask extends GuardedAsyncTask { final int mHeight; int mTargetWidth = 0; int mTargetHeight = 0; - final Callback mSuccess; - final Callback mError; + final Promise mPromise; private CropTask( ReactContext context, @@ -217,8 +213,7 @@ private CropTask( int y, int width, int height, - Callback success, - Callback error) { + Promise promise) { super(context); if (x < 0 || y < 0 || width <= 0 || height <= 0) { throw new JSApplicationIllegalArgumentException(String.format( @@ -230,8 +225,7 @@ private CropTask( mY = y; mWidth = width; mHeight = height; - mSuccess = success; - mError = error; + mPromise = promise; } public void setTargetSize(int width, int height) { @@ -284,9 +278,9 @@ protected void doInBackgroundGuarded(Void... params) { copyExif(mContext, Uri.parse(mUri), tempFile); } - mSuccess.invoke(Uri.fromFile(tempFile).toString()); + mPromise.resolve(Uri.fromFile(tempFile).toString()); } catch (Exception e) { - mError.invoke(e.getMessage()); + mPromise.reject(e); } } diff --git a/example/src/App.js b/example/src/App.js index b70001e..0499e20 100755 --- a/example/src/App.js +++ b/example/src/App.js @@ -65,7 +65,7 @@ export default class SquareImageCropper extends React.Component< async _fetchRandomPhoto() { this.setState({ randomPhoto: { - uri: `http://placeimg.com/${DEFAULT_IMAGE_WIDTH}/${DEFAULT_IMAGE_HEIGHT}/tech`, + uri: `http://placeimg.com/${DEFAULT_IMAGE_WIDTH}/${DEFAULT_IMAGE_HEIGHT}/tech?${new Date().getTime()}`, height: DEFAULT_IMAGE_HEIGHT, width: DEFAULT_IMAGE_WIDTH, }, @@ -150,13 +150,19 @@ export default class SquareImageCropper extends React.Component< ); } - _crop() { - ImageEditor.cropImage( - this.state.randomPhoto.uri, - this._transformData, - croppedImageURI => this.setState({croppedImageURI}), - cropError => this.setState({cropError}), - ); + async _crop() { + try { + const croppedImageURI = await ImageEditor.cropImage( + this.state.randomPhoto.uri, + this._transformData, + ); + + if (croppedImageURI) { + this.setState({croppedImageURI}); + } + } catch (cropError) { + this.setState({cropError}); + } } _reset() { diff --git a/ios/RNCImageEditor.m b/ios/RNCImageEditor.m index 23d928a..3654af7 100644 --- a/ios/RNCImageEditor.m +++ b/ios/RNCImageEditor.m @@ -42,8 +42,8 @@ @implementation RNCImageEditor */ RCT_EXPORT_METHOD(cropImage:(NSURLRequest *)imageRequest cropData:(NSDictionary *)cropData - successCallback:(RCTResponseSenderBlock)successCallback - errorCallback:(RCTResponseErrorBlock)errorCallback) + resolve:(RCTPromiseResolveBlock)resolve + reject:(RCTPromiseRejectBlock)reject) { CGRect rect = { [RCTConvert CGPoint:cropData[@"offset"]], @@ -52,7 +52,7 @@ @implementation RNCImageEditor [_bridge.imageLoader loadImageWithURLRequest:imageRequest callback:^(NSError *error, UIImage *image) { if (error) { - errorCallback(error); + reject(@(error.code).stringValue, error.description, error); return; } @@ -79,11 +79,11 @@ @implementation RNCImageEditor NSString *uri = [RNCImageUtils writeImage:imageData toPath:path error:&writeError]; if (writeError != nil) { - errorCallback(writeError); + reject(@(writeError.code).stringValue, writeError.description, writeError); return; } - successCallback(@[uri]); + resolve(uri); }]; } diff --git a/lib/ImageEditor.js b/lib/ImageEditor.js index e07a1ea..9d0e8c5 100644 --- a/lib/ImageEditor.js +++ b/lib/ImageEditor.js @@ -51,22 +51,17 @@ class ImageEditor { /** * Crop the image specified by the URI param. If URI points to a remote * image, it will be downloaded automatically. If the image cannot be - * loaded/downloaded, the failure callback will be called. On Android, a + * loaded/downloaded, the promise will be rejected. On Android, a * downloaded image may be cached in external storage, a publicly accessible * location, if it has more available space than internal storage. * * If the cropping process is successful, the resultant cropped image - * will be stored in the ImageStore, and the URI returned in the success - * callback will point to the image in the store. Remember to delete the - * cropped image from the ImageStore when you are done with it. + * will be stored in the Cache Path, and the URI returned in the promise + * will point to the image in the cache path. Remember to delete the + * cropped image from the cache path when you are done with it. */ - static cropImage( - uri: string, - cropData: ImageCropData, - success: (uri: string) => void, - failure: (error: Object) => void, - ) { - RNCImageEditor.cropImage(uri, cropData, success, failure); + static cropImage(uri: string, cropData: ImageCropData): Promise { + return RNCImageEditor.cropImage(uri, cropData); } } diff --git a/typings/index.d.ts b/typings/index.d.ts index 43d35f3..5c000be 100644 --- a/typings/index.d.ts +++ b/typings/index.d.ts @@ -35,21 +35,19 @@ declare class ImageEditor { /** * Crop the image specified by the URI param. If URI points to a remote * image, it will be downloaded automatically. If the image cannot be - * loaded/downloaded, the failure callback will be called. On Android, a + * loaded/downloaded, the promise will be rejected. On Android, a * downloaded image may be cached in external storage, a publicly accessible * location, if it has more available space than internal storage. * * If the cropping process is successful, the resultant cropped image - * will be stored in the ImageStore, and the URI returned in the success - * callback will point to the image in the store. Remember to delete the - * cropped image from the ImageStore when you are done with it. + * will be stored in the Cache Path, and the URI returned in the promise + * will point to the image in the cache path. Remember to delete the + * cropped image from the cache path when you are done with it. */ static cropImage: ( uri: string, cropData: ImageCropData, - success: (uri: string) => void, - failure: (error: Object) => void, - ) => void + ) => Promise } export default ImageEditor \ No newline at end of file