react-native-compressor 1.7.0 → 1.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/README.md +42 -20
  2. package/android/src/main/java/com/reactnativecompressor/CompressorModule.java +31 -22
  3. package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.java +28 -16
  4. package/android/src/main/java/com/reactnativecompressor/Image/utils/ImageCompressorOptions.java +4 -0
  5. package/android/src/main/java/com/reactnativecompressor/Utils/MediaCache.java +65 -0
  6. package/android/src/main/java/com/reactnativecompressor/Utils/Utils.java +161 -2
  7. package/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java +3 -16
  8. package/android/src/oldarch/CompressorSpec.java +13 -7
  9. package/ios/Compressor-Bridging-Header.h +1 -0
  10. package/ios/Compressor.h +3 -2
  11. package/ios/Compressor.mm +56 -24
  12. package/ios/Image/ImageCompressor.h +12 -7
  13. package/ios/Image/ImageCompressor.m +164 -67
  14. package/ios/Image/ImageCompressorOptions.h +1 -0
  15. package/ios/Image/ImageCompressorOptions.m +5 -1
  16. package/ios/Utils/Downloader.h +16 -0
  17. package/ios/Utils/Downloader.m +150 -0
  18. package/ios/Utils/MediaCache.h +11 -0
  19. package/ios/Utils/MediaCache.m +51 -0
  20. package/ios/Video/VideoCompressor.swift +13 -4
  21. package/lib/commonjs/Image/index.js +25 -3
  22. package/lib/commonjs/Image/index.js.map +1 -1
  23. package/lib/commonjs/Spec/NativeCompressor.js.map +1 -1
  24. package/lib/commonjs/Video/index.js +14 -1
  25. package/lib/commonjs/Video/index.js.map +1 -1
  26. package/lib/module/Image/index.js +25 -3
  27. package/lib/module/Image/index.js.map +1 -1
  28. package/lib/module/Spec/NativeCompressor.js.map +1 -1
  29. package/lib/module/Video/index.js +14 -1
  30. package/lib/module/Video/index.js.map +1 -1
  31. package/lib/typescript/Image/index.d.ts +4 -0
  32. package/lib/typescript/Image/index.d.ts.map +1 -1
  33. package/lib/typescript/Spec/NativeCompressor.d.ts +2 -0
  34. package/lib/typescript/Spec/NativeCompressor.d.ts.map +1 -1
  35. package/lib/typescript/Video/index.d.ts +1 -0
  36. package/lib/typescript/Video/index.d.ts.map +1 -1
  37. package/package.json +4 -2
  38. package/src/Image/index.tsx +36 -3
  39. package/src/Spec/NativeCompressor.ts +2 -0
  40. package/src/Video/index.tsx +23 -1
package/README.md CHANGED
@@ -5,18 +5,21 @@
5
5
 
6
6
  <div align="center">
7
7
 
8
- [![GitHub Repo stars](https://img.shields.io/static/v1?style=for-the-badge&message=Discord&color=5865F2&logo=Discord&logoColor=FFFFFF&label=)](https://discord.gg/dtYzk8sp)
8
+ [![GitHub Repo stars](https://img.shields.io/static/v1?style=for-the-badge&message=Discord&color=5865F2&logo=Discord&logoColor=FFFFFF&label=)](https://discord.gg/6Wx8Em8KAN)
9
9
  [![GitHub Repo stars](https://img.shields.io/github/stars/numandev1/react-native-compressor?style=for-the-badge&logo=github)](https://github.com/numandev1/react-native-compressor/stargazers)
10
10
  [![GitHub Repo stars](https://img.shields.io/npm/v/react-native-compressor?style=for-the-badge&message=npm&&color=CB3837&logo=npm&logoColor=FFFFFF&label=)](https://www.npmjs.com/package/react-native-compressor)
11
11
  ![npm](https://img.shields.io/static/v1?style=for-the-badge&message=TypeScript&color=3178C6&logo=TypeScript&logoColor=FFFFFF&label=)
12
12
  ![npm](https://img.shields.io/npm/dt/react-native-compressor?style=for-the-badge)
13
+ [![GitHub Repo stars](https://img.shields.io/badge/PRs-welcome-brightgreen.svg?style=for-the-badge)](http://makeapullrequest.com)
13
14
 
14
15
  </div>
15
16
 
16
- **REACT-NATIVE-COMPRESSOR** is a react-native package, which help us to Compress `Image`, `Video`, and `Audio` same like **Whatsapp** without knowing compression `algorithm`
17
+ **REACT-NATIVE-COMPRESSOR** is a react-native package, which helps us to Compress `Image`, `Video`, and `Audio` before uploading, same like **Whatsapp** without knowing the compression `algorithm`
17
18
 
18
19
  <div align="center">
19
- <img height="60" src="/media/whatsapp_logo.png">
20
+ <img height="90" src="/media/whatsapp_logo.png"/>
21
+ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
22
+ <img height="90" src="/media/compress_media.png"/>
20
23
  <h2 align="center">🗜️Compress Image, Video, and Audio same like Whatsapp</h2>
21
24
  </div>
22
25
 
@@ -81,8 +84,8 @@ yarn add react-native-compressor
81
84
  ```
82
85
 
83
86
  ### [New Architecture (Turbo Module)](https://reactnative.dev/docs/new-architecture-intro) Supported
84
- you can give feedback on [Discord channel](https://discord.gg/dtYzk8sp)
85
87
 
88
+ you can give feedback on [Discord channel](https://discord.gg/dtYzk8sp)
86
89
 
87
90
  ### Managed Expo
88
91
 
@@ -158,8 +161,12 @@ react-native link react-native-compressor
158
161
  ```js
159
162
  import { Image } from 'react-native-compressor';
160
163
 
161
- const result = await Image.compress('file://path_of_file/image.jpg', {
162
- compressionMethod: 'auto',
164
+ const result = await Image.compress('file://path_of_file/image.jpg');
165
+ // OR
166
+ const result = await Image.compress('https://path_of_file/image.jpg', {
167
+ downloadProgress: (progress) => {
168
+ console.log('downloadProgress: ', progress);
169
+ },
163
170
  });
164
171
  ```
165
172
 
@@ -171,6 +178,7 @@ const result = await Image.compress('file://path_of_file/image.jpg', {
171
178
  import { Image } from 'react-native-compressor';
172
179
 
173
180
  const result = await Image.compress('file://path_of_file/image.jpg', {
181
+ compressionMethod: 'manual',
174
182
  maxWidth: 1000,
175
183
  quality: 0.8,
176
184
  });
@@ -185,15 +193,23 @@ import { Video } from 'react-native-compressor';
185
193
 
186
194
  const result = await Video.compress(
187
195
  'file://path_of_file/BigBuckBunny.mp4',
196
+ {},
197
+ (progress) => {
198
+ console.log('Compression Progress: ', progress);
199
+ }
200
+ );
201
+
202
+ //OR
203
+
204
+ const result = await Video.compress(
205
+ 'https://example.com/video.mp4',
188
206
  {
189
- compressionMethod: 'auto',
207
+ downloadProgress: (progress) => {
208
+ console.log('downloadProgress: ', progress);
209
+ },
190
210
  },
191
211
  (progress) => {
192
- if (backgroundMode) {
193
- console.log('Compression Progress: ', progress);
194
- } else {
195
- setCompressingProgress(progress);
196
- }
212
+ console.log('Compression Progress: ', progress);
197
213
  }
198
214
  );
199
215
  ```
@@ -207,13 +223,11 @@ import { Video } from 'react-native-compressor';
207
223
 
208
224
  const result = await Video.compress(
209
225
  'file://path_of_file/BigBuckBunny.mp4',
210
- {},
226
+ {
227
+ compressionMethod: 'manual',
228
+ },
211
229
  (progress) => {
212
- if (backgroundMode) {
213
- console.log('Compression Progress: ', progress);
214
- } else {
215
- setCompressingProgress(progress);
216
- }
230
+ console.log('Compression Progress: ', progress);
217
231
  }
218
232
  );
219
233
  ```
@@ -286,10 +300,14 @@ const uploadResult = await backgroundUpload(
286
300
 
287
301
  ### CompressorOptions
288
302
 
289
- - ###### `compressionMethod: compressionMethod` (default: "manual")
303
+ - ###### `compressionMethod: compressionMethod` (default: "auto")
290
304
 
291
305
  if you want to compress images like **whatsapp** then make this prop `auto`. Can be either `manual` or `auto`, defines the Compression Method.
292
306
 
307
+ - ##### `downloadProgress?: (progress: number) => void;`
308
+
309
+ it is callback, only trigger when we pass image url from server
310
+
293
311
  - ###### `maxWidth: number` (default: 1280)
294
312
 
295
313
  The maximum width boundary used as the main boundary in resizing a landscape image.
@@ -326,11 +344,15 @@ const uploadResult = await backgroundUpload(
326
344
 
327
345
  if you want to compress videos like **whatsapp** then make this prop `auto`. Can be either `manual` or `auto`, defines the Compression Method.
328
346
 
347
+ - ##### `downloadProgress?: (progress: number) => void;`
348
+
349
+ it is callback, only trigger when we pass image url from server
350
+
329
351
  - ###### `maxSize: number` (default: 640)
330
352
 
331
353
  The maximum size can be height in case of portrait video or can be width in case of landscape video.
332
354
 
333
- - ###### `bitrate: string`
355
+ - ###### `bitrate: number`
334
356
 
335
357
  bitrate of video which reduce or increase video size. if compressionMethod will auto then this prop will not work
336
358
 
@@ -6,17 +6,15 @@ import com.facebook.react.bridge.Promise;
6
6
  import com.facebook.react.bridge.ReactApplicationContext;
7
7
  import com.facebook.react.bridge.ReactMethod;
8
8
 
9
- import androidx.annotation.NonNull;
10
- import androidx.annotation.Nullable;
11
9
  import androidx.annotation.RequiresApi;
12
10
 
13
11
  import com.facebook.react.bridge.Arguments;
14
12
  import com.facebook.react.bridge.ReactContext;
15
13
  import com.facebook.react.bridge.ReadableMap;
16
14
  import com.facebook.react.bridge.WritableMap;
17
- import com.facebook.react.modules.core.DeviceEventManagerModule;
18
15
  import com.reactnativecompressor.Image.ImageCompressor;
19
16
  import com.reactnativecompressor.Image.utils.ImageCompressorOptions;
17
+ import com.reactnativecompressor.Utils.MediaCache;
20
18
  import com.reactnativecompressor.Utils.Utils;
21
19
  import com.reactnativecompressor.Video.VideoCompressorHelper;
22
20
  import com.reactnativecompressor.CompressorSpec;
@@ -40,7 +38,7 @@ public class CompressorModule extends CompressorSpec {
40
38
  public static final String NAME = "Compressor";
41
39
  private final ReactApplicationContext reactContext;
42
40
 
43
- CompressorModule(ReactApplicationContext context) {
41
+ public CompressorModule(ReactApplicationContext context) {
44
42
  super(context);
45
43
  this.reactContext = context;
46
44
  }
@@ -51,15 +49,6 @@ public class CompressorModule extends CompressorSpec {
51
49
  return NAME;
52
50
  }
53
51
 
54
-
55
- private void sendEvent(ReactContext reactContext,
56
- String eventName,
57
- @Nullable WritableMap params) {
58
- reactContext
59
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
60
- .emit(eventName, params);
61
- }
62
-
63
52
  //Image
64
53
  @ReactMethod
65
54
  public void image_compress(
@@ -67,8 +56,9 @@ public class CompressorModule extends CompressorSpec {
67
56
  ReadableMap optionMap,
68
57
  Promise promise) {
69
58
  try {
70
- imagePath=Utils.getRealPath(imagePath,reactContext);
71
59
  final ImageCompressorOptions options = ImageCompressorOptions.fromMap(optionMap);
60
+ imagePath=Utils.getRealPath(imagePath,reactContext,options.uuid);
61
+
72
62
 
73
63
  if(options.compressionMethod==ImageCompressorOptions.CompressionMethod.auto)
74
64
  {
@@ -80,6 +70,7 @@ public class CompressorModule extends CompressorSpec {
80
70
  String returnableResult=ImageCompressor.manualCompressImage(imagePath,options,reactContext);
81
71
  promise.resolve(returnableResult);
82
72
  }
73
+ MediaCache.removeCompletedImagePath(imagePath);
83
74
  } catch (Exception ex) {
84
75
  promise.reject(ex);
85
76
  }
@@ -163,17 +154,34 @@ public class CompressorModule extends CompressorSpec {
163
154
  @ReactMethod
164
155
  public void getFileSize(String filePath, Promise promise)
165
156
  {
166
- filePath=Utils.getRealPath(filePath,reactContext);
167
- Uri uri= Uri.parse(filePath);
168
- ContentResolver contentResolver = reactContext.getContentResolver();
169
- long fileSize = getLength(uri, contentResolver);
170
- if (fileSize >= 0) {
171
- promise.resolve(String.valueOf(fileSize));
172
- } else {
173
- promise.resolve("");
157
+ if(filePath.startsWith("http://")||filePath.startsWith("https://"))
158
+ {
159
+ promise.resolve(Utils.getFileSizeFromURL(filePath));
160
+ }
161
+ else
162
+ {
163
+ filePath=Utils.getRealPath(filePath,reactContext);
164
+ Uri uri= Uri.parse(filePath);
165
+ ContentResolver contentResolver = reactContext.getContentResolver();
166
+ long fileSize = getLength(uri, contentResolver);
167
+ if (fileSize >= 0) {
168
+ promise.resolve(String.valueOf(fileSize));
169
+ } else {
170
+ promise.resolve("");
171
+ }
174
172
  }
175
173
  }
176
174
 
175
+ @ReactMethod
176
+ public void addListener(String eventName) {
177
+
178
+ }
179
+
180
+ @ReactMethod
181
+ public void removeListeners(double count) {
182
+
183
+ }
184
+
177
185
  public static long getLength(Uri uri, ContentResolver contentResolver) {
178
186
  AssetFileDescriptor assetFileDescriptor = null;
179
187
  try {
@@ -208,4 +216,5 @@ public class CompressorModule extends CompressorSpec {
208
216
  return -1L;
209
217
  }
210
218
  }
219
+
211
220
  }
@@ -201,22 +201,7 @@ public class ImageCompressor {
201
201
  bmp.recycle();
202
202
  }
203
203
 
204
- ExifInterface exif;
205
- try {
206
- exif = new ExifInterface(imagePath);
207
- int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, 0);
208
- Matrix matrix = new Matrix();
209
- if (orientation == 6) {
210
- matrix.postRotate(90);
211
- } else if (orientation == 3) {
212
- matrix.postRotate(180);
213
- } else if (orientation == 8) {
214
- matrix.postRotate(270);
215
- }
216
- scaledBitmap = Bitmap.createBitmap(scaledBitmap, 0, 0, scaledBitmap.getWidth(), scaledBitmap.getHeight(), matrix, true);
217
- } catch (IOException e) {
218
- e.printStackTrace();
219
- }
204
+ scaledBitmap = correctImageOrientation(scaledBitmap, imagePath);
220
205
 
221
206
  final ByteArrayOutputStream imageDataByteArrayOutputStream = ImageCompressor.compress(scaledBitmap, compressorOptions.output, compressorOptions.quality);
222
207
  String returnableResult = ImageCompressor.encodeImage(imageDataByteArrayOutputStream,isBase64,compressorOptions.output.toString(),reactContext);
@@ -242,4 +227,31 @@ public class ImageCompressor {
242
227
 
243
228
  return inSampleSize;
244
229
  }
230
+
231
+ public static Bitmap correctImageOrientation(Bitmap bitmap, String imagePath) {
232
+ try {
233
+ ExifInterface exif = new ExifInterface(imagePath);
234
+ int orientation = exif.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
235
+ Matrix matrix = new Matrix();
236
+
237
+ switch (orientation) {
238
+ case ExifInterface.ORIENTATION_ROTATE_90:
239
+ matrix.postRotate(90);
240
+ break;
241
+ case ExifInterface.ORIENTATION_ROTATE_180:
242
+ matrix.postRotate(180);
243
+ break;
244
+ case ExifInterface.ORIENTATION_ROTATE_270:
245
+ matrix.postRotate(270);
246
+ break;
247
+ default:
248
+ return bitmap; // No rotation needed
249
+ }
250
+
251
+ return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
252
+ } catch (IOException e) {
253
+ e.printStackTrace();
254
+ return bitmap; // Return original bitmap if an error occurs
255
+ }
256
+ }
245
257
  }
@@ -33,6 +33,9 @@ public class ImageCompressorOptions {
33
33
  case "returnableOutputType":
34
34
  options.returnableOutputType = ReturnableOutputType.valueOf(map.getString(key));
35
35
  break;
36
+ case "uuid":
37
+ options.uuid = map.getString(key);
38
+ break;
36
39
  }
37
40
  }
38
41
 
@@ -61,5 +64,6 @@ public class ImageCompressorOptions {
61
64
  public float quality = 0.8f;
62
65
  public InputType input = InputType.uri;
63
66
  public OutputType output = OutputType.jpg;
67
+ public String uuid = "";
64
68
  public ReturnableOutputType returnableOutputType = ReturnableOutputType.uri;
65
69
  }
@@ -0,0 +1,65 @@
1
+ package com.reactnativecompressor.Utils;
2
+
3
+ import android.util.Log;
4
+
5
+ import java.io.File;
6
+ import java.util.ArrayList;
7
+ import java.util.List;
8
+
9
+ public class MediaCache {
10
+
11
+ private static final String TAG = "MediaCache";
12
+ private static List<String> completedImagePaths = new ArrayList<>();
13
+
14
+ public static void addCompletedImagePath(String imagePath) {
15
+ if (imagePath != null) {
16
+ // Your code to add the imagePath to a list or perform other actions if needed.
17
+ completedImagePaths.add(imagePath);
18
+ Log.d(TAG, "Successfully added image path: " + imagePath);
19
+ }
20
+ }
21
+
22
+ public static void removeCompletedImagePath(String imagePath) {
23
+ if (imagePath != null) {
24
+ if (completedImagePaths.contains(imagePath)) {
25
+ // Image path exists in the list, so remove it
26
+ completedImagePaths.remove(imagePath);
27
+
28
+ if (imagePath.startsWith("file://")) {
29
+ imagePath = imagePath.substring(7); // Remove "file://"
30
+ }
31
+
32
+ // Remove the image file
33
+ File file = new File(imagePath);
34
+ if (file.exists()) {
35
+ if (file.delete()) {
36
+ Log.d(TAG, "Successfully deleted image file: " + imagePath);
37
+ } else {
38
+ Log.d(TAG, "Failed to delete image file: " + imagePath);
39
+ }
40
+ } else {
41
+ Log.d(TAG, "Image file not found: " + imagePath);
42
+ }
43
+ } else {
44
+ Log.d(TAG, "Image path not found in the completedImagePaths list: " + imagePath);
45
+ }
46
+ }
47
+ }
48
+
49
+ public static void cleanupCache() {
50
+ // Iterate through the list of completed image paths and delete the corresponding files
51
+ for (String imagePath : completedImagePaths) {
52
+ File file = new File(imagePath);
53
+ if (file.exists()) {
54
+ if (file.delete()) {
55
+ Log.d(TAG, "Successfully deleted image file during cache cleanup: " + imagePath);
56
+ } else {
57
+ Log.d(TAG, "Failed to delete image file during cache cleanup: " + imagePath);
58
+ }
59
+ } else {
60
+ Log.d(TAG, "Image file not found during cache cleanup: " + imagePath);
61
+ }
62
+ }
63
+ completedImagePaths.clear();
64
+ }
65
+ }
@@ -13,10 +13,26 @@ import com.facebook.react.bridge.WritableMap;
13
13
  import com.facebook.react.modules.core.DeviceEventManagerModule;
14
14
  import numan.dev.videocompressor.VideoCompressTask;
15
15
  import numan.dev.videocompressor.VideoCompressor;
16
+
17
+ import okhttp3.Call;
18
+ import okhttp3.Callback;
19
+ import okhttp3.OkHttpClient;
20
+ import okhttp3.Request;
21
+ import okhttp3.Response;
22
+ import okhttp3.ResponseBody;
23
+
24
+ import java.io.BufferedInputStream;
16
25
  import java.io.File;
26
+ import java.io.FileOutputStream;
27
+ import java.io.IOException;
28
+ import java.net.HttpURLConnection;
29
+ import java.net.URL;
30
+ import java.net.URLConnection;
17
31
  import java.util.HashMap;
18
32
  import java.util.Map;
19
33
  import java.util.UUID;
34
+ import java.util.concurrent.Semaphore;
35
+ import java.util.concurrent.atomic.AtomicReference;
20
36
 
21
37
  public class Utils {
22
38
  static int videoCompressionThreshold=10;
@@ -41,8 +57,10 @@ public class Utils {
41
57
  }
42
58
  @Override
43
59
  public void onFinish(boolean result) {
60
+ String fileUrl="file://"+destinationPath;
44
61
  //convert finish,result(true is success,false is fail)
45
- promise.resolve("file://"+destinationPath);
62
+ promise.resolve(fileUrl);
63
+ MediaCache.removeCompletedImagePath(fileUrl);
46
64
  }
47
65
 
48
66
  @Override
@@ -97,7 +115,25 @@ public class Utils {
97
115
  .emit(eventName, params);
98
116
  }
99
117
 
100
- public static String getRealPath(String fileUrl,ReactApplicationContext reactContext){
118
+ public static int getFileSizeFromURL(String urlString) {
119
+ URL url;
120
+ HttpURLConnection conn = null;
121
+ try {
122
+ url = new URL(urlString);
123
+ conn = (HttpURLConnection) url.openConnection();
124
+ conn.setRequestMethod("HEAD");
125
+ conn.getInputStream();
126
+ return conn.getContentLength();
127
+ } catch (IOException e) {
128
+ throw new RuntimeException(e);
129
+ } finally {
130
+ if (conn != null) {
131
+ conn.disconnect();
132
+ }
133
+ }
134
+ }
135
+
136
+ public static String getRealPath(String fileUrl,ReactApplicationContext reactContext, String... args){
101
137
  if(fileUrl.startsWith("content://"))
102
138
  {
103
139
  try {
@@ -108,6 +144,129 @@ public class Utils {
108
144
  Log.d(TAG, " Please see this issue: https://github.com/numandev1/react-native-compressor/issues/25");
109
145
  }
110
146
  }
147
+ else if(fileUrl.startsWith("http://")||fileUrl.startsWith("https://"))
148
+ {
149
+ String uuid = (args.length > 0) ? args[0] : "";
150
+ fileUrl=downloadMediaWithProgress(fileUrl,reactContext, uuid);
151
+ Log.d(TAG, "getRealPath: "+fileUrl);
152
+ }
153
+
111
154
  return fileUrl;
112
155
  }
156
+
157
+ public static String downloadMediaWithProgress(String mediaUrl, ReactApplicationContext reactContext, String uuid) {
158
+ downloadCompression[0]=0;
159
+ OkHttpClient client = new OkHttpClient();
160
+
161
+ Request request = new Request.Builder()
162
+ .url(mediaUrl)
163
+ .build();
164
+
165
+ final Semaphore semaphore = new Semaphore(0); // Semaphore to wait for the download to complete
166
+ final AtomicReference<String> filePathRef = new AtomicReference<>(null); // To store the file path
167
+
168
+ // Perform the request asynchronously
169
+ client.newCall(request).enqueue(new Callback() {
170
+ @Override
171
+ public void onResponse(Call call, Response response) throws IOException {
172
+ if (response.isSuccessful()) {
173
+ ResponseBody responseBody = response.body();
174
+ if (responseBody != null) {
175
+ String fileExtension = "unknown"; // Default extension
176
+
177
+ // Detect the file extension based on the Content-Type header
178
+ String contentType = response.header("Content-Type");
179
+ if (contentType != null) {
180
+ if (contentType.equals("image/jpeg")) {
181
+ fileExtension = "jpg";
182
+ } else if (contentType.equals("image/png")) {
183
+ fileExtension = "png";
184
+ } else if (contentType.equals("video/mp4")) {
185
+ fileExtension = "mp4";
186
+ }
187
+ }
188
+
189
+ File cacheDir = reactContext.getCacheDir();
190
+ String randomFileName = UUID.randomUUID().toString() + "." + fileExtension;
191
+ File mediaFile = new File(cacheDir, randomFileName);
192
+
193
+ try (FileOutputStream fos = new FileOutputStream(mediaFile)) {
194
+ BufferedInputStream inputStream = new BufferedInputStream(responseBody.byteStream());
195
+ byte[] buffer = new byte[4096];
196
+ int bytesRead;
197
+ long totalBytesRead = 0;
198
+ long totalBytes = responseBody.contentLength();
199
+
200
+ if (totalBytes <= 0) {
201
+ totalBytes = 31457280;
202
+ }
203
+
204
+ Log.d(TAG, totalBytesRead+" totalBytesRead "+totalBytes);
205
+ Log.d(TAG, response.toString()+" responseBody "+responseBody.toString());
206
+ while ((bytesRead = inputStream.read(buffer)) != -1) {
207
+ fos.write(buffer, 0, bytesRead);
208
+ totalBytesRead += bytesRead;
209
+ double progressRatio = (double) totalBytesRead / totalBytes;
210
+ int progress = (int) (progressRatio * 100);
211
+ sendProgressUpdate(progress, uuid, reactContext);
212
+ }
213
+ fos.flush();
214
+ String filePath="file://" + mediaFile.getAbsolutePath();
215
+ MediaCache.addCompletedImagePath(filePath);
216
+ filePathRef.set(filePath); // Set the file path
217
+ } catch (IOException e) {
218
+ e.printStackTrace();
219
+ sendErrorResult(e.getMessage(), uuid, reactContext);
220
+ } finally {
221
+ semaphore.release(); // Release the semaphore when download is complete
222
+ }
223
+ }
224
+ } else {
225
+ sendErrorResult("Failed to download media: " + response.message(), uuid, reactContext);
226
+ semaphore.release(); // Release the semaphore in case of error
227
+ }
228
+ }
229
+
230
+ @Override
231
+ public void onFailure(Call call, IOException e) {
232
+ e.printStackTrace();
233
+ sendErrorResult(e.getMessage(), uuid, reactContext);
234
+ semaphore.release(); // Release the semaphore in case of failure
235
+ }
236
+ });
237
+
238
+ try {
239
+ semaphore.acquire(); // Wait for the download to complete
240
+ } catch (InterruptedException e) {
241
+ e.printStackTrace();
242
+ }
243
+
244
+ return filePathRef.get(); // Return the file path
245
+ }
246
+ static final int[] downloadCompression = {0};
247
+ private static void sendProgressUpdate(int progress, String uuid, ReactApplicationContext reactContext) {
248
+ int roundProgress=Math.round(progress);
249
+ if(roundProgress%videoCompressionThreshold==0&&roundProgress> downloadCompression[0]) {
250
+ WritableMap params = Arguments.createMap();
251
+ WritableMap data = Arguments.createMap();
252
+ params.putString("uuid", uuid);
253
+ data.putDouble("progress", progress / 100.0);
254
+ params.putMap("data", data);
255
+ sendEvent(reactContext, "downloadProgress", params);
256
+ Log.d(TAG, "downloadProgress: " + (progress / 100.0));
257
+ downloadCompression[0] =roundProgress;
258
+ }
259
+ }
260
+
261
+ private static void sendErrorResult(String error, String uuid, ReactApplicationContext reactContext) {
262
+ WritableMap params = Arguments.createMap();
263
+ WritableMap data = Arguments.createMap();
264
+ params.putString("uuid", uuid);
265
+ params.putString("error", error);
266
+ params.putMap("data", data);
267
+ Log.d(TAG, "videoDownloadError: "+error);
268
+ sendEvent(reactContext, "videoDownloadError", params);
269
+ }
270
+
271
+
113
272
  }
@@ -8,13 +8,9 @@ import androidx.annotation.Nullable;
8
8
 
9
9
  import com.facebook.react.bridge.Promise;
10
10
  import com.facebook.react.bridge.ReactApplicationContext;
11
- import com.facebook.react.bridge.ReactContext;
12
- import com.facebook.react.bridge.ReactContextBaseJavaModule;
13
11
  import com.facebook.react.bridge.ReactMethod;
14
12
  import com.facebook.react.bridge.ReadableMap;
15
- import com.facebook.react.bridge.WritableMap;
16
- import com.facebook.react.module.annotations.ReactModule;
17
- import com.facebook.react.modules.core.DeviceEventManagerModule;
13
+ import com.reactnativecompressor.Utils.MediaCache;
18
14
  import com.reactnativecompressor.VideoCompressorSpec;
19
15
  import com.reactnativecompressor.Utils.RealPathUtil;
20
16
 
@@ -41,14 +37,6 @@ public class VideoModule extends VideoCompressorSpec {
41
37
  return NAME;
42
38
  }
43
39
 
44
- private void sendEvent(ReactContext reactContext,
45
- String eventName,
46
- @Nullable WritableMap params) {
47
- reactContext
48
- .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
49
- .emit(eventName, params);
50
- }
51
-
52
40
  //Video
53
41
  @ReactMethod
54
42
  public void compress(
@@ -56,7 +44,8 @@ public class VideoModule extends VideoCompressorSpec {
56
44
  ReadableMap optionMap,
57
45
  Promise promise) {
58
46
  final VideoCompressorHelper options = VideoCompressorHelper.fromMap(optionMap);
59
- fileUrl=getRealPath(fileUrl,reactContext);
47
+
48
+ fileUrl=getRealPath(fileUrl,reactContext,options.uuid);
60
49
 
61
50
  if(options.compressionMethod==VideoCompressorHelper.CompressionMethod.auto)
62
51
  {
@@ -66,8 +55,6 @@ public class VideoModule extends VideoCompressorSpec {
66
55
  {
67
56
  VideoCompressorHelper.VideoCompressManual(fileUrl,options,promise,reactContext);
68
57
  }
69
-
70
-
71
58
  }
72
59
 
73
60
  @ReactMethod
@@ -11,18 +11,24 @@ abstract class CompressorSpec extends ReactContextBaseJavaModule {
11
11
  }
12
12
 
13
13
  public abstract void image_compress(
14
- String imagePath,
15
- ReadableMap optionMap,
16
- Promise promise);
14
+ String imagePath,
15
+ ReadableMap optionMap,
16
+ Promise promise);
17
17
 
18
18
  public abstract void compress_audio(
19
- String fileUrl,
20
- ReadableMap optionMap,
21
- Promise promise);
19
+ String fileUrl,
20
+ ReadableMap optionMap,
21
+ Promise promise);
22
22
 
23
23
  public abstract void generateFilePath(String extension, Promise promise);
24
- public abstract void getRealPath(String path,String type, Promise promise);
24
+
25
+ public abstract void getRealPath(String path, String type, Promise promise);
26
+
25
27
  public abstract void getVideoMetaData(String filePath, Promise promise);
26
28
 
27
29
  public abstract void getFileSize(String filePath, Promise promise);
30
+
31
+ public abstract void addListener(String eventName);
32
+
33
+ public abstract void removeListeners(double count);
28
34
  }
@@ -4,3 +4,4 @@
4
4
  #import <React/RCTBridgeModule.h>
5
5
  #import <React/RCTEventEmitter.h>
6
6
  #import "ImageCompressor.h"
7
+ #import "MediaCache.h"
package/ios/Compressor.h CHANGED
@@ -1,12 +1,13 @@
1
+ #import <React/RCTEventEmitter.h>
1
2
 
2
3
  #ifdef RCT_NEW_ARCH_ENABLED
3
4
  #import "RNCompressorSpec.h"
4
5
 
5
- @interface Compressor : NSObject <NativeCompressorSpec>
6
+ @interface Compressor : RCTEventEmitter <NativeCompressorSpec>
6
7
  #else
7
8
  #import <React/RCTBridgeModule.h>
8
9
 
9
- @interface Compressor : NSObject <RCTBridgeModule>
10
+ @interface Compressor : RCTEventEmitter <RCTBridgeModule>
10
11
  #endif
11
12
 
12
13
  @end