react-native-compressor 1.7.0 → 1.7.1
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.
- package/README.md +36 -16
- package/android/src/main/java/com/reactnativecompressor/CompressorModule.java +31 -22
- package/android/src/main/java/com/reactnativecompressor/Image/ImageCompressor.java +28 -16
- package/android/src/main/java/com/reactnativecompressor/Image/utils/ImageCompressorOptions.java +4 -0
- package/android/src/main/java/com/reactnativecompressor/Utils/MediaCache.java +65 -0
- package/android/src/main/java/com/reactnativecompressor/Utils/Utils.java +161 -2
- package/android/src/main/java/com/reactnativecompressor/Video/VideoModule.java +3 -16
- package/android/src/oldarch/CompressorSpec.java +13 -7
- package/ios/Compressor-Bridging-Header.h +1 -0
- package/ios/Compressor.h +3 -2
- package/ios/Compressor.mm +56 -24
- package/ios/Image/ImageCompressor.h +12 -7
- package/ios/Image/ImageCompressor.m +164 -67
- package/ios/Image/ImageCompressorOptions.h +1 -0
- package/ios/Image/ImageCompressorOptions.m +5 -1
- package/ios/Utils/Downloader.h +16 -0
- package/ios/Utils/Downloader.m +150 -0
- package/ios/Utils/MediaCache.h +11 -0
- package/ios/Utils/MediaCache.m +51 -0
- package/ios/Video/VideoCompressor.swift +12 -3
- package/lib/commonjs/Image/index.js +25 -3
- package/lib/commonjs/Image/index.js.map +1 -1
- package/lib/commonjs/Spec/NativeCompressor.js.map +1 -1
- package/lib/commonjs/Video/index.js +14 -1
- package/lib/commonjs/Video/index.js.map +1 -1
- package/lib/module/Image/index.js +25 -3
- package/lib/module/Image/index.js.map +1 -1
- package/lib/module/Spec/NativeCompressor.js.map +1 -1
- package/lib/module/Video/index.js +14 -1
- package/lib/module/Video/index.js.map +1 -1
- package/lib/typescript/Image/index.d.ts +4 -0
- package/lib/typescript/Image/index.d.ts.map +1 -1
- package/lib/typescript/Spec/NativeCompressor.d.ts +2 -0
- package/lib/typescript/Spec/NativeCompressor.d.ts.map +1 -1
- package/lib/typescript/Video/index.d.ts +1 -0
- package/lib/typescript/Video/index.d.ts.map +1 -1
- package/package.json +4 -2
- package/src/Image/index.tsx +36 -3
- package/src/Spec/NativeCompressor.ts +2 -0
- package/src/Video/index.tsx +23 -1
package/ios/Compressor.mm
CHANGED
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
#import "Image/ImageCompressorOptions.h"
|
|
6
6
|
#import <React/RCTEventEmitter.h>
|
|
7
7
|
#import <AVFoundation/AVFoundation.h>
|
|
8
|
+
#import "MediaCache.h"
|
|
8
9
|
|
|
9
10
|
#define AlAsset_Library_Scheme @"assets-library"
|
|
10
11
|
@implementation Compressor
|
|
@@ -35,8 +36,18 @@ static NSArray *metadatas;
|
|
|
35
36
|
return metadatas;
|
|
36
37
|
}
|
|
37
38
|
|
|
39
|
+
- (instancetype)init {
|
|
40
|
+
self = [super init];
|
|
41
|
+
[ImageCompressor initCompressorInstance:self];
|
|
42
|
+
return self;
|
|
43
|
+
}
|
|
44
|
+
|
|
38
45
|
RCT_EXPORT_MODULE()
|
|
39
46
|
|
|
47
|
+
+ (BOOL)requiresMainQueueSetup {
|
|
48
|
+
return NO;
|
|
49
|
+
}
|
|
50
|
+
|
|
40
51
|
|
|
41
52
|
//Image
|
|
42
53
|
RCT_EXPORT_METHOD(
|
|
@@ -88,6 +99,10 @@ RCT_EXPORT_METHOD(
|
|
|
88
99
|
[self getVideoMetaData:filePath resolve:resolve reject:reject];
|
|
89
100
|
}
|
|
90
101
|
|
|
102
|
+
- (NSArray<NSString *>*)supportedEvents {
|
|
103
|
+
return @[@"downloadProgress"];
|
|
104
|
+
}
|
|
105
|
+
|
|
91
106
|
- (NSString *)getAudioQualityConstant:(NSString *)quality
|
|
92
107
|
{
|
|
93
108
|
NSMutableArray *audioQualityArray = [[NSMutableArray alloc]initWithObjects:@"low", @"medium", @"high", nil];
|
|
@@ -233,13 +248,13 @@ RCT_EXPORT_METHOD(
|
|
|
233
248
|
@try {
|
|
234
249
|
if([type isEqualToString:@"video"])
|
|
235
250
|
{
|
|
236
|
-
[ImageCompressor getAbsoluteVideoPath:path completionHandler:^(NSString* absoluteImagePath){
|
|
251
|
+
[ImageCompressor getAbsoluteVideoPath:path uuid:@"" completionHandler:^(NSString* absoluteImagePath){
|
|
237
252
|
resolve(absoluteImagePath);
|
|
238
253
|
}];
|
|
239
254
|
}
|
|
240
255
|
else
|
|
241
256
|
{
|
|
242
|
-
[ImageCompressor getAbsoluteImagePath:path completionHandler:^(NSString* absoluteImagePath){
|
|
257
|
+
[ImageCompressor getAbsoluteImagePath:path uuid:@"test" completionHandler:^(NSString* absoluteImagePath){
|
|
243
258
|
resolve(absoluteImagePath);
|
|
244
259
|
}];
|
|
245
260
|
}
|
|
@@ -251,7 +266,7 @@ RCT_EXPORT_METHOD(
|
|
|
251
266
|
|
|
252
267
|
- (void)getVideoMetaData:(NSString *)filePath resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
253
268
|
@try {
|
|
254
|
-
|
|
269
|
+
[ImageCompressor getAbsoluteVideoPath:filePath uuid:@"" completionHandler:^(NSString *absoluteImagePath) {
|
|
255
270
|
if([absoluteImagePath containsString:@"file://"])
|
|
256
271
|
{
|
|
257
272
|
absoluteImagePath=[absoluteImagePath stringByReplacingOccurrencesOfString:@"file://"
|
|
@@ -305,7 +320,7 @@ RCT_EXPORT_METHOD(
|
|
|
305
320
|
- (void)image_compress:(NSString *)imagePath optionMap:(NSDictionary *)optionMap resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
306
321
|
@try {
|
|
307
322
|
ImageCompressorOptions *options = [ImageCompressorOptions fromDictionary:optionMap];
|
|
308
|
-
[ImageCompressor getAbsoluteImagePath:imagePath completionHandler:^(NSString* absoluteImagePath){
|
|
323
|
+
[ImageCompressor getAbsoluteImagePath:imagePath uuid:options.uuid completionHandler:^(NSString* absoluteImagePath){
|
|
309
324
|
if(options.autoCompress)
|
|
310
325
|
{
|
|
311
326
|
NSString *result = [ImageCompressor autoCompressHandler:absoluteImagePath options:options];
|
|
@@ -316,6 +331,7 @@ RCT_EXPORT_METHOD(
|
|
|
316
331
|
NSString *result = [ImageCompressor manualCompressHandler:absoluteImagePath options:options];
|
|
317
332
|
resolve(result);
|
|
318
333
|
}
|
|
334
|
+
[MediaCache removeCompletedImagePath:absoluteImagePath];
|
|
319
335
|
}];
|
|
320
336
|
|
|
321
337
|
}
|
|
@@ -326,26 +342,42 @@ RCT_EXPORT_METHOD(
|
|
|
326
342
|
|
|
327
343
|
- (void)getFileSize:(NSString *)filePath resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject {
|
|
328
344
|
@try {
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
345
|
+
if([filePath hasPrefix:@"http://"]||[filePath hasPrefix:@"https://"])
|
|
346
|
+
{
|
|
347
|
+
[ImageCompressor getFileSizeFromURL:filePath completion:^(NSNumber *fileSize, NSError *error) {
|
|
348
|
+
if (error) {
|
|
349
|
+
NSLog(@"Error: %@", error.localizedDescription);
|
|
350
|
+
} else {
|
|
351
|
+
NSLog(@"File size: %@", fileSize);
|
|
352
|
+
resolve(fileSize);
|
|
353
|
+
}
|
|
354
|
+
}];
|
|
355
|
+
|
|
356
|
+
}
|
|
357
|
+
else
|
|
358
|
+
{
|
|
359
|
+
if([filePath containsString:@"file://"])
|
|
360
|
+
{
|
|
361
|
+
filePath=[filePath stringByReplacingOccurrencesOfString:@"file://"
|
|
362
|
+
withString:@""];
|
|
363
|
+
}
|
|
364
|
+
NSFileManager *fileManager = [NSFileManager defaultManager];
|
|
365
|
+
BOOL isDir;
|
|
366
|
+
if (![fileManager fileExistsAtPath:filePath isDirectory:&isDir] || isDir){
|
|
367
|
+
NSError *err = [NSError errorWithDomain:@"file not found" code:-15 userInfo:nil];
|
|
368
|
+
reject([NSString stringWithFormat: @"%lu", (long)err.code], err.localizedDescription, err);
|
|
369
|
+
return;
|
|
370
|
+
}
|
|
371
|
+
NSDictionary *attrs = [fileManager attributesOfItemAtPath: filePath error: NULL];
|
|
372
|
+
UInt32 fileSize = [attrs fileSize];
|
|
373
|
+
NSString *fileSizeString = [@(fileSize) stringValue];
|
|
374
|
+
resolve(fileSizeString);
|
|
375
|
+
}
|
|
376
|
+
|
|
377
|
+
}
|
|
378
|
+
@catch (NSException *exception) {
|
|
379
|
+
reject(exception.name, exception.reason, nil);
|
|
380
|
+
}
|
|
349
381
|
}
|
|
350
382
|
|
|
351
383
|
// Don't compile this code when we build for the old architecture.
|
|
@@ -1,17 +1,22 @@
|
|
|
1
1
|
#import <UIKit/UIKit.h>
|
|
2
|
-
|
|
2
|
+
#import <React/RCTEventEmitter.h>
|
|
3
|
+
#import "Compressor.h"
|
|
3
4
|
#import "ImageCompressorOptions.h"
|
|
4
5
|
|
|
5
|
-
@interface ImageCompressor : NSObject
|
|
6
|
+
@interface ImageCompressor : RCTEventEmitter<NSObject>
|
|
6
7
|
+ (UIImage *)decodeImage:(NSString *)base64;
|
|
7
8
|
+ (UIImage *)loadImage:(NSString *)path;
|
|
8
9
|
+ (NSString *)generateCacheFilePath:(NSString *)extension;
|
|
9
10
|
|
|
10
11
|
+ (UIImage *)manualResize:(UIImage *)image maxWidth:(int)maxWidth maxHeight:(int)maxHeight;
|
|
11
|
-
+(NSString *)manualCompressHandler:(NSString *)imagePath options:(ImageCompressorOptions*)options;
|
|
12
|
-
+(NSString *)autoCompressHandler:(NSString *)imagePath options:(ImageCompressorOptions*)options;
|
|
13
|
-
+ (NSString *)manualCompress:(UIImage *)image output:(enum OutputType)output quality:(float)quality outputExtension:(NSString*)outputExtension isBase64:(Boolean)isBase64;
|
|
12
|
+
+ (NSString *)manualCompressHandler:(NSString *)imagePath options:(ImageCompressorOptions *)options;
|
|
13
|
+
+ (NSString *)autoCompressHandler:(NSString *)imagePath options:(ImageCompressorOptions *)options;
|
|
14
|
+
+ (NSString *)manualCompress:(UIImage *)image output:(enum OutputType)output quality:(float)quality outputExtension:(NSString *)outputExtension isBase64:(Boolean)isBase64;
|
|
14
15
|
+ (UIImage *)scaleAndRotateImage:(UIImage *)image;
|
|
15
|
-
+ (void)getAbsoluteImagePath:(NSString *)imagePath completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler;
|
|
16
|
-
+(void)getAbsoluteVideoPath:(NSString *)videoPath completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler;
|
|
16
|
+
+ (void)getAbsoluteImagePath:(NSString *)imagePath uuid:(NSString *)uuid completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler;
|
|
17
|
+
+ (void)getAbsoluteVideoPath:(NSString *)videoPath uuid:(NSString *)uuid completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler;
|
|
18
|
+
+ (void)downloadFileAndSaveToCache:(NSString *)fileUrl;
|
|
19
|
+
+ (void)getFileSizeFromURL:(NSString *)urlString completion:(void (^)(NSNumber *fileSize, NSError *error))completion;
|
|
20
|
+
+ (void)initCompressorInstance:(Compressor*)instance;
|
|
21
|
+
+ (void)initVideoCompressorInstance:(id)object;
|
|
17
22
|
@end
|
|
@@ -7,8 +7,24 @@
|
|
|
7
7
|
#import <React/RCTConvert.h>
|
|
8
8
|
#import <Foundation/Foundation.h>
|
|
9
9
|
#import <MobileCoreServices/MobileCoreServices.h>
|
|
10
|
+
#import <React/RCTEventEmitter.h>
|
|
11
|
+
#import "../Utils/Downloader.h"
|
|
12
|
+
#import "react_native_compressor-Swift.h"
|
|
13
|
+
#import "VideoCompressor.h"
|
|
14
|
+
#import "MediaCache.h"
|
|
10
15
|
|
|
11
16
|
@implementation ImageCompressor
|
|
17
|
+
Compressor *sharedCompressorObject;
|
|
18
|
+
id sharedVideoCompressorObject;
|
|
19
|
+
|
|
20
|
+
+ (void)initCompressorInstance:(Compressor*)instance {
|
|
21
|
+
sharedCompressorObject=instance;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
+ (void)initVideoCompressorInstance:(id)object {
|
|
25
|
+
sharedVideoCompressorObject=object;
|
|
26
|
+
}
|
|
27
|
+
|
|
12
28
|
+ (CGSize) findTargetSize: (UIImage *) image maxWidth: (int) maxWidth maxHeight: (int) maxHeight {
|
|
13
29
|
CGFloat width = image.size.width;
|
|
14
30
|
CGFloat height = image.size.height;
|
|
@@ -293,86 +309,167 @@
|
|
|
293
309
|
return returnablePath;
|
|
294
310
|
}
|
|
295
311
|
|
|
296
|
-
|
|
312
|
+
|
|
313
|
+
+ (void)getFileSizeFromURL:(NSString *)urlString completion:(void (^)(NSNumber *fileSize, NSError *error))completion {
|
|
314
|
+
NSURL *url = [NSURL URLWithString:urlString];
|
|
315
|
+
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
|
|
316
|
+
[request setHTTPMethod:@"HEAD"];
|
|
317
|
+
|
|
318
|
+
NSURLSession *session = [NSURLSession sharedSession];
|
|
319
|
+
NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
|
|
320
|
+
if (error) {
|
|
321
|
+
if (completion) {
|
|
322
|
+
completion(nil, error);
|
|
323
|
+
}
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
if ([response isKindOfClass:[NSHTTPURLResponse class]]) {
|
|
328
|
+
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
|
329
|
+
long long contentLength = [httpResponse expectedContentLength];
|
|
330
|
+
if (completion) {
|
|
331
|
+
completion([NSNumber numberWithLongLong:contentLength], nil);
|
|
332
|
+
}
|
|
333
|
+
} else {
|
|
334
|
+
if (completion) {
|
|
335
|
+
completion(nil, [NSError errorWithDomain:@"FileDownloadError" code:-1 userInfo:@{NSLocalizedDescriptionKey: @"Invalid response."}]);
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}];
|
|
339
|
+
|
|
340
|
+
[task resume];
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
|
|
344
|
+
+ (void)sendProgressUpdate:(NSNumber*)progress uuid:(NSString *)uuid type:(NSString *)type {
|
|
345
|
+
NSMutableDictionary *params = [[NSMutableDictionary alloc] init];
|
|
346
|
+
NSMutableDictionary *data = [[NSMutableDictionary alloc] init];
|
|
347
|
+
params[@"uuid"] = uuid;
|
|
348
|
+
data[@"progress"] = progress;
|
|
349
|
+
params[@"data"] = data;
|
|
350
|
+
|
|
351
|
+
if(type==@"image")
|
|
352
|
+
{
|
|
353
|
+
[sharedCompressorObject sendEventWithName:@"downloadProgress" body:params];
|
|
354
|
+
}
|
|
355
|
+
else
|
|
356
|
+
{
|
|
357
|
+
[sharedVideoCompressorObject sendEventWithName:@"downloadProgress" body:params];
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
+ (void)downloadFileAndSaveToCache:(NSString *)fileUrl uuid:(NSString *)uuid type:(NSString *)type completion:(void (^)(NSString *downloadedPath))completion {
|
|
364
|
+
|
|
365
|
+
Downloader *downloader = [[Downloader alloc] init];
|
|
366
|
+
[downloader downloadFile:fileUrl downloadCompleteCallback:^(NSString *filePath) {
|
|
367
|
+
[MediaCache addCompletedImagePath:filePath];
|
|
368
|
+
NSLog(@"download completed file path: %@",filePath);
|
|
369
|
+
completion(filePath);
|
|
370
|
+
} progressCallback:^(NSNumber * progress) {
|
|
371
|
+
[self sendProgressUpdate:progress uuid:uuid type:type];
|
|
372
|
+
|
|
373
|
+
} errorCallback:^(NSError * error) {
|
|
374
|
+
NSLog(@"error downloadFile",error);
|
|
375
|
+
}];
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
+(void)getAbsoluteImagePath:(NSString *)imagePath uuid:(NSString *)uuid completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler
|
|
297
379
|
{
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
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);
|
|
380
|
+
if([imagePath hasPrefix:@"http://"]||[imagePath hasPrefix:@"https://"])
|
|
381
|
+
{
|
|
382
|
+
[ImageCompressor downloadFileAndSaveToCache:imagePath uuid:uuid type:@"image" completion:^(NSString *downloadedPath) {
|
|
383
|
+
completionHandler(downloadedPath); // Pass the downloaded path to the completionHandler
|
|
384
|
+
}];
|
|
385
|
+
return;
|
|
386
|
+
|
|
387
|
+
}
|
|
388
|
+
else if (![imagePath containsString:@"ph://"]) {
|
|
389
|
+
completionHandler(imagePath);
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
NSURL *imageURL = [NSURL URLWithString:[imagePath stringByReplacingOccurrencesOfString:@" " withString:@"%20"]];
|
|
393
|
+
CGSize size = CGSizeZero;
|
|
394
|
+
CGFloat scale = 1;
|
|
395
|
+
RCTResizeMode resizeMode = RCTResizeModeContain;
|
|
396
|
+
NSString *assetID = @"";
|
|
397
|
+
PHFetchResult *results;
|
|
398
|
+
if (!imageURL) {
|
|
399
|
+
NSString *errorText = @"Cannot load a photo library asset with no URL";
|
|
400
|
+
@throw([NSException exceptionWithName:errorText reason:errorText userInfo:nil]);
|
|
401
|
+
} else if ([imageURL.scheme caseInsensitiveCompare:@"assets-library"] == NSOrderedSame) {
|
|
402
|
+
assetID = [imageURL absoluteString];
|
|
403
|
+
results = [PHAsset fetchAssetsWithALAssetURLs:@[imageURL] options:nil];
|
|
352
404
|
} else {
|
|
353
|
-
|
|
405
|
+
assetID = [imageURL.absoluteString substringFromIndex:@"ph://".length];
|
|
406
|
+
results = [PHAsset fetchAssetsWithLocalIdentifiers:@[assetID] options:nil];
|
|
407
|
+
}
|
|
408
|
+
if (results.count == 0) {
|
|
409
|
+
NSString *errorText = [NSString stringWithFormat:@"Failed to fetch PHAsset with local identifier %@ with no error message.", assetID];
|
|
410
|
+
@throw([NSException exceptionWithName:errorText reason:errorText userInfo:nil]);
|
|
354
411
|
}
|
|
355
|
-
|
|
412
|
+
PHAsset *asset = [results firstObject]; // <-- WE GOT THE ASSET
|
|
413
|
+
PHImageRequestOptions *imageOptions = [PHImageRequestOptions new];
|
|
414
|
+
imageOptions.networkAccessAllowed = YES;
|
|
415
|
+
imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
|
|
416
|
+
|
|
417
|
+
BOOL useMaximumSize = CGSizeEqualToSize(size, CGSizeZero);
|
|
418
|
+
CGSize targetSize;
|
|
419
|
+
if (useMaximumSize) {
|
|
420
|
+
targetSize = PHImageManagerMaximumSize;
|
|
421
|
+
imageOptions.resizeMode = PHImageRequestOptionsResizeModeNone;
|
|
422
|
+
} else {
|
|
423
|
+
targetSize = CGSizeApplyAffineTransform(size, CGAffineTransformMakeScale(scale, scale));
|
|
424
|
+
imageOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
PHImageContentMode contentMode = PHImageContentModeAspectFill;
|
|
428
|
+
if (resizeMode == RCTResizeModeContain) {
|
|
429
|
+
contentMode = PHImageContentModeAspectFit;
|
|
430
|
+
}
|
|
431
|
+
[[PHImageManager defaultManager] requestImageForAsset:asset
|
|
432
|
+
targetSize:targetSize
|
|
433
|
+
contentMode:contentMode
|
|
434
|
+
options:imageOptions
|
|
435
|
+
resultHandler:^(UIImage *result, NSDictionary<NSString *, id> *info) {
|
|
436
|
+
// WE GOT THE IMAGE
|
|
437
|
+
if (result) {
|
|
438
|
+
UIImage *image = result;
|
|
439
|
+
NSString *imageName = [assetID stringByReplacingOccurrencesOfString:@"/" withString:@"_"];
|
|
440
|
+
NSString *imagePath = [self saveImageIntoCache:image withName:imageName];
|
|
441
|
+
completionHandler(imagePath);
|
|
442
|
+
} else {
|
|
443
|
+
@throw([NSException exceptionWithName:@"image not found" reason:@"image not found" userInfo:nil]);
|
|
444
|
+
}
|
|
445
|
+
}];
|
|
356
446
|
}
|
|
357
447
|
|
|
358
448
|
+(NSString*) saveImageIntoCache:(UIImage *)image withName:(NSString *)name {
|
|
359
|
-
|
|
449
|
+
NSData *imageData = UIImageJPEGRepresentation(image, 1);
|
|
360
450
|
NSString *path =[self generateCacheFilePath:@"jpg"];
|
|
361
|
-
|
|
362
|
-
|
|
451
|
+
[[NSFileManager defaultManager] createFileAtPath:path contents:imageData attributes:NULL];
|
|
452
|
+
return path;
|
|
363
453
|
}
|
|
364
454
|
|
|
365
455
|
/// for video
|
|
366
|
-
|
|
367
|
-
+(void)getAbsoluteVideoPath:(NSString *)videoPath completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler
|
|
456
|
+
|
|
457
|
+
+(void)getAbsoluteVideoPath:(NSString *)videoPath uuid:(NSString *)uuid completionHandler:(void (^)(NSString *absoluteImagePath))completionHandler
|
|
368
458
|
{
|
|
459
|
+
if([videoPath hasPrefix:@"http://"]||[videoPath hasPrefix:@"https://"])
|
|
460
|
+
{
|
|
461
|
+
[ImageCompressor downloadFileAndSaveToCache:videoPath uuid:uuid type:@"video" completion:^(NSString *downloadedPath) {
|
|
462
|
+
completionHandler(downloadedPath); // Pass the downloaded path to the completionHandler
|
|
463
|
+
}];
|
|
464
|
+
return;
|
|
369
465
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
466
|
+
}
|
|
467
|
+
else if (![videoPath containsString:@"ph://"]) {
|
|
468
|
+
completionHandler(videoPath);
|
|
469
|
+
return;
|
|
373
470
|
}
|
|
374
471
|
NSString *assetId =[videoPath stringByReplacingOccurrencesOfString:@"ph://"
|
|
375
|
-
|
|
472
|
+
withString:@""];
|
|
376
473
|
AVFileType outputFileType = AVFileTypeMPEG4;
|
|
377
474
|
NSString *pressetType = AVAssetExportPresetPassthrough;
|
|
378
475
|
|
|
@@ -390,7 +487,7 @@
|
|
|
390
487
|
// Getting information from the asset
|
|
391
488
|
NSString *mimeType = (NSString *)CFBridgingRelease(UTTypeCopyPreferredTagWithClass((__bridge CFStringRef _Nonnull)(outputFileType), kUTTagClassMIMEType));
|
|
392
489
|
CFStringRef uti = UTTypeCreatePreferredIdentifierForTag(kUTTagClassMIMEType, (__bridge CFStringRef _Nonnull)(mimeType), NULL);
|
|
393
|
-
|
|
490
|
+
NSString *extension = (NSString *)CFBridgingRelease(UTTypeCopyPreferredTagWithClass(uti, kUTTagClassFilenameExtension));
|
|
394
491
|
|
|
395
492
|
// Creating output url and temp file name
|
|
396
493
|
NSString *path =[self generateCacheFilePath:extension];
|
|
@@ -23,5 +23,6 @@ typedef NS_ENUM(long, ReturnableOutputType) { rbase64,
|
|
|
23
23
|
@property(nonatomic, assign) enum OutputType output;
|
|
24
24
|
@property(nonatomic, assign) enum InputType input;
|
|
25
25
|
@property(nonatomic, assign) enum ReturnableOutputType returnableOutputType;
|
|
26
|
+
@property(nonatomic, assign) NSString* uuid;
|
|
26
27
|
|
|
27
28
|
@end
|
|
@@ -28,7 +28,9 @@
|
|
|
28
28
|
[options parseOutput: value];
|
|
29
29
|
} else if ([key isEqual:@"returnableOutputType"]) {
|
|
30
30
|
[options parseReturnableOutput: value];
|
|
31
|
-
}
|
|
31
|
+
}else if ([key isEqual:@"uuid"]) {
|
|
32
|
+
options.uuid=value;
|
|
33
|
+
}
|
|
32
34
|
}
|
|
33
35
|
|
|
34
36
|
return options;
|
|
@@ -56,6 +58,7 @@
|
|
|
56
58
|
self.input = uri;
|
|
57
59
|
self.output = jpg;
|
|
58
60
|
self.returnableOutputType = uri;
|
|
61
|
+
self.uuid = uuid;
|
|
59
62
|
}
|
|
60
63
|
|
|
61
64
|
return self;
|
|
@@ -68,6 +71,7 @@
|
|
|
68
71
|
@synthesize input;
|
|
69
72
|
@synthesize output;
|
|
70
73
|
@synthesize returnableOutputType;
|
|
74
|
+
@synthesize uuid;
|
|
71
75
|
|
|
72
76
|
- (void) parseInput:(NSString*)input {
|
|
73
77
|
NSDictionary *inputTranslations = @{ @"base64": @(base64), @"uri": @(uri) };
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
|
|
3
|
+
typedef void (^DownloadCompleteCallback)(NSString *filePath);
|
|
4
|
+
typedef void (^ErrorCallback)(NSError*);
|
|
5
|
+
typedef void (^ProgressCallback)(NSNumber*);
|
|
6
|
+
|
|
7
|
+
@interface Downloader : NSObject <NSURLSessionDelegate, NSURLSessionDownloadDelegate>
|
|
8
|
+
|
|
9
|
+
@property (nonatomic, copy) ProgressCallback globalProgressCallback;
|
|
10
|
+
@property (nonatomic, copy) DownloadCompleteCallback globalDownloadCompleteCallback;
|
|
11
|
+
@property (nonatomic, copy) ErrorCallback globalErrorCallback;
|
|
12
|
+
|
|
13
|
+
- (NSString *)downloadFile:(NSString *)fromUrl downloadCompleteCallback:(DownloadCompleteCallback)downloadCompleteCallback progressCallback:(ProgressCallback)progressCallback errorCallback:(ErrorCallback)errorCallback;
|
|
14
|
+
- (NSString *)generateCacheFilePath:(NSString *)extension;
|
|
15
|
+
|
|
16
|
+
@end
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
#import "Downloader.h"
|
|
2
|
+
|
|
3
|
+
@implementation Downloader
|
|
4
|
+
|
|
5
|
+
NSURLSession* _session;
|
|
6
|
+
NSURLSessionDownloadTask* _task;
|
|
7
|
+
NSNumber* _statusCode;
|
|
8
|
+
NSTimeInterval _lastProgressEmitTimestamp;
|
|
9
|
+
NSNumber* _lastProgressValue;
|
|
10
|
+
NSNumber* _contentLength;
|
|
11
|
+
NSNumber* _bytesWritten;
|
|
12
|
+
NSData* _resumeData;
|
|
13
|
+
NSString* _toFile;
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
ProgressCallback globalProgressCallback;
|
|
17
|
+
DownloadCompleteCallback globalDownloadCompleteCallback;
|
|
18
|
+
ErrorCallback globalErrorCallback;
|
|
19
|
+
|
|
20
|
+
NSFileHandle* _fileHandle;
|
|
21
|
+
|
|
22
|
+
- (NSString *)generateCacheFilePath:(NSString *)extension{
|
|
23
|
+
NSUUID *uuid = [NSUUID UUID];
|
|
24
|
+
NSString *imageNameWihtoutExtension = [uuid UUIDString];
|
|
25
|
+
NSString *imageName=[imageNameWihtoutExtension stringByAppendingPathExtension:extension];
|
|
26
|
+
NSString *filePath =
|
|
27
|
+
[NSTemporaryDirectory() stringByAppendingPathComponent:imageName];
|
|
28
|
+
return filePath;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
- (NSString *)downloadFile:(NSString *)fromUrl downloadCompleteCallback:(DownloadCompleteCallback)downloadCompleteCallback progressCallback:(ProgressCallback)progressCallback errorCallback:(ErrorCallback)errorCallback
|
|
32
|
+
{
|
|
33
|
+
NSString *uuid = nil;
|
|
34
|
+
|
|
35
|
+
Downloader *downloader = [[Downloader alloc] init];
|
|
36
|
+
globalProgressCallback = progressCallback;
|
|
37
|
+
globalDownloadCompleteCallback = downloadCompleteCallback;
|
|
38
|
+
globalErrorCallback = errorCallback;
|
|
39
|
+
|
|
40
|
+
_lastProgressEmitTimestamp = 0;
|
|
41
|
+
_bytesWritten = 0;
|
|
42
|
+
|
|
43
|
+
NSURL* url = [NSURL URLWithString:fromUrl];
|
|
44
|
+
NSString *fileExtension = [fromUrl pathExtension];
|
|
45
|
+
|
|
46
|
+
NSString *toFile =[self generateCacheFilePath:fileExtension];
|
|
47
|
+
_toFile=toFile;
|
|
48
|
+
|
|
49
|
+
if ([[NSFileManager defaultManager] fileExistsAtPath:toFile]) {
|
|
50
|
+
_fileHandle = [NSFileHandle fileHandleForWritingAtPath:toFile];
|
|
51
|
+
|
|
52
|
+
if (!_fileHandle) {
|
|
53
|
+
NSError* error = [NSError errorWithDomain:@"Downloader" code:NSURLErrorFileDoesNotExist
|
|
54
|
+
userInfo:@{NSLocalizedDescriptionKey: [NSString stringWithFormat: @"Failed to write target file at path: %@", toFile]}];
|
|
55
|
+
|
|
56
|
+
globalErrorCallback(error);
|
|
57
|
+
return nil;
|
|
58
|
+
} else {
|
|
59
|
+
[_fileHandle closeFile];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
NSURLSessionConfiguration *config;
|
|
64
|
+
|
|
65
|
+
config = [NSURLSessionConfiguration defaultSessionConfiguration];
|
|
66
|
+
|
|
67
|
+
_session = [NSURLSession sessionWithConfiguration:config delegate:downloader delegateQueue:nil];
|
|
68
|
+
_task = [_session downloadTaskWithURL:url];
|
|
69
|
+
[_task resume];
|
|
70
|
+
|
|
71
|
+
return uuid;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
|
|
75
|
+
{
|
|
76
|
+
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)downloadTask.response;
|
|
77
|
+
|
|
78
|
+
_statusCode = [NSNumber numberWithLong:httpResponse.statusCode];
|
|
79
|
+
_contentLength = [NSNumber numberWithLong:httpResponse.expectedContentLength];
|
|
80
|
+
|
|
81
|
+
if ([_statusCode isEqualToNumber:[NSNumber numberWithInt:200]]) {
|
|
82
|
+
|
|
83
|
+
_bytesWritten = @(totalBytesWritten);
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
double doubleBytesWritten = (double)[_bytesWritten longValue];
|
|
87
|
+
double doubleContentLength = (double)[_contentLength longValue];
|
|
88
|
+
double doublePercents = doubleBytesWritten / doubleContentLength * 100;
|
|
89
|
+
NSNumber* progress = [NSNumber numberWithUnsignedInt: floor(doublePercents)];
|
|
90
|
+
if ([progress unsignedIntValue] % 10 == 0) {
|
|
91
|
+
if (([progress unsignedIntValue] != [_lastProgressValue unsignedIntValue]) || ([_bytesWritten unsignedIntegerValue] == [_contentLength longValue])) {
|
|
92
|
+
_lastProgressValue = [NSNumber numberWithUnsignedInt:[progress unsignedIntValue]];
|
|
93
|
+
NSNumber *progressPercentage = @([_bytesWritten doubleValue] / [_contentLength doubleValue]);
|
|
94
|
+
return globalProgressCallback(progressPercentage);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
|
|
103
|
+
{
|
|
104
|
+
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)downloadTask.response;
|
|
105
|
+
if (!_statusCode) {
|
|
106
|
+
_statusCode = [NSNumber numberWithLong:httpResponse.statusCode];
|
|
107
|
+
}
|
|
108
|
+
NSURL *destURL = [NSURL fileURLWithPath:_toFile];
|
|
109
|
+
NSFileManager *fm = [NSFileManager defaultManager];
|
|
110
|
+
NSError *error = nil;
|
|
111
|
+
if([_statusCode integerValue] >= 200 && [_statusCode integerValue] < 300) {
|
|
112
|
+
[fm removeItemAtURL:destURL error:nil]; // Remove file at destination path, if it exists
|
|
113
|
+
[fm moveItemAtURL:location toURL:destURL error:&error];
|
|
114
|
+
// There are no guarantees about how often URLSession:downloadTask:didWriteData: will fire,
|
|
115
|
+
// so we read an authoritative number of bytes written here.
|
|
116
|
+
_bytesWritten = @([fm attributesOfItemAtPath:_toFile error:nil].fileSize);
|
|
117
|
+
}
|
|
118
|
+
if (error) {
|
|
119
|
+
NSLog(@"RNFS download: unable to move tempfile to destination. %@, %@", error, error.userInfo);
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
// When numerous downloads are called the sessions are not always invalidated and cleared by iOS14.
|
|
123
|
+
// This leads to error 28 – no space left on device so we manually flush and invalidate to free up space
|
|
124
|
+
if(session != nil){
|
|
125
|
+
[session flushWithCompletionHandler:^{
|
|
126
|
+
[session finishTasksAndInvalidate];
|
|
127
|
+
}];
|
|
128
|
+
}
|
|
129
|
+
NSURL *fileURL = [NSURL fileURLWithPath:_toFile];
|
|
130
|
+
return globalDownloadCompleteCallback([fileURL absoluteString]);
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
|
|
134
|
+
{
|
|
135
|
+
if (error) {
|
|
136
|
+
NSLog(@"RNFS download: didCompleteWithError %@, %@", error, error.userInfo);
|
|
137
|
+
if (error.code != NSURLErrorCancelled) {
|
|
138
|
+
_resumeData = error.userInfo[NSURLSessionDownloadTaskResumeData];
|
|
139
|
+
if (_resumeData != nil) {
|
|
140
|
+
|
|
141
|
+
} else {
|
|
142
|
+
globalErrorCallback(error);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
@end
|