Skip to content

Commit ef185ed

Browse files
Merge pull request #9 from IslamRustamov/feature/add-compressPhotoArray
feat: add compressPhotoArray method
2 parents 21b0862 + 148d7cb commit ef185ed

File tree

7 files changed

+396
-145
lines changed

7 files changed

+396
-145
lines changed

README.md

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -30,13 +30,14 @@ RCT_NEW_ARCH_ENABLED=1 bundle exec pod install
3030
## Usage
3131

3232
```js
33-
import { compressPhoto, getSizeInBytes, deletePhoto } from 'react-native-photo-compressor';
33+
import { compressPhoto, compressPhotos, getSizeInBytes, deletePhoto } from 'react-native-photo-compressor';
3434

3535
// ...
3636

3737
const compressedPhoto = await compressPhoto('file://some/photo.png', 50);
3838
const remoteCompressedPhoto = await compressPhoto('http://remote/photo.png', 50);
3939
const namedCompressedPhoto = await compressPhoto('file://some/photo.png', 50, 'myFileName', true);
40+
const compressedPhotos = await compressPhotos(['file://some/photo_1.png', 'file://some/photo_2.png'], 50);
4041

4142
const photoSize = await getSizeInBytes('file://some/photo.png');
4243
await deletePhoto('file://some/photo.png');
@@ -48,12 +49,23 @@ await deletePhoto('file://some/photo.png');
4849
Creates a compressed copy of the image at the given ```uri``` inside a ```/RNPhotoCompressorImages``` directory.</br>
4950
Also supports images from web url. In this case ```uri``` should start with ```"http"```.
5051

51-
| Argument | Info |
52-
|---------------|---------------------------------------------------------------------------------------------------------|
53-
| uri | string, path to the photo, must contain *file://* prefix |
54-
| quality | number, value from 0 to 100 (smaller number -> more compression) |
55-
| fileName? | string, optional name of the compressed photo |
56-
| forceRewrite? | boolean, optional flag to force the file to be overwritten if a file with the given name already exists |
52+
| Argument | Info |
53+
|---------------|-------------------------------------------------------------------------------------------------------------------------------|
54+
| uri | string, path to the photo, must contain *file://* prefix |
55+
| quality | number, value from 0 to 100 (smaller number -> more compression) |
56+
| fileName? | string, optional name of the compressed photo |
57+
| forceRewrite? | boolean, optional flag to force the file to be overwritten if a file with the given name already exists. Default: ```false``` |
58+
59+
### ```compressPhotos(photos: string[], quality: number, onProgress?: (progress: number) => void): Promise<string[]>```
60+
Creates a compressed copy of the images by uri from a given ```photos``` array inside a ```/RNPhotoCompressorImages``` directory.</br>
61+
Also supports images from web url. In this case ```uri``` should start with ```"http"```.
62+
63+
| Argument | Info |
64+
|-------------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
65+
| photos | string[], paths to the photo, must contain *file://* prefix |
66+
| quality | number, value from 0 to 100 (smaller number -> more compression) |
67+
| rejectAll? | boolean, optional flag indicating whether to reject all if compression of one image fails, otherwise rejected images will return null. Default: ```true``` |
68+
| onProgress? | (progress: number) => void, optional callback that triggers when the image in the array has completed compression. ```progress``` returns the index of elements that have completed compression. |
5769

5870
### ```getSizeInBytes(uri: string, size?: SizeType): Promise<number>```
5971
Returns the size of the file in bytes at the given ```uri```.

android/src/main/java/com/photocompressor/PhotoCompressorModule.java

Lines changed: 167 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,11 @@
1313

1414
import com.facebook.react.bridge.ReactApplicationContext;
1515
import com.facebook.react.bridge.Promise;
16+
import com.facebook.react.bridge.ReadableArray;
17+
import com.facebook.react.bridge.WritableNativeArray;
1618
import com.facebook.react.module.annotations.ReactModule;
1719
import com.facebook.react.bridge.GuardedAsyncTask;
20+
import com.facebook.react.modules.core.DeviceEventManagerModule;
1821

1922
import java.io.File;
2023
import java.io.FileOutputStream;
@@ -39,7 +42,7 @@ public String getName() {
3942

4043
@Override
4144
public void compressPhoto(String uri, double quality, String fileName, Boolean forceRewrite, Promise promise) {
42-
CompressStrategy compressStrategy = new CompressStrategy(
45+
CompressPhotoStrategy compressPhotoStrategy = new CompressPhotoStrategy(
4346
mContext,
4447
uri,
4548
quality,
@@ -48,7 +51,20 @@ public void compressPhoto(String uri, double quality, String fileName, Boolean f
4851
promise
4952
);
5053

51-
compressStrategy.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
54+
compressPhotoStrategy.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
55+
}
56+
57+
@Override
58+
public void compressPhotos(ReadableArray photos, double quality, Boolean rejectAll, Promise promise) {
59+
CompressPhotosStrategy compressPhotosStrategy = new CompressPhotosStrategy(
60+
mContext,
61+
photos,
62+
quality,
63+
rejectAll,
64+
promise
65+
);
66+
67+
compressPhotosStrategy.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
5268
}
5369

5470
@Override
@@ -74,6 +90,155 @@ public void deletePhoto(String uri, Promise promise) {
7490
deleteStrategy.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
7591
}
7692

93+
@Override
94+
public void addListener(String eventName) {}
95+
96+
@Override
97+
public void removeListeners(double count) {}
98+
99+
private static String compressImage(
100+
ReactApplicationContext mContext,
101+
String mUri,
102+
double mQuality,
103+
String mFileName,
104+
Boolean mForceRewrite,
105+
Promise mPromise
106+
) {
107+
Bitmap bitmap;
108+
109+
try {
110+
Uri imageUri = Uri.parse(mUri);
111+
112+
if (mUri.startsWith("http")) {
113+
URL url = new URL(mUri);
114+
bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
115+
} else {
116+
bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), imageUri);
117+
}
118+
119+
File cacheDir = mContext.getExternalCacheDir();
120+
121+
File folder = new File(cacheDir, "/RNPhotoCompressorImages/");
122+
if (!folder.exists()) {
123+
folder.mkdirs();
124+
}
125+
126+
File fileName;
127+
if (mFileName instanceof String) {
128+
fileName = new File(folder, "/" + mFileName + ".jpeg");
129+
} else {
130+
String uniqueID = UUID.randomUUID().toString();
131+
fileName = new File(folder, "/" + uniqueID + ".jpeg");
132+
}
133+
134+
if (fileName.exists() && !mForceRewrite) {
135+
throw new Exception("File with this name already exists");
136+
}
137+
138+
FileOutputStream out = new FileOutputStream(String.valueOf(fileName));
139+
bitmap.compress(Bitmap.CompressFormat.JPEG, (int) mQuality, out);
140+
out.close();
141+
142+
String res = "file://" + String.valueOf(fileName);
143+
return res;
144+
} catch (Exception e) {
145+
if (mPromise != null) {
146+
mPromise.reject(e);
147+
}
148+
}
149+
150+
return null;
151+
}
152+
153+
private static class CompressPhotoStrategy extends GuardedAsyncTask<Void, Void> {
154+
final ReactApplicationContext mContext;
155+
final Promise mPromise;
156+
final String mUri;
157+
final double mQuality;
158+
final String mFileName;
159+
final Boolean mForceRewrite;
160+
161+
private CompressPhotoStrategy(
162+
ReactApplicationContext context,
163+
String uri,
164+
double quality,
165+
String fileName,
166+
Boolean forceRewrite,
167+
Promise promise
168+
) {
169+
super(context);
170+
mContext = context;
171+
mPromise = promise;
172+
mUri = uri;
173+
mQuality = quality;
174+
mFileName = fileName;
175+
mForceRewrite = forceRewrite;
176+
}
177+
178+
@Override
179+
protected void doInBackgroundGuarded(Void... params) {
180+
try {
181+
String res = compressImage(mContext, mUri, mQuality, mFileName, mForceRewrite, mPromise);
182+
183+
mPromise.resolve(res);
184+
} catch (Exception e) {
185+
mPromise.reject(e);
186+
}
187+
}
188+
}
189+
190+
private static class CompressPhotosStrategy extends GuardedAsyncTask<Void, Void> {
191+
final ReactApplicationContext mContext;
192+
final Promise mPromise;
193+
final ReadableArray mPhotos;
194+
final double mQuality;
195+
final Boolean mRejectAll;
196+
197+
private CompressPhotosStrategy(
198+
ReactApplicationContext context,
199+
ReadableArray photos,
200+
double quality,
201+
Boolean rejectAll,
202+
Promise promise
203+
) {
204+
super(context);
205+
mContext = context;
206+
mPromise = promise;
207+
mPhotos = photos;
208+
mQuality = quality;
209+
mRejectAll = rejectAll;
210+
}
211+
212+
@Override
213+
protected void doInBackgroundGuarded(Void... params) {
214+
WritableNativeArray res = new WritableNativeArray();
215+
216+
try {
217+
for (int i = 0; i < mPhotos.size(); i++) {
218+
String mUri = mPhotos.getString(i);
219+
220+
String compressedImage = compressImage(mContext, mUri, mQuality, null, null, null);
221+
if (compressedImage == null && mRejectAll) {
222+
throw new Exception(String.format("Compression of image at index %s was failed.", i));
223+
}
224+
225+
res.pushString(compressedImage);
226+
227+
mContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class).emit("compressProgress", (double) i);
228+
}
229+
230+
mPromise.resolve(res);
231+
} catch (Exception e) {
232+
for (int i = 0; i < res.size(); i++) {
233+
File file = new File(res.getString(i).replace("file://", ""));
234+
file.delete();
235+
}
236+
237+
mPromise.reject(e);
238+
}
239+
}
240+
}
241+
77242
private static class SizeStrategy extends GuardedAsyncTask<Void, Void> {
78243
final ReactApplicationContext mContext;
79244
final Promise mPromise;
@@ -165,73 +330,4 @@ protected void doInBackgroundGuarded(Void... params) {
165330
}
166331
}
167332
}
168-
169-
private static class CompressStrategy extends GuardedAsyncTask<Void, Void> {
170-
final ReactApplicationContext mContext;
171-
final Promise mPromise;
172-
final String mUri;
173-
final double mQuality;
174-
final String mFileName;
175-
final Boolean mForceRewrite;
176-
177-
private CompressStrategy(
178-
ReactApplicationContext context,
179-
String uri,
180-
double quality,
181-
String fileName,
182-
boolean forceRewrite,
183-
Promise promise
184-
) {
185-
super(context);
186-
mContext = context;
187-
mPromise = promise;
188-
mUri = uri;
189-
mQuality = quality;
190-
mFileName = fileName;
191-
mForceRewrite = forceRewrite;
192-
}
193-
194-
@Override
195-
protected void doInBackgroundGuarded(Void... params) {
196-
Bitmap bitmap;
197-
198-
try {
199-
Uri imageUri = Uri.parse(mUri);
200-
201-
if (mUri.startsWith("http")) {
202-
URL url = new URL(mUri);
203-
bitmap = BitmapFactory.decodeStream(url.openConnection().getInputStream());
204-
} else {
205-
bitmap = MediaStore.Images.Media.getBitmap(mContext.getContentResolver(), imageUri);
206-
}
207-
208-
File cacheDir = mContext.getExternalCacheDir();
209-
210-
File folder = new File(cacheDir, "/RNPhotoCompressorImages/");
211-
if (!folder.exists()) {
212-
folder.mkdirs();
213-
}
214-
215-
File fileName;
216-
if (mFileName instanceof String) {
217-
fileName = new File(folder, "/" + mFileName + ".jpeg");
218-
} else {
219-
String uniqueID = UUID.randomUUID().toString();
220-
fileName = new File(folder, "/" + uniqueID + ".jpeg");
221-
}
222-
223-
if (fileName.exists() && !mForceRewrite) {
224-
throw new Exception("File with this name already exists");
225-
}
226-
227-
FileOutputStream out = new FileOutputStream(String.valueOf(fileName));
228-
bitmap.compress(Bitmap.CompressFormat.JPEG, (int) mQuality, out);
229-
out.close();
230-
231-
mPromise.resolve("file://" + String.valueOf(fileName));
232-
} catch (Exception e) {
233-
mPromise.reject(e);
234-
}
235-
}
236-
}
237333
}

0 commit comments

Comments
 (0)