4
4
* This source code is licensed under the MIT license found in the
5
5
* LICENSE file in the root directory of this source tree.
6
6
*/
7
-
8
7
package com .reactnativecommunity .imageeditor ;
9
8
10
9
import javax .annotation .Nullable ;
18
17
import java .net .URL ;
19
18
import java .net .URLConnection ;
20
19
import java .util .Arrays ;
21
- import java .util .Collections ;
22
20
import java .util .List ;
23
- import java .util .Map ;
24
21
25
22
import android .annotation .SuppressLint ;
26
23
import android .content .ContentResolver ;
43
40
import com .facebook .react .bridge .ReactApplicationContext ;
44
41
import com .facebook .react .bridge .ReactContext ;
45
42
import com .facebook .react .bridge .ReactContextBaseJavaModule ;
46
- import com .facebook .react .bridge .ReactMethod ;
47
43
import com .facebook .react .bridge .JSApplicationIllegalArgumentException ;
48
44
import com .facebook .react .bridge .ReadableMap ;
49
45
import com .facebook .infer .annotation .Assertions ;
50
46
import com .facebook .react .common .ReactConstants ;
51
47
52
- /**
53
- * Native module that provides image cropping functionality.
54
- */
55
- public class ImageEditorModule extends ReactContextBaseJavaModule {
48
+ public class ImageEditorModuleImpl {
49
+ private ReactApplicationContext reactContext ;
56
50
57
51
protected static final String NAME = "RNCImageEditor" ;
58
52
59
53
private static final List <String > LOCAL_URI_PREFIXES = Arrays .asList (
60
- ContentResolver .SCHEME_FILE ,
61
- ContentResolver .SCHEME_CONTENT ,
62
- ContentResolver .SCHEME_ANDROID_RESOURCE
54
+ ContentResolver .SCHEME_FILE ,
55
+ ContentResolver .SCHEME_CONTENT ,
56
+ ContentResolver .SCHEME_ANDROID_RESOURCE
63
57
);
64
58
65
59
private static final String TEMP_FILE_PREFIX = "ReactNative_cropped_image_" ;
@@ -95,24 +89,13 @@ public class ImageEditorModule extends ReactContextBaseJavaModule {
95
89
ExifInterface .TAG_WHITE_BALANCE
96
90
};
97
91
98
- public ImageEditorModule (ReactApplicationContext reactContext ) {
99
- super (reactContext );
100
- new CleanTask (getReactApplicationContext ()).executeOnExecutor (AsyncTask .THREAD_POOL_EXECUTOR );
101
- }
102
-
103
- @ Override
104
- public String getName () {
105
- return NAME ;
106
- }
107
-
108
- @ Override
109
- public Map <String , Object > getConstants () {
110
- return Collections .emptyMap ();
92
+ public ImageEditorModuleImpl (ReactApplicationContext context ) {
93
+ reactContext = context ;
94
+ new CleanTask (reactContext ).executeOnExecutor (AsyncTask .THREAD_POOL_EXECUTOR );
111
95
}
112
96
113
- @ Override
114
97
public void onCatalystInstanceDestroy () {
115
- new CleanTask (getReactApplicationContext () ).executeOnExecutor (AsyncTask .THREAD_POOL_EXECUTOR );
98
+ new CleanTask (reactContext ).executeOnExecutor (AsyncTask .THREAD_POOL_EXECUTOR );
116
99
}
117
100
118
101
/**
@@ -139,12 +122,12 @@ protected void doInBackgroundGuarded(Void... params) {
139
122
140
123
private void cleanDirectory (File directory ) {
141
124
File [] toDelete = directory .listFiles (
142
- new FilenameFilter () {
143
- @ Override
144
- public boolean accept (File dir , String filename ) {
145
- return filename .startsWith (TEMP_FILE_PREFIX );
146
- }
147
- });
125
+ new FilenameFilter () {
126
+ @ Override
127
+ public boolean accept (File dir , String filename ) {
128
+ return filename .startsWith (TEMP_FILE_PREFIX );
129
+ }
130
+ });
148
131
if (toDelete != null ) {
149
132
for (File file : toDelete ) {
150
133
file .delete ();
@@ -166,30 +149,29 @@ public boolean accept(File dir, String filename) {
166
149
* @param promise Promise to be resolved when the image has been cropped; the only argument that
167
150
* is passed to this is the file:// URI of the new image
168
151
*/
169
- @ ReactMethod
170
152
public void cropImage (
171
- String uri ,
172
- ReadableMap options ,
173
- Promise promise ) {
153
+ String uri ,
154
+ ReadableMap options ,
155
+ Promise promise ) {
174
156
ReadableMap offset = options .hasKey ("offset" ) ? options .getMap ("offset" ) : null ;
175
157
ReadableMap size = options .hasKey ("size" ) ? options .getMap ("size" ) : null ;
176
158
if (offset == null || size == null ||
177
- !offset .hasKey ("x" ) || !offset .hasKey ("y" ) ||
178
- !size .hasKey ("width" ) || !size .hasKey ("height" )) {
159
+ !offset .hasKey ("x" ) || !offset .hasKey ("y" ) ||
160
+ !size .hasKey ("width" ) || !size .hasKey ("height" )) {
179
161
throw new JSApplicationIllegalArgumentException ("Please specify offset and size" );
180
162
}
181
163
if (uri == null || uri .isEmpty ()) {
182
164
throw new JSApplicationIllegalArgumentException ("Please specify a URI" );
183
165
}
184
166
185
167
CropTask cropTask = new CropTask (
186
- getReactApplicationContext () ,
187
- uri ,
188
- (int ) offset .getDouble ("x" ),
189
- (int ) offset .getDouble ("y" ),
190
- (int ) size .getDouble ("width" ),
191
- (int ) size .getDouble ("height" ),
192
- promise );
168
+ reactContext ,
169
+ uri ,
170
+ (int ) offset .getDouble ("x" ),
171
+ (int ) offset .getDouble ("y" ),
172
+ (int ) size .getDouble ("width" ),
173
+ (int ) size .getDouble ("height" ),
174
+ promise );
193
175
if (options .hasKey ("displaySize" )) {
194
176
ReadableMap targetSize = options .getMap ("displaySize" );
195
177
cropTask .setTargetSize (
@@ -211,17 +193,17 @@ private static class CropTask extends GuardedAsyncTask<Void, Void> {
211
193
final Promise mPromise ;
212
194
213
195
private CropTask (
214
- ReactContext context ,
215
- String uri ,
216
- int x ,
217
- int y ,
218
- int width ,
219
- int height ,
220
- Promise promise ) {
196
+ ReactContext context ,
197
+ String uri ,
198
+ int x ,
199
+ int y ,
200
+ int width ,
201
+ int height ,
202
+ Promise promise ) {
221
203
super (context );
222
204
if (x < 0 || y < 0 || width <= 0 || height <= 0 ) {
223
205
throw new JSApplicationIllegalArgumentException (String .format (
224
- "Invalid crop rectangle: [%d, %d, %d, %d]" , x , y , width , height ));
206
+ "Invalid crop rectangle: [%d, %d, %d, %d]" , x , y , width , height ));
225
207
}
226
208
mContext = context ;
227
209
mUri = uri ;
@@ -235,7 +217,7 @@ private CropTask(
235
217
public void setTargetSize (int width , int height ) {
236
218
if (width <= 0 || height <= 0 ) {
237
219
throw new JSApplicationIllegalArgumentException (String .format (
238
- "Invalid target size: [%d, %d]" , width , height ));
220
+ "Invalid target size: [%d, %d]" , width , height ));
239
221
}
240
222
mTargetWidth = width ;
241
223
mTargetHeight = height ;
@@ -314,10 +296,10 @@ private Bitmap crop(BitmapFactory.Options outOptions) throws IOException {
314
296
* @param outOptions Bitmap options, useful to determine {@code outMimeType}.
315
297
*/
316
298
private Bitmap cropAndResize (
317
- int targetWidth ,
318
- int targetHeight ,
319
- BitmapFactory .Options outOptions )
320
- throws IOException {
299
+ int targetWidth ,
300
+ int targetHeight ,
301
+ BitmapFactory .Options outOptions )
302
+ throws IOException {
321
303
Assertions .assertNotNull (outOptions );
322
304
323
305
// Loading large bitmaps efficiently:
@@ -450,7 +432,7 @@ private static Bitmap.CompressFormat getCompressFormatForType(String type) {
450
432
}
451
433
452
434
private static void writeCompressedBitmapToFile (Bitmap cropped , String mimeType , File tempFile )
453
- throws IOException {
435
+ throws IOException {
454
436
OutputStream out = new FileOutputStream (tempFile );
455
437
try {
456
438
cropped .compress (getCompressFormatForType (mimeType ), COMPRESS_QUALITY , out );
@@ -468,7 +450,7 @@ private static void writeCompressedBitmapToFile(Bitmap cropped, String mimeType,
468
450
* @param mimeType the MIME type of the file to create (image/*)
469
451
*/
470
452
private static File createTempFile (Context context , @ Nullable String mimeType )
471
- throws IOException {
453
+ throws IOException {
472
454
File externalCacheDir = context .getExternalCacheDir ();
473
455
File internalCacheDir = context .getCacheDir ();
474
456
File cacheDir ;
@@ -482,7 +464,7 @@ else if (internalCacheDir == null) {
482
464
cacheDir = externalCacheDir ;
483
465
} else {
484
466
cacheDir = externalCacheDir .getFreeSpace () > internalCacheDir .getFreeSpace () ?
485
- externalCacheDir : internalCacheDir ;
467
+ externalCacheDir : internalCacheDir ;
486
468
}
487
469
return File .createTempFile (TEMP_FILE_PREFIX , getFileExtensionForType (mimeType ), cacheDir );
488
470
}
@@ -499,7 +481,7 @@ private static int getDecodeSampleSize(int width, int height, int targetWidth, i
499
481
int halfHeight = height / 2 ;
500
482
int halfWidth = width / 2 ;
501
483
while ((halfWidth / inSampleSize ) >= targetWidth
502
- && (halfHeight / inSampleSize ) >= targetHeight ) {
484
+ && (halfHeight / inSampleSize ) >= targetHeight ) {
503
485
inSampleSize *= 2 ;
504
486
}
505
487
}
0 commit comments