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:
Tolgahan Çelik
2022-12-08 09:22:33 +01:00
committed by GitHub
parent bf03ab5a63
commit d515b12681
5 changed files with 44 additions and 16 deletions
+2
View File
@@ -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
View File
@@ -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);
}
+2
View File
@@ -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;