Skip to content

Commit f98be8f

Browse files
committed
Merge branch 'master' of github.com:itinance/react-native-fs
* 'master' of github.com:itinance/react-native-fs: Added copyAssetsFileIOS to support asset-library-Files from camera-roll in iOS
2 parents 91d93b8 + 285d0fb commit f98be8f

File tree

4 files changed

+108
-14
lines changed

4 files changed

+108
-14
lines changed

FS.common.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,15 @@ var RNFS = {
274274
return RNFSManager.copyFileAssets(normalizeFilePath(filepath), normalizeFilePath(destPath)).then(() => void 0);
275275
},
276276

277+
// iOS only
278+
// Copies fotos from asset-library (camera-roll) to a specific location
279+
// with a given width or height
280+
// @see: https://developer.apple.com/reference/photos/phimagemanager/1616964-requestimageforasset
281+
copyAssetsFileIOS(imageUri: string, destPath: string, width: number, height: number,
282+
scale : number = 1.0, compression : number = 1.0, resizeMode : string = 'contain' ): Promise<string> {
283+
return RNFSManager.copyAssetsFileIOS(imageUri, destPath, width, height, scale, compression, resizeMode );
284+
},
285+
277286
writeFile(filepath: string, contents: string, encodingOrOptions?: any): Promise<void> {
278287
var b64;
279288

README.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -381,10 +381,20 @@ Note: On Android copyFile will overwrite `destPath` if it already exists. On iOS
381381

382382
### `copyFileAssets(filepath: string, destPath: string): Promise<void>`
383383

384-
Copies the file at `filepath ` in the Android app's assets folder and copies it to the given `destPath ` path.
384+
Copies the file at `filepath` in the Android app's assets folder and copies it to the given `destPath ` path.
385385

386386
Note: Android only. Will overwrite destPath if it already exists
387387

388+
### `copyAssetsFileIOS(imageUri: string, destPath: string, width: number, height: number, scale : number = 1.0, compression : number = 1.0, resizeMode : string = 'contain' ): Promise<string>`
389+
390+
iOS-ony: copies a file from camera-roll, that is prefixed with "assets-library://asset/asset.JPG?..."
391+
to a specific destination. It will download the original from iCloud if necessary.
392+
If width and height is > 0, the image will be resized to a specific size and a specific compression rate.
393+
If scale is below 1, the image will be scaled according to the scale-factor (between 0.0 and 1.0)
394+
The resizeMode is also considered.
395+
Further information: https://developer.apple.com/reference/photos/phimagemanager/1616964-requestimageforasset
396+
The promise will on success return the final destination of the file, as it was defined in the destPath-parameter.
397+
388398
### `unlink(filepath: string): Promise<void>`
389399

390400
Unlinks the item at `filepath`. If the item does not exist, an error will be thrown.

RNFSManager.h

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,17 +6,8 @@
66
// Copyright (c) 2015 Johannes Lumpe. All rights reserved.
77
//
88

9-
#if __has_include("RCTBridgeModule.h")
10-
#import "RCTBridgeModule.h"
11-
#else
129
#import <React/RCTBridgeModule.h>
13-
#endif
14-
15-
#if __has_include("RCTLog.h")
16-
#import "RCTLog.h"
17-
#else
1810
#import <React/RCTLog.h>
19-
#endif
2011

2112
@interface RNFSManager : NSObject <RCTBridgeModule>
2213

RNFSManager.m

Lines changed: 88 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@
1212
#import "Downloader.h"
1313
#import "Uploader.h"
1414

15-
#if __has_include("RCTEventDispatcher.h")
16-
#import "RCTEventDispatcher.h"
17-
#else
1815
#import <React/RCTEventDispatcher.h>
19-
#endif
16+
#import <React/RCTUtils.h>
17+
#import <React/RCTImageLoader.h>
2018

2119
#import <CommonCrypto/CommonDigest.h>
20+
#import <Photos/Photos.h>
21+
2222

2323
@interface RNFSManager()
2424

@@ -503,6 +503,90 @@ - (dispatch_queue_t)methodQueue
503503
}
504504
}
505505

506+
507+
/**
508+
* iOS Only: copy images from the assets-library (camera-roll) to a specific path, asuming
509+
* JPEG-Images. Video-Support will follow up, not implemented yet.
510+
*
511+
* It is also supported to scale the image via scale-factor (0.0-1.0) or with a specific
512+
* width and height. Also the resizeMode will be considered.
513+
*/
514+
RCT_EXPORT_METHOD(copyAssetsFileIOS: (NSString *) imageUri
515+
toFilepath: (NSString *) destination
516+
width: (NSInteger) width
517+
height: (NSInteger) height
518+
scale: (CGFloat) scale
519+
compression: (CGFloat) compression
520+
resizeMode: (RCTResizeMode) resizeMode
521+
resolver: (RCTPromiseResolveBlock) resolve
522+
rejecter: (RCTPromiseRejectBlock) reject)
523+
524+
{
525+
CGSize size = CGSizeMake(width, height);
526+
527+
NSURL* url = [NSURL URLWithString:imageUri];
528+
PHFetchResult *results = [PHAsset fetchAssetsWithALAssetURLs:@[url] options:nil];
529+
530+
if (results.count == 0) {
531+
NSString *errorText = [NSString stringWithFormat:@"Failed to fetch PHAsset with local identifier %@ with no error message.", imageUri];
532+
533+
NSMutableDictionary* details = [NSMutableDictionary dictionary];
534+
[details setValue:errorText forKey:NSLocalizedDescriptionKey];
535+
NSError *error = [NSError errorWithDomain:@"RNFS" code:500 userInfo:details];
536+
[self reject: reject withError:error];
537+
return;
538+
}
539+
540+
PHAsset *asset = [results firstObject];
541+
PHImageRequestOptions *imageOptions = [PHImageRequestOptions new];
542+
543+
// Allow us to fetch images from iCloud
544+
imageOptions.networkAccessAllowed = YES;
545+
546+
547+
// Note: PhotoKit defaults to a deliveryMode of PHImageRequestOptionsDeliveryModeOpportunistic
548+
// which means it may call back multiple times - we probably don't want that
549+
imageOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
550+
551+
BOOL useMaximumSize = CGSizeEqualToSize(size, CGSizeZero);
552+
CGSize targetSize;
553+
if (useMaximumSize) {
554+
targetSize = PHImageManagerMaximumSize;
555+
imageOptions.resizeMode = PHImageRequestOptionsResizeModeNone;
556+
} else {
557+
targetSize = CGSizeApplyAffineTransform(size, CGAffineTransformMakeScale(scale, scale));
558+
imageOptions.resizeMode = PHImageRequestOptionsResizeModeFast;
559+
}
560+
561+
PHImageContentMode contentMode = PHImageContentModeAspectFill;
562+
if (resizeMode == RCTResizeModeContain) {
563+
contentMode = PHImageContentModeAspectFit;
564+
}
565+
566+
// PHImageRequestID requestID =
567+
[[PHImageManager defaultManager] requestImageForAsset:asset
568+
targetSize:targetSize
569+
contentMode:contentMode
570+
options:imageOptions
571+
resultHandler:^(UIImage *result, NSDictionary<NSString *, id> *info) {
572+
if (result) {
573+
574+
NSData *imageData = UIImageJPEGRepresentation(result, compression );
575+
[imageData writeToFile:destination atomically:YES];
576+
resolve(destination);
577+
578+
} else {
579+
NSMutableDictionary* details = [NSMutableDictionary dictionary];
580+
[details setValue:info[PHImageErrorKey] forKey:NSLocalizedDescriptionKey];
581+
NSError *error = [NSError errorWithDomain:@"RNFS" code:501 userInfo:details];
582+
[self reject: reject withError:error];
583+
584+
}
585+
}];
586+
587+
588+
}
589+
506590
- (NSNumber *)dateToTimeIntervalNumber:(NSDate *)date
507591
{
508592
return @([date timeIntervalSince1970]);

0 commit comments

Comments
 (0)