mirror of
https://github.com/status-im/react-native-camera-roll.git
synced 2026-08-29 04:11:10 +00:00
feat(all): file extension support (for CameraRoll.getPhotos ) (#440)
* Ios added extension support. * Android added extesion support. * Android mimetype process moved to utils. * Typescript added types. * Readme added types.
This commit is contained in:
@@ -237,6 +237,7 @@ Returns a Promise with photo identifier objects from the local camera roll of th
|
||||
* `include` : {Array} : Whether to include some fields that are slower to fetch
|
||||
* `filename` : Ensures `image.filename` is available in each node. This has a large performance impact on iOS.
|
||||
* `fileSize` : Ensures `image.fileSize` is available in each node. This has a large performance impact on iOS.
|
||||
* `fileExtension` : Ensures `image.fileExtension` is available in each node.
|
||||
* `location`: Ensures `location` is available in each node. This has a large performance impact on Android.
|
||||
* `imageSize` : Ensures `image.width` and `image.height` are available in each node. This has a small performance impact on Android.
|
||||
* `playableDuration` : Ensures `image.playableDuration` is available in each node. This has a medium peformance impact on Android.
|
||||
@@ -250,6 +251,7 @@ Returns a Promise which when resolved will be of the following shape:
|
||||
* `image`: {object} : An object with the following shape:
|
||||
* `uri`: {string}
|
||||
* `filename`: {string | null} : Only set if the `include` parameter contains `filename`
|
||||
* `extension`: {string | null} : Only set if the `include` parameter contains `fileExtension`
|
||||
* `height`: {number | null} : Only set if the `include` parameter contains `imageSize`
|
||||
* `width`: {number | null} : Only set if the `include` parameter contains `imageSize`
|
||||
* `fileSize`: {number | null} : Only set if the `include` parameter contains `fileSize`
|
||||
|
||||
@@ -80,6 +80,7 @@ public class CameraRollModule extends ReactContextBaseJavaModule {
|
||||
|
||||
private static final String INCLUDE_FILENAME = "filename";
|
||||
private static final String INCLUDE_FILE_SIZE = "fileSize";
|
||||
private static final String INCLUDE_FILE_EXTENSION = "fileExtension";
|
||||
private static final String INCLUDE_LOCATION = "location";
|
||||
private static final String INCLUDE_IMAGE_SIZE = "imageSize";
|
||||
private static final String INCLUDE_PLAYABLE_DURATION = "playableDuration";
|
||||
@@ -572,6 +573,7 @@ public class CameraRollModule extends ReactContextBaseJavaModule {
|
||||
boolean includeLocation = include.contains(INCLUDE_LOCATION);
|
||||
boolean includeFilename = include.contains(INCLUDE_FILENAME);
|
||||
boolean includeFileSize = include.contains(INCLUDE_FILE_SIZE);
|
||||
boolean includeFileExtension = include.contains(INCLUDE_FILE_EXTENSION);
|
||||
boolean includeImageSize = include.contains(INCLUDE_IMAGE_SIZE);
|
||||
boolean includePlayableDuration = include.contains(INCLUDE_PLAYABLE_DURATION);
|
||||
|
||||
@@ -580,7 +582,7 @@ public class CameraRollModule extends ReactContextBaseJavaModule {
|
||||
WritableMap node = new WritableNativeMap();
|
||||
boolean imageInfoSuccess =
|
||||
putImageInfo(resolver, media, node, widthIndex, heightIndex, sizeIndex, dataIndex,
|
||||
mimeTypeIndex, includeFilename, includeFileSize, includeImageSize,
|
||||
mimeTypeIndex, includeFilename, includeFileSize, includeFileExtension, includeImageSize,
|
||||
includePlayableDuration);
|
||||
if (imageInfoSuccess) {
|
||||
putBasicNodeInfo(media, node, mimeTypeIndex, groupNameIndex, dateTakenIndex, dateAddedIndex, dateModifiedIndex);
|
||||
@@ -632,6 +634,7 @@ public class CameraRollModule extends ReactContextBaseJavaModule {
|
||||
int mimeTypeIndex,
|
||||
boolean includeFilename,
|
||||
boolean includeFileSize,
|
||||
boolean includeFileExtension,
|
||||
boolean includeImageSize,
|
||||
boolean includePlayableDuration) {
|
||||
WritableMap image = new WritableNativeMap();
|
||||
@@ -659,6 +662,12 @@ public class CameraRollModule extends ReactContextBaseJavaModule {
|
||||
image.putNull("fileSize");
|
||||
}
|
||||
|
||||
if (includeFileExtension) {
|
||||
image.putString("extension", Utils.getExtension(mimeType));
|
||||
} else {
|
||||
image.putNull("extension");
|
||||
}
|
||||
|
||||
node.putMap("image", image);
|
||||
return putImageSizeSuccess && putPlayableDurationSuccess;
|
||||
}
|
||||
|
||||
@@ -13,4 +13,9 @@ public class Utils {
|
||||
return type;
|
||||
}
|
||||
|
||||
public static String getExtension(String mimeType) {
|
||||
String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);
|
||||
return extension;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+25
-15
@@ -293,6 +293,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||
|
||||
BOOL __block includeFilename = [include indexOfObject:@"filename"] != NSNotFound;
|
||||
BOOL __block includeFileSize = [include indexOfObject:@"fileSize"] != NSNotFound;
|
||||
BOOL __block includeFileExtension = [include indexOfObject:@"fileExtension"] != NSNotFound;
|
||||
BOOL __block includeLocation = [include indexOfObject:@"location"] != NSNotFound;
|
||||
BOOL __block includeImageSize = [include indexOfObject:@"imageSize"] != NSNotFound;
|
||||
BOOL __block includePlayableDuration = [include indexOfObject:@"playableDuration"] != NSNotFound;
|
||||
@@ -338,7 +339,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||
requestPhotoLibraryAccess(reject, ^(bool isLimited){
|
||||
void (^collectAsset)(PHAsset*, NSUInteger, BOOL*) = ^(PHAsset * _Nonnull asset, NSUInteger assetIdx, BOOL * _Nonnull stopAssets) {
|
||||
NSString *const uri = [NSString stringWithFormat:@"ph://%@", [asset localIdentifier]];
|
||||
|
||||
|
||||
if (afterCursor && !foundAfter) {
|
||||
if ([afterCursor isEqualToString:uri]) {
|
||||
foundAfter = YES;
|
||||
@@ -346,6 +347,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||
return;
|
||||
}
|
||||
NSString *_Nullable originalFilename = NULL;
|
||||
NSString *_Nullable fileExtension = NULL;
|
||||
PHAssetResource *_Nullable resource = NULL;
|
||||
NSNumber* fileSize = [NSNumber numberWithInt:0];
|
||||
|
||||
@@ -399,6 +401,13 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||
: (asset.mediaType == PHAssetMediaTypeAudio
|
||||
? @"audio"
|
||||
: @"unknown")));
|
||||
|
||||
if (includeFileExtension) {
|
||||
NSString *name = [asset valueForKey:@"filename"];
|
||||
NSString *extension = [name pathExtension];
|
||||
fileExtension = [extension lowercaseString];
|
||||
}
|
||||
|
||||
CLLocation *const loc = asset.location;
|
||||
|
||||
[assets addObject:@{
|
||||
@@ -407,6 +416,7 @@ RCT_EXPORT_METHOD(getPhotos:(NSDictionary *)params
|
||||
@"group_name": currentCollectionName,
|
||||
@"image": @{
|
||||
@"uri": uri,
|
||||
@"extension": (includeFileExtension ? fileExtension : [NSNull null]),
|
||||
@"filename": (includeFilename && originalFilename ? originalFilename : [NSNull null]),
|
||||
@"height": (includeImageSize ? @([asset pixelHeight]) : [NSNull null]),
|
||||
@"width": (includeImageSize ? @([asset pixelWidth]) : [NSNull null]),
|
||||
@@ -487,25 +497,25 @@ RCT_EXPORT_METHOD(getPhotoByInternalID:(NSString *)internalId
|
||||
BOOL const convertHeic = [RCTConvert BOOL:options[@"convertHeicImages"]];
|
||||
|
||||
requestPhotoLibraryAccess(reject, ^(bool isLimited){
|
||||
|
||||
|
||||
PHFetchResult<PHAsset *> *fetchResult;
|
||||
PHAsset *asset;
|
||||
|
||||
|
||||
NSString *mediaIdentifier = internalId;
|
||||
|
||||
|
||||
if ([internalId rangeOfString:@"ph://"].location != NSNotFound) {
|
||||
mediaIdentifier = [internalId stringByReplacingOccurrencesOfString:@"ph://"
|
||||
withString:@""];
|
||||
}
|
||||
|
||||
|
||||
fetchResult = [PHAsset fetchAssetsWithLocalIdentifiers:@[mediaIdentifier] options:nil];
|
||||
if(fetchResult){
|
||||
asset = fetchResult.firstObject;//only object in the array.
|
||||
}
|
||||
|
||||
|
||||
if(asset){
|
||||
__block NSURL *imageURL = [[NSURL alloc]initWithString:@""];
|
||||
|
||||
|
||||
NSString *const assetMediaTypeLabel = (asset.mediaType == PHAssetMediaTypeVideo
|
||||
? @"video"
|
||||
: (asset.mediaType == PHAssetMediaTypeImage
|
||||
@@ -516,16 +526,16 @@ RCT_EXPORT_METHOD(getPhotoByInternalID:(NSString *)internalId
|
||||
|
||||
|
||||
CLLocation *const loc = asset.location;
|
||||
|
||||
|
||||
NSArray<PHAssetResource *> *const assetResources = [PHAssetResource assetResourcesForAsset:asset];
|
||||
if (![assetResources firstObject]) {
|
||||
return;
|
||||
}
|
||||
PHAssetResource *const _Nonnull resource = [assetResources firstObject];
|
||||
|
||||
|
||||
__block NSString *originalFilename = resource.originalFilename;
|
||||
NSString *const uniformMimeType = resource.uniformTypeIdentifier;
|
||||
|
||||
|
||||
__block NSString *filePath = @"";
|
||||
|
||||
// check if HEIC extension asset
|
||||
@@ -535,7 +545,7 @@ RCT_EXPORT_METHOD(getPhotoByInternalID:(NSString *)internalId
|
||||
requestOptions.networkAccessAllowed = YES;
|
||||
requestOptions.version = PHImageRequestOptionsVersionUnadjusted;
|
||||
requestOptions.deliveryMode = PHImageRequestOptionsDeliveryModeHighQualityFormat;
|
||||
|
||||
|
||||
CGSize const targetSize = CGSizeMake((CGFloat)asset.pixelWidth, (CGFloat)asset.pixelHeight);
|
||||
[[PHImageManager defaultManager] requestImageForAsset:asset
|
||||
targetSize:targetSize
|
||||
@@ -589,11 +599,11 @@ RCT_EXPORT_METHOD(getPhotoByInternalID:(NSString *)internalId
|
||||
PHContentEditingInputRequestOptions *const editOptions = [PHContentEditingInputRequestOptions new];
|
||||
// Download asset if on icloud.
|
||||
editOptions.networkAccessAllowed = YES;
|
||||
|
||||
|
||||
[asset requestContentEditingInputWithOptions:editOptions completionHandler:^(PHContentEditingInput *contentEditingInput, NSDictionary *info) {
|
||||
imageURL = contentEditingInput.fullSizeImageURL;
|
||||
if (imageURL.absoluteString.length != 0) {
|
||||
|
||||
|
||||
filePath = [imageURL.absoluteString stringByReplacingOccurrencesOfString:@"pathfile:" withString:@"file:"];
|
||||
|
||||
resolve(@{
|
||||
@@ -626,14 +636,14 @@ RCT_EXPORT_METHOD(getPhotoByInternalID:(NSString *)internalId
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
} else {
|
||||
NSString *errorMessage = [NSString stringWithFormat:@"Failed to load asset"
|
||||
" with localIdentifier %@ with no error message.", internalId];
|
||||
NSError *error = RCTErrorWithMessage(errorMessage);
|
||||
reject(@"No asset found",@"No asset found",error);
|
||||
}
|
||||
|
||||
|
||||
}, false);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@ export type GroupTypes =
|
||||
export type Include =
|
||||
| 'filename'
|
||||
| 'fileSize'
|
||||
| 'fileExtension'
|
||||
| 'location'
|
||||
| 'imageSize'
|
||||
| 'playableDuration';
|
||||
@@ -101,6 +102,7 @@ export type PhotoIdentifier = {
|
||||
group_name: string;
|
||||
image: {
|
||||
filename: string | null;
|
||||
extension: string | null;
|
||||
uri: string;
|
||||
height: number;
|
||||
width: number;
|
||||
|
||||
Reference in New Issue
Block a user