react-native-compressor 0.5.12 → 0.5.17

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 (45) hide show
  1. package/README.md +74 -1
  2. package/android/.gradle/6.1.1/fileHashes/fileHashes.lock +0 -0
  3. package/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock +0 -0
  4. package/android/.gradle/buildOutputCleanup/cache.properties +2 -2
  5. package/android/.gradle/checksums/checksums.lock +0 -0
  6. package/android/.gradle/checksums/sha1-checksums.bin +0 -0
  7. package/android/build.gradle +40 -44
  8. package/android/src/main/java/com/.DS_Store +0 -0
  9. package/android/src/main/java/com/reactnativecompressor/.DS_Store +0 -0
  10. package/android/src/main/java/com/reactnativecompressor/Audio/AudioCompressor.java +0 -6
  11. package/android/src/main/java/com/reactnativecompressor/CompressorModule.java +46 -37
  12. package/android/src/main/java/com/reactnativecompressor/Utils/RealPathUtil.java +210 -0
  13. package/android/src/main/java/com/reactnativecompressor/Utils/Utils.java +32 -1
  14. package/android/src/main/java/com/reactnativecompressor/Video/AutoVideoCompression/AutoVideoCompression.java +24 -58
  15. package/android/src/main/java/com/reactnativecompressor/Video/VideoCompressorHelper.java +6 -42
  16. package/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java +23 -15
  17. package/ios/.DS_Store +0 -0
  18. package/ios/Compressor-Bridging-Header.h +1 -1
  19. package/ios/Compressor.m +120 -12
  20. package/ios/Image/ImageCompressor.h +2 -0
  21. package/ios/Image/ImageCompressor.m +153 -1
  22. package/ios/Video/VideoCompressor.swift +56 -59
  23. package/lib/commonjs/Audio/index.js.map +1 -1
  24. package/lib/commonjs/Video/index.js +46 -31
  25. package/lib/commonjs/Video/index.js.map +1 -1
  26. package/lib/commonjs/index.js +22 -1
  27. package/lib/commonjs/index.js.map +1 -1
  28. package/lib/commonjs/utils/index.js +18 -4
  29. package/lib/commonjs/utils/index.js.map +1 -1
  30. package/lib/module/Audio/index.js.map +1 -1
  31. package/lib/module/Video/index.js +39 -30
  32. package/lib/module/Video/index.js.map +1 -1
  33. package/lib/module/index.js +6 -3
  34. package/lib/module/index.js.map +1 -1
  35. package/lib/module/utils/index.js +9 -4
  36. package/lib/module/utils/index.js.map +1 -1
  37. package/lib/typescript/Video/index.d.ts +4 -0
  38. package/lib/typescript/index.d.ts +5 -2
  39. package/lib/typescript/utils/index.d.ts +3 -0
  40. package/package.json +1 -1
  41. package/react-native-compressor.podspec +1 -1
  42. package/src/Audio/index.tsx +1 -1
  43. package/src/Video/index.tsx +49 -37
  44. package/src/index.tsx +13 -1
  45. package/src/utils/index.tsx +14 -3
@@ -1,94 +1,60 @@
1
1
  package com.reactnativecompressor.Video.AutoVideoCompression;
2
2
 
3
- import android.media.MediaCodecInfo;
4
3
  import android.media.MediaMetadataRetriever;
5
- import android.media.session.MediaController;
6
4
  import android.net.Uri;
7
- import android.os.Build;
8
5
 
9
6
  import androidx.annotation.Nullable;
10
7
 
11
- import com.facebook.react.bridge.Arguments;
12
8
  import com.facebook.react.bridge.Promise;
13
9
  import com.facebook.react.bridge.ReactApplicationContext;
14
10
  import com.facebook.react.bridge.ReactContext;
15
11
  import com.facebook.react.bridge.WritableMap;
16
12
  import com.facebook.react.modules.core.DeviceEventManagerModule;
17
13
  import com.reactnativecompressor.Video.VideoCompressorHelper;
18
- import com.zolad.videoslimmer.VideoSlimmer;
14
+ import static com.reactnativecompressor.Utils.Utils.compressVideo;
19
15
 
20
16
  import java.io.File;
21
17
 
22
18
  import static com.reactnativecompressor.Utils.Utils.generateCacheFilePath;
23
19
 
24
20
  public class AutoVideoCompression {
25
- static int videoCompressionThreshold=10;
26
- static int currentVideoCompression=0;
27
-
28
21
  public static void createCompressionSettings(String fileUrl,VideoCompressorHelper options,Promise promise, ReactApplicationContext reactContext) {
29
22
  float maxSize = options.maxSize;
30
23
  float minimumFileSizeForCompress=options.minimumFileSizeForCompress;
31
24
  try{
32
- Uri uri= Uri.parse(fileUrl);
33
- String srcPath = uri.getPath();
34
- MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
35
- metaRetriever.setDataSource(srcPath);
36
- File file=new File(srcPath);
37
- float sizeInBytes = file.length();
38
- float sizeInMb = sizeInBytes / (1024 * 1024);
39
- if(sizeInMb>minimumFileSizeForCompress)
40
- {
41
- String destinationPath = generateCacheFilePath("mp4", reactContext);
42
- int actualHeight =Integer.parseInt(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
43
- int actualWidth = Integer.parseInt(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
44
- int bitrate = Integer.parseInt(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE));
45
-
46
- float scale = actualWidth > actualHeight ? maxSize / actualWidth : maxSize / actualHeight;
47
- int resultWidth = Math.round(actualWidth * scale / 2) * 2;
48
- int resultHeight = Math.round(actualHeight * scale / 2) * 2;
49
-
50
- float videoBitRate = makeVideoBitrate(
51
- actualHeight, actualWidth,
52
- bitrate,
53
- resultHeight, resultWidth
54
- );
25
+ Uri uri= Uri.parse(fileUrl);
26
+ String srcPath = uri.getPath();
27
+ MediaMetadataRetriever metaRetriever = new MediaMetadataRetriever();
28
+ metaRetriever.setDataSource(srcPath);
29
+ File file=new File(srcPath);
30
+ float sizeInBytes = file.length();
31
+ float sizeInMb = sizeInBytes / (1024 * 1024);
32
+ if(sizeInMb>minimumFileSizeForCompress)
33
+ {
34
+ String destinationPath = generateCacheFilePath("mp4", reactContext);
35
+ int actualHeight =Integer.parseInt(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_HEIGHT));
36
+ int actualWidth = Integer.parseInt(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_VIDEO_WIDTH));
37
+ int bitrate = Integer.parseInt(metaRetriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_BITRATE));
55
38
 
56
- VideoSlimmer.convertVideo(srcPath, destinationPath, resultWidth, resultHeight, (int) videoBitRate, new VideoSlimmer.ProgressListener() {
57
- @Override
58
- public void onStart() {
59
- //convert start
60
- }
61
- @Override
62
- public void onFinish(boolean result) {
63
- //convert finish,result(true is success,false is fail)
64
- promise.resolve("file:/"+destinationPath);
65
- }
66
- @Override
67
- public void onProgress(float percent) {
68
- int roundProgress=Math.round(percent);
69
- if(roundProgress%videoCompressionThreshold==0&&roundProgress>currentVideoCompression) {
70
- WritableMap params = Arguments.createMap();
71
- WritableMap data = Arguments.createMap();
72
- params.putString("uuid", options.uuid);
73
- data.putDouble("progress", percent / 100);
74
- params.putMap("data", data);
75
- sendEvent(reactContext, "videoCompressProgress", params);
76
- currentVideoCompression=roundProgress;
77
- }
78
- }
79
- });
39
+ float scale = actualWidth > actualHeight ? maxSize / actualWidth : maxSize / actualHeight;
40
+ int resultWidth = Math.round(actualWidth * scale / 2) * 2;
41
+ int resultHeight = Math.round(actualHeight * scale / 2) * 2;
80
42
 
43
+ float videoBitRate = makeVideoBitrate(
44
+ actualHeight, actualWidth,
45
+ bitrate,
46
+ resultHeight, resultWidth
47
+ );
48
+ compressVideo(srcPath, destinationPath, resultWidth, resultHeight, videoBitRate,options.uuid,promise,reactContext);
81
49
  }
82
50
  else
83
51
  {
84
52
  promise.resolve(fileUrl);
85
53
  }
54
+
86
55
  } catch (Exception ex) {
87
56
  promise.reject(ex);
88
57
  }
89
- finally {
90
- currentVideoCompression=0;
91
- }
92
58
  }
93
59
 
94
60
  public static int makeVideoBitrate(int originalHeight, int originalWidth, int originalBitrate, int height, int width) {
@@ -8,7 +8,6 @@ import android.os.PowerManager;
8
8
 
9
9
  import androidx.annotation.Nullable;
10
10
 
11
- import com.facebook.react.bridge.Arguments;
12
11
  import com.facebook.react.bridge.LifecycleEventListener;
13
12
  import com.facebook.react.bridge.Promise;
14
13
  import com.facebook.react.bridge.ReactApplicationContext;
@@ -17,13 +16,12 @@ import com.facebook.react.bridge.ReadableMap;
17
16
  import com.facebook.react.bridge.ReadableMapKeySetIterator;
18
17
  import com.facebook.react.bridge.WritableMap;
19
18
  import com.facebook.react.modules.core.DeviceEventManagerModule;
20
- import com.reactnativecompressor.Image.utils.ImageCompressorOptions;
21
19
  import com.reactnativecompressor.Utils.FileUplaoder.FileUploader;
22
20
  import com.reactnativecompressor.Video.AutoVideoCompression.AutoVideoCompression;
23
- import com.zolad.videoslimmer.VideoSlimmer;
24
21
 
25
22
  import java.util.UUID;
26
23
 
24
+ import static com.reactnativecompressor.Utils.Utils.compressVideo;
27
25
  import static com.reactnativecompressor.Utils.Utils.generateCacheFilePath;
28
26
 
29
27
  public class VideoCompressorHelper {
@@ -50,8 +48,8 @@ public class VideoCompressorHelper {
50
48
  };
51
49
 
52
50
  private static void sendEventString(ReactContext reactContext,
53
- String eventName,
54
- @Nullable String params) {
51
+ String eventName,
52
+ @Nullable String params) {
55
53
  reactContext
56
54
  .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
57
55
  .emit(eventName, params);
@@ -118,7 +116,7 @@ public class VideoCompressorHelper {
118
116
  case "maxSize":
119
117
  options.maxSize = (float) map.getDouble(key);
120
118
  break;
121
- case "uuid":
119
+ case "uuid":
122
120
  options.uuid = map.getString(key);
123
121
  break;
124
122
  case "minimumFileSizeForCompress":
@@ -166,44 +164,10 @@ public class VideoCompressorHelper {
166
164
  }
167
165
  }
168
166
  float videoBitRate = (options.bitrate>0)?options.bitrate: (float) (height * width * 1.5);
169
-
170
- VideoSlimmer.convertVideo(srcPath, destinationPath, width, height, (int) videoBitRate, new VideoSlimmer.ProgressListener() {
171
-
172
-
173
- @Override
174
- public void onStart() {
175
- //convert start
176
-
177
- }
178
-
179
- @Override
180
- public void onFinish(boolean result) {
181
- //convert finish,result(true is success,false is fail)
182
- promise.resolve("file:/"+destinationPath);
183
- }
184
-
185
-
186
- @Override
187
- public void onProgress(float percent) {
188
- int roundProgress=Math.round(percent);
189
- if(roundProgress%videoCompressionThreshold==0&&roundProgress>currentVideoCompression) {
190
- WritableMap params = Arguments.createMap();
191
- WritableMap data = Arguments.createMap();
192
- params.putString("uuid", options.uuid);
193
- data.putDouble("progress", percent / 100);
194
- params.putMap("data", data);
195
- sendEvent(reactContext, "videoCompressProgress", params);
196
- currentVideoCompression=roundProgress;
197
- }
198
- }
199
- });
200
-
167
+ compressVideo(srcPath, destinationPath, width, height, videoBitRate,options.uuid,promise,reactContext);
201
168
  } catch (Exception ex) {
202
169
  promise.reject(ex);
203
170
  }
204
- finally {
205
- currentVideoCompression=0;
206
- }
207
171
  }
208
172
 
209
173
 
@@ -212,4 +176,4 @@ public class VideoCompressorHelper {
212
176
  }
213
177
 
214
178
 
215
- }
179
+ }
@@ -1,12 +1,11 @@
1
1
  package com.reactnativecompressor.Video;
2
2
 
3
- import android.media.MediaMetadataRetriever;
4
3
  import android.net.Uri;
4
+ import android.util.Log;
5
5
 
6
6
  import androidx.annotation.NonNull;
7
7
  import androidx.annotation.Nullable;
8
8
 
9
- import com.facebook.react.bridge.Arguments;
10
9
  import com.facebook.react.bridge.Promise;
11
10
  import com.facebook.react.bridge.ReactApplicationContext;
12
11
  import com.facebook.react.bridge.ReactContext;
@@ -16,17 +15,18 @@ import com.facebook.react.bridge.ReadableMap;
16
15
  import com.facebook.react.bridge.WritableMap;
17
16
  import com.facebook.react.module.annotations.ReactModule;
18
17
  import com.facebook.react.modules.core.DeviceEventManagerModule;
19
- import com.reactnativecompressor.Image.utils.ImageCompressorOptions;
20
- import com.zolad.videoslimmer.VideoSlimmer;
18
+ import com.reactnativecompressor.Utils.RealPathUtil;
21
19
 
22
- import static com.reactnativecompressor.Utils.Utils.generateCacheFilePath;
20
+ import static com.reactnativecompressor.Utils.Utils.getRealPath;
23
21
  import static com.reactnativecompressor.Video.VideoCompressorHelper.video_activateBackgroundTask_helper;
24
22
  import static com.reactnativecompressor.Video.VideoCompressorHelper.video_deactivateBackgroundTask_helper;
25
23
  import static com.reactnativecompressor.Video.VideoCompressorHelper.video_upload_helper;
24
+ import static com.reactnativecompressor.Utils.Utils.cancelCompressionHelper;
26
25
 
27
26
  @ReactModule(name = VideoModule.NAME)
28
- public class VideoModule extends ReactContextBaseJavaModule {
27
+ public class VideoModule extends ReactContextBaseJavaModule {
29
28
  public static final String NAME = "VideoCompressor";
29
+ private static final String TAG = "react-native-compessor";
30
30
  private final ReactApplicationContext reactContext;
31
31
  public VideoModule(ReactApplicationContext reactContext) {
32
32
  super(reactContext);
@@ -53,20 +53,28 @@ public class VideoModule extends ReactContextBaseJavaModule {
53
53
  String fileUrl,
54
54
  ReadableMap optionMap,
55
55
  Promise promise) {
56
- final VideoCompressorHelper options = VideoCompressorHelper.fromMap(optionMap);
56
+ final VideoCompressorHelper options = VideoCompressorHelper.fromMap(optionMap);
57
+ fileUrl=getRealPath(fileUrl,reactContext);
57
58
 
58
- if(options.compressionMethod==VideoCompressorHelper.CompressionMethod.auto)
59
- {
60
- VideoCompressorHelper.VideoCompressAuto(fileUrl,options,promise,reactContext);
61
- }
62
- else
63
- {
64
- VideoCompressorHelper.VideoCompressManual(fileUrl,options,promise,reactContext);
65
- }
59
+ if(options.compressionMethod==VideoCompressorHelper.CompressionMethod.auto)
60
+ {
61
+ VideoCompressorHelper.VideoCompressAuto(fileUrl,options,promise,reactContext);
62
+ }
63
+ else
64
+ {
65
+ VideoCompressorHelper.VideoCompressManual(fileUrl,options,promise,reactContext);
66
+ }
66
67
 
67
68
 
68
69
  }
69
70
 
71
+ @ReactMethod
72
+ public void cancelCompression(
73
+ String uuid) {
74
+ cancelCompressionHelper(uuid);
75
+ Log.d("cancelCompression", uuid);
76
+ }
77
+
70
78
  @ReactMethod
71
79
  public void upload(
72
80
  String fileUrl,
package/ios/.DS_Store CHANGED
Binary file
@@ -3,4 +3,4 @@
3
3
  //
4
4
  #import <React/RCTBridgeModule.h>
5
5
  #import <React/RCTEventEmitter.h>
6
-
6
+ #import "ImageCompressor.h"
package/ios/Compressor.m CHANGED
@@ -9,6 +9,30 @@
9
9
  #define AlAsset_Library_Scheme @"assets-library"
10
10
  @implementation Compressor
11
11
  AVAssetWriter *assetWriter=nil;
12
+ static NSArray *metadatas;
13
+
14
+ - (NSArray *)metadatas
15
+ {
16
+ if (!metadatas) {
17
+ metadatas = @[
18
+ @"albumName",
19
+ @"artist",
20
+ @"comment",
21
+ @"copyrights",
22
+ @"creationDate",
23
+ @"date",
24
+ @"encodedby",
25
+ @"genre",
26
+ @"language",
27
+ @"location",
28
+ @"lastModifiedDate",
29
+ @"performer",
30
+ @"publisher",
31
+ @"title"
32
+ ];
33
+ }
34
+ return metadatas;
35
+ }
12
36
 
13
37
  RCT_EXPORT_MODULE()
14
38
 
@@ -20,17 +44,19 @@ RCT_EXPORT_METHOD(
20
44
  rejecter: (RCTPromiseRejectBlock) reject) {
21
45
  @try {
22
46
  ImageCompressorOptions *options = [ImageCompressorOptions fromDictionary:optionsDict];
47
+ [ImageCompressor getAbsoluteImagePath:imagePath completionHandler:^(NSString* absoluteImagePath){
48
+ if(options.autoCompress)
49
+ {
50
+ NSString *result = [ImageCompressor autoCompressHandler:absoluteImagePath options:options];
51
+ resolve(result);
52
+ }
53
+ else
54
+ {
55
+ NSString *result = [ImageCompressor manualCompressHandler:absoluteImagePath options:options];
56
+ resolve(result);
57
+ }
58
+ }];
23
59
 
24
- if(options.autoCompress)
25
- {
26
- NSString *result = [ImageCompressor autoCompressHandler:imagePath options:options];
27
- resolve(result);
28
- }
29
- else
30
- {
31
- NSString *result = [ImageCompressor manualCompressHandler:imagePath options:options];
32
- resolve(result);
33
- }
34
60
  }
35
61
  @catch (NSException *exception) {
36
62
  reject(exception.name, exception.reason, nil);
@@ -176,7 +202,7 @@ RCT_EXPORT_METHOD(
176
202
 
177
203
  //general
178
204
  RCT_EXPORT_METHOD(
179
- generateFile: (NSString*) extension
205
+ generateFilePath: (NSString*) extension
180
206
  resolver: (RCTPromiseResolveBlock) resolve
181
207
  rejecter: (RCTPromiseRejectBlock) reject) {
182
208
  @try {
@@ -188,6 +214,30 @@ RCT_EXPORT_METHOD(
188
214
  }
189
215
  }
190
216
 
217
+ RCT_EXPORT_METHOD(
218
+ getRealPath: (NSString*) path
219
+ type: (NSString*) type
220
+ resolver: (RCTPromiseResolveBlock) resolve
221
+ rejecter: (RCTPromiseRejectBlock) reject) {
222
+ @try {
223
+ if([type isEqualToString:@"video"])
224
+ {
225
+ [ImageCompressor getAbsoluteVideoPath:path completionHandler:^(NSString* absoluteImagePath){
226
+ resolve(absoluteImagePath);
227
+ }];
228
+ }
229
+ else
230
+ {
231
+ [ImageCompressor getAbsoluteImagePath:path completionHandler:^(NSString* absoluteImagePath){
232
+ resolve(absoluteImagePath);
233
+ }];
234
+ }
235
+ }
236
+ @catch (NSException *exception) {
237
+ reject(exception.name, exception.reason, nil);
238
+ }
239
+ }
240
+
191
241
  //general
192
242
  RCT_EXPORT_METHOD(
193
243
  getFileSize: (NSString*) filePath
@@ -216,6 +266,63 @@ RCT_EXPORT_METHOD(
216
266
  }
217
267
  }
218
268
 
269
+
270
+ RCT_EXPORT_METHOD(
271
+ getVideoMetaData: (NSString*) filePath
272
+ resolver: (RCTPromiseResolveBlock) resolve
273
+ rejecter: (RCTPromiseRejectBlock) reject) {
274
+ @try {
275
+ [ImageCompressor getAbsoluteVideoPath:filePath completionHandler:^(NSString *absoluteImagePath) {
276
+ if([absoluteImagePath containsString:@"file://"])
277
+ {
278
+ absoluteImagePath=[absoluteImagePath stringByReplacingOccurrencesOfString:@"file://"
279
+ withString:@""];
280
+ }
281
+ NSFileManager *fileManager = [NSFileManager defaultManager];
282
+
283
+ BOOL isDir;
284
+ if (![fileManager fileExistsAtPath:absoluteImagePath isDirectory:&isDir] || isDir){
285
+ NSError *err = [NSError errorWithDomain:@"file not found" code:-15 userInfo:nil];
286
+ reject([NSString stringWithFormat: @"%lu", (long)err.code], err.localizedDescription, err);
287
+ return;
288
+ }
289
+ NSDictionary *attrs = [fileManager attributesOfItemAtPath: absoluteImagePath error: NULL];
290
+ UInt32 fileSize = [attrs fileSize];
291
+ NSString *fileSizeString = [@(fileSize) stringValue];
292
+
293
+ NSMutableDictionary *result = [NSMutableDictionary new];
294
+ NSDictionary *assetOptions = @{AVURLAssetPreferPreciseDurationAndTimingKey: @YES};
295
+ AVURLAsset *asset = [AVURLAsset URLAssetWithURL:[NSURL fileURLWithPath:absoluteImagePath] options:assetOptions];\
296
+ AVAssetTrack *avAsset = [[asset tracksWithMediaType:AVMediaTypeVideo] objectAtIndex:0];
297
+ CGSize size = [avAsset naturalSize];
298
+ NSString *extension = [[absoluteImagePath lastPathComponent] pathExtension];
299
+ CMTime time = [asset duration];
300
+ int seconds = ceil(time.value/time.timescale);
301
+ [result setObject:[NSString stringWithFormat: @"%.2f", size.width] forKey:@"width"];
302
+ [result setObject:[NSString stringWithFormat: @"%.2f", size.height] forKey:@"height"];
303
+ [result setObject:extension forKey:@"extension"];
304
+ [result setObject:fileSizeString forKey:@"size"];
305
+ [result setObject:[@(seconds) stringValue] forKey:@"duration"];
306
+ NSArray *keys = [NSArray arrayWithObjects:@"commonMetadata", nil];
307
+ [asset loadValuesAsynchronouslyForKeys:keys completionHandler:^{
308
+ // string keys
309
+ for (NSString *key in [self metadatas]) {
310
+ NSArray *items = [AVMetadataItem metadataItemsFromArray:asset.commonMetadata
311
+ withKey:key
312
+ keySpace:AVMetadataKeySpaceCommon];
313
+ for (AVMetadataItem *item in items) {
314
+ [result setObject:item.value forKey:key];
315
+ }
316
+ }
317
+ resolve(result);
318
+ }];
319
+ }];
320
+ }
321
+ @catch (NSException *exception) {
322
+ reject(exception.name, exception.reason, nil);
323
+ }
324
+ }
325
+
219
326
  @end
220
327
 
221
328
 
@@ -239,5 +346,6 @@ RCT_EXTERN_METHOD(deactivateBackgroundTask: (NSDictionary *)options
239
346
  withResolver:(RCTPromiseResolveBlock)resolve
240
347
  withRejecter:(RCTPromiseRejectBlock)reject)
241
348
 
242
- @end
349
+ RCT_EXTERN_METHOD(cancelCompression:(NSString *)uuid)
243
350
 
351
+ @end
@@ -12,4 +12,6 @@
12
12
  +(NSString *)autoCompressHandler:(NSString *)imagePath options:(ImageCompressorOptions*)options;
13
13
  + (NSString *)manualCompress:(UIImage *)image output:(enum OutputType)output quality:(float)quality outputExtension:(NSString*)outputExtension isBase64:(Boolean)isBase64;
14
14
  + (UIImage *)scaleAndRotateImage:(UIImage *)image;
15
+ + (void)getAbsoluteImagePath:(NSString *)imagePath completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler;
16
+ +(void)getAbsoluteVideoPath:(NSString *)videoPath completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler;
15
17
  @end
@@ -1,7 +1,12 @@
1
1
  #import <Accelerate/Accelerate.h>
2
2
  #import <CoreGraphics/CoreGraphics.h>
3
-
3
+ #import <Photos/Photos.h>
4
+ #import <React/RCTUtils.h>
5
+ #import <React/RCTImageLoader.h>
4
6
  #import "ImageCompressor.h"
7
+ #import <React/RCTConvert.h>
8
+ #import <Foundation/Foundation.h>
9
+ #import <MobileCoreServices/MobileCoreServices.h>
5
10
 
6
11
  @implementation ImageCompressor
7
12
  + (CGSize) findTargetSize: (UIImage *) image maxWidth: (int) maxWidth maxHeight: (int) maxHeight {
@@ -288,4 +293,151 @@
288
293
  return returnablePath;
289
294
  }
290
295
 
296
+ +(void)getAbsoluteImagePath:(NSString *)imagePath completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler
297
+ {
298
+ if (![imagePath containsString:@"ph://"]) {
299
+ completionHandler(imagePath);
300
+ return;
301
+ }
302
+ NSURL *imageURL = [NSURL URLWithString:[imagePath stringByReplacingOccurrencesOfString:@" " withString:@"%20"]];
303
+ CGSize size = CGSizeZero;
304
+ CGFloat scale = 1;
305
+ RCTResizeMode resizeMode = RCTResizeModeContain;
306
+ NSString *assetID = @"";
307
+ PHFetchResult *results;
308
+ if (!imageURL) {
309
+ NSString *errorText = @"Cannot load a photo library asset with no URL";
310
+ @throw([NSException exceptionWithName:errorText reason:errorText userInfo:nil]);
311
+ } else if ([imageURL.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame) {
312
+ assetID = [imageURL absoluteString];
313
+ results = [PHAsset fetchAssetsWithALAssetURLs:@[imageURL] options:nil];
314
+ } else {
315
+ assetID = [imageURL.absoluteString substringFromIndex:@"ph://".length];
316
+ results = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetID] options:nil];
317
+ }
318
+ if (results.count == 0) {
319
+ NSString *errorText = [NSString stringWithFormat:@"Failed to fetch PHAsset with local identifier %@ with no error message.", assetID];
320
+ @throw([NSException exceptionWithName:errorText reason:errorText userInfo:nil]);
321
+ }
322
+ PHAsset *asset = [results firstObject]; // <-- WE GOT THE ASSET
323
+ PHImageRequestOptions *imageOptions = [PHImageRequestOptions new];
324
+ imageOptions.networkAccessAllowed = YES;
325
+ imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
326
+
327
+ BOOL useMaximumSize = CGSizeEqualToSize(size, CGSizeZero);
328
+ CGSize targetSize;
329
+ if (useMaximumSize) {
330
+ targetSize = PHImageManagerMaximumSize;
331
+ imageOptions.resizeMode = PHImageRequestOptionsResizeModeNone;
332
+ } else {
333
+ targetSize = CGSizeApplyAffineTransform(size, CGAffineTransformMakeScale(scale, scale));
334
+ imageOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
335
+ }
336
+
337
+ PHImageContentMode contentMode = PHImageContentModeAspectFill;
338
+ if (resizeMode == RCTResizeModeContain) {
339
+ contentMode = PHImageContentModeAspectFit;
340
+ }
341
+ [[PHImageManager defaultManager] requestImageForAsset:asset
342
+ targetSize:targetSize
343
+ contentMode:contentMode
344
+ options:imageOptions
345
+ resultHandler:^(UIImage *result, NSDictionary<NSString *, id> *info) {
346
+ // WE GOT THE IMAGE
347
+ if (result) {
348
+ UIImage *image = result;
349
+ NSString *imageName = [assetID stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
350
+ NSString *imagePath = [self saveImageIntoCache:image withName:imageName];
351
+ completionHandler(imagePath);
352
+ } else {
353
+ @throw([NSException exceptionWithName:@"image not found" reason:@"image not found" userInfo:nil]);
354
+ }
355
+ }];
356
+ }
357
+
358
+ +(NSString*) saveImageIntoCache:(UIImage *)image withName:(NSString *)name {
359
+ NSData *imageData = UIImageJPEGRepresentation(image, 1);
360
+ NSString *path =[self generateCacheFilePath:@"jpg"];
361
+ [[NSFileManager defaultManager] createFileAtPath:path contents:imageData attributes:NULL];
362
+ return path;
363
+ }
364
+
365
+ /// for video
366
+
367
+ +(void)getAbsoluteVideoPath:(NSString *)videoPath completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler
368
+ {
369
+
370
+ if (![videoPath containsString:@"ph://"]) {
371
+ completionHandler(videoPath);
372
+ return;
373
+ }
374
+ NSString *assetId =[videoPath stringByReplacingOccurrencesOfString:@"ph://"
375
+ withString:@""];
376
+ AVFileType outputFileType = AVFileTypeMPEG4;
377
+ NSString *pressetType = AVAssetExportPresetPassthrough;
378
+
379
+ // Throwing some errors to the user if he is not careful enough
380
+ if ([assetId isEqualToString:@""]) {
381
+ NSError *error = [NSError errorWithDomain:@"RNGalleryManager" code: -91 userInfo:nil];
382
+ @throw([NSException exceptionWithName:error reason:error userInfo:nil]);
383
+ return;
384
+ }
385
+
386
+ // Getting Video Asset
387
+ NSArray* localIds = [NSArray arrayWithObjects: assetId, nil];
388
+ PHAsset * _Nullable videoAsset = [PHAsset fetchAssetsWithLocalIdentifiers:localIds options:nil].firstObject;
389
+
390
+ // Getting information from the asset
391
+ NSString *mimeType = (NSString *)CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(outputFileType), kUTTagClassMIMEType));
392
+ CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef _Nonnull)(mimeType), NULL);
393
+ NSString *extension = (NSString *)CFBridgingRelease(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension));
394
+
395
+ // Creating output url and temp file name
396
+ NSString *path =[self generateCacheFilePath:extension];
397
+ NSURL *outputUrl = [NSURL URLWithString:[@"file://" stringByAppendingString:path]];
398
+
399
+ // Setting video export session options
400
+ PHVideoRequestOptions *videoRequestOptions = [[PHVideoRequestOptions alloc] init];
401
+ videoRequestOptions.networkAccessAllowed = YES;
402
+ videoRequestOptions.deliveryMode = PHVideoRequestOptionsDeliveryModeHighQualityFormat;
403
+
404
+ // Creating new export session
405
+ [[PHImageManager defaultManager] requestExportSessionForVideo:videoAsset options:videoRequestOptions exportPreset:pressetType resultHandler:^(AVAssetExportSession * _Nullable exportSession, NSDictionary * _Nullable info) {
406
+
407
+ exportSession.shouldOptimizeForNetworkUse = YES;
408
+ exportSession.outputFileType = outputFileType;
409
+ exportSession.outputURL = outputUrl;
410
+ // Converting the video and waiting to see whats going to happen
411
+ [exportSession exportAsynchronouslyWithCompletionHandler:^{
412
+ switch ([exportSession status])
413
+ {
414
+ case AVAssetExportSessionStatusFailed:
415
+ {
416
+ NSError* error = exportSession.error;
417
+ NSString *codeWithDomain = [NSString stringWithFormat:@"E%@%zd", error.domain.uppercaseString, error.code];
418
+ @throw([NSException exceptionWithName:error reason:error userInfo:nil]);
419
+ break;
420
+ }
421
+ case AVAssetExportSessionStatusCancelled:
422
+ {
423
+ NSError *error = [NSError errorWithDomain:@"RNGalleryManager" code: -91 userInfo:nil];
424
+ @throw([NSException exceptionWithName:error reason:error userInfo:nil]);
425
+ break;
426
+ }
427
+ case AVAssetExportSessionStatusCompleted:
428
+ {
429
+ completionHandler(outputUrl.absoluteString);
430
+ break;
431
+ }
432
+ default:
433
+ {
434
+ NSError *error = [NSError errorWithDomain:@"RNGalleryManager" code: -91 userInfo:nil];
435
+ @throw([NSException exceptionWithName:@"Unknown status" reason:@"Unknown status" userInfo:nil]);
436
+ break;
437
+ }
438
+ }
439
+ }];
440
+ }];
441
+ }
442
+
291
443
  @end