Return cropped image rectangle (#458)

* android: Update ucrop version #457

Use latest uCrop version.

* Return cropped image rectangle #457

* Update README.md #457

Update Android installation instructions.
This commit is contained in:
Ivan Magda 2017-12-07 03:47:38 +03:00 committed by Ivan Pusic
parent 1476fd80aa
commit 5633a99c4a
5 changed files with 133 additions and 83 deletions

View File

@ -202,6 +202,16 @@ buildscript {
} }
``` ```
- Add the following to your `build.gradle`'s repositories section. (project build.gradle)
```gradle
allprojects {
repositories {
jcenter()
maven { url "https://jitpack.io" }
}
}
```
- Add `useSupportLibrary` (app build.gradle) - Add `useSupportLibrary` (app build.gradle)
```gradle ```gradle

View File

@ -16,6 +16,6 @@ android {
dependencies { dependencies {
compile 'com.facebook.react:react-native:+' compile 'com.facebook.react:react-native:+'
compile 'com.yalantis:ucrop:2.2.0-native' compile 'com.github.yalantis:ucrop:2.2.1-native'
compile 'id.zelory:compressor:2.1.0' compile 'id.zelory:compressor:2.1.0'
} }

View File

@ -678,8 +678,11 @@ class PickerModule extends ReactContextBaseJavaModule implements ActivityEventLi
final Uri resultUri = UCrop.getOutput(data); final Uri resultUri = UCrop.getOutput(data);
if (resultUri != null) { if (resultUri != null) {
try { try {
WritableMap result = getSelection(activity, resultUri, false);
result.putMap("cropRect", PickerModule.getCroppedRectMap(data));
resultCollector.setWaitCount(1); resultCollector.setWaitCount(1);
resultCollector.notifySuccess(getSelection(activity, resultUri, false)); resultCollector.notifySuccess(result);
} catch (Exception ex) { } catch (Exception ex) {
resultCollector.notifyProblem(E_NO_IMAGE_DATA_FOUND, ex.getMessage()); resultCollector.notifyProblem(E_NO_IMAGE_DATA_FOUND, ex.getMessage());
} }
@ -729,4 +732,16 @@ class PickerModule extends ReactContextBaseJavaModule implements ActivityEventLi
return image; return image;
} }
private static WritableMap getCroppedRectMap(Intent data) {
final int DEFAULT_VALUE = -1;
final WritableMap map = new WritableNativeMap();
map.putInt("x", data.getIntExtra(UCrop.EXTRA_OUTPUT_OFFSET_X, DEFAULT_VALUE));
map.putInt("y", data.getIntExtra(UCrop.EXTRA_OUTPUT_OFFSET_Y, DEFAULT_VALUE));
map.putInt("width", data.getIntExtra(UCrop.EXTRA_OUTPUT_IMAGE_WIDTH, DEFAULT_VALUE));
map.putInt("height", data.getIntExtra(UCrop.EXTRA_OUTPUT_IMAGE_HEIGHT, DEFAULT_VALUE));
return map;
}
} }

8
index.d.ts vendored
View File

@ -33,6 +33,14 @@ declare module "react-native-image-crop-picker" {
height: number; height: number;
mime: string; mime: string;
exif: null | object; exif: null | object;
cropRect: null | CropRect
}
export interface CropRect {
x: number;
y: number;
width: number;
height: number;
} }
export function openPicker(options: Options): Promise<Image | Image[]>; export function openPicker(options: Options): Promise<Image | Image[]>;

View File

@ -67,7 +67,7 @@ RCT_EXPORT_MODULE();
}; };
self.compression = [[Compression alloc] init]; self.compression = [[Compression alloc] init];
} }
return self; return self;
} }
@ -79,11 +79,11 @@ RCT_EXPORT_MODULE();
if ([[self.options objectForKey:@"waitAnimationEnd"] boolValue]) { if ([[self.options objectForKey:@"waitAnimationEnd"] boolValue]) {
return completion; return completion;
} }
if (completion != nil) { if (completion != nil) {
completion(); completion();
} }
return nil; return nil;
} }
@ -106,7 +106,7 @@ RCT_EXPORT_MODULE();
- (void) setConfiguration:(NSDictionary *)options - (void) setConfiguration:(NSDictionary *)options
resolver:(RCTPromiseResolveBlock)resolve resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject { rejecter:(RCTPromiseRejectBlock)reject {
self.resolve = resolve; self.resolve = resolve;
self.reject = reject; self.reject = reject;
self.options = [NSMutableDictionary dictionaryWithDictionary:self.defaultOptions]; self.options = [NSMutableDictionary dictionaryWithDictionary:self.defaultOptions];
@ -120,17 +120,17 @@ RCT_EXPORT_MODULE();
while (root.presentedViewController != nil) { while (root.presentedViewController != nil) {
root = root.presentedViewController; root = root.presentedViewController;
} }
return root; return root;
} }
RCT_EXPORT_METHOD(openCamera:(NSDictionary *)options RCT_EXPORT_METHOD(openCamera:(NSDictionary *)options
resolver:(RCTPromiseResolveBlock)resolve resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) { rejecter:(RCTPromiseRejectBlock)reject) {
[self setConfiguration:options resolver:resolve rejecter:reject]; [self setConfiguration:options resolver:resolve rejecter:reject];
self.currentSelectionMode = CAMERA; self.currentSelectionMode = CAMERA;
#if TARGET_IPHONE_SIMULATOR #if TARGET_IPHONE_SIMULATOR
self.reject(ERROR_PICKER_CANNOT_RUN_CAMERA_ON_SIMULATOR_KEY, ERROR_PICKER_CANNOT_RUN_CAMERA_ON_SIMULATOR_MSG, nil); self.reject(ERROR_PICKER_CANNOT_RUN_CAMERA_ON_SIMULATOR_KEY, ERROR_PICKER_CANNOT_RUN_CAMERA_ON_SIMULATOR_MSG, nil);
return; return;
@ -140,7 +140,7 @@ RCT_EXPORT_METHOD(openCamera:(NSDictionary *)options
self.reject(ERROR_PICKER_NO_CAMERA_PERMISSION_KEY, ERROR_PICKER_NO_CAMERA_PERMISSION_MSG, nil); self.reject(ERROR_PICKER_NO_CAMERA_PERMISSION_KEY, ERROR_PICKER_NO_CAMERA_PERMISSION_MSG, nil);
return; return;
} }
UIImagePickerController *picker = [[UIImagePickerController alloc] init]; UIImagePickerController *picker = [[UIImagePickerController alloc] init];
picker.delegate = self; picker.delegate = self;
picker.allowsEditing = NO; picker.allowsEditing = NO;
@ -148,7 +148,7 @@ RCT_EXPORT_METHOD(openCamera:(NSDictionary *)options
if ([[self.options objectForKey:@"useFrontCamera"] boolValue]) { if ([[self.options objectForKey:@"useFrontCamera"] boolValue]) {
picker.cameraDevice = UIImagePickerControllerCameraDeviceFront; picker.cameraDevice = UIImagePickerControllerCameraDeviceFront;
} }
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[[self getRootVC] presentViewController:picker animated:YES completion:nil]; [[self getRootVC] presentViewController:picker animated:YES completion:nil];
}); });
@ -163,12 +163,12 @@ RCT_EXPORT_METHOD(openCamera:(NSDictionary *)options
- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info { - (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info {
UIImage *chosenImage = [info objectForKey:UIImagePickerControllerOriginalImage]; UIImage *chosenImage = [info objectForKey:UIImagePickerControllerOriginalImage];
UIImage *chosenImageT = [chosenImage fixOrientation]; UIImage *chosenImageT = [chosenImage fixOrientation];
NSDictionary *exif; NSDictionary *exif;
if([[self.options objectForKey:@"includeExif"] boolValue]) { if([[self.options objectForKey:@"includeExif"] boolValue]) {
exif = [info objectForKey:UIImagePickerControllerMediaMetadata]; exif = [info objectForKey:UIImagePickerControllerMediaMetadata];
} }
[self processSingleImagePick:chosenImageT withExif:exif withViewController:picker withSourceURL:self.croppingFile[@"sourceURL"] withLocalIdentifier:self.croppingFile[@"localIdentifier"] withFilename:self.croppingFile[@"filename"] withCreationDate:self.croppingFile[@"creationDate"] withModificationDate:self.croppingFile[@"modificationDate"]]; [self processSingleImagePick:chosenImageT withExif:exif withViewController:picker withSourceURL:self.croppingFile[@"sourceURL"] withLocalIdentifier:self.croppingFile[@"localIdentifier"] withFilename:self.croppingFile[@"filename"] withCreationDate:self.croppingFile[@"creationDate"] withModificationDate:self.croppingFile[@"modificationDate"]];
} }
@ -181,38 +181,38 @@ RCT_EXPORT_METHOD(openCamera:(NSDictionary *)options
- (NSString*) getTmpDirectory { - (NSString*) getTmpDirectory {
NSString *TMP_DIRECTORY = @"react-native-image-crop-picker/"; NSString *TMP_DIRECTORY = @"react-native-image-crop-picker/";
NSString *tmpFullPath = [NSTemporaryDirectory() stringByAppendingString:TMP_DIRECTORY]; NSString *tmpFullPath = [NSTemporaryDirectory() stringByAppendingString:TMP_DIRECTORY];
BOOL isDir; BOOL isDir;
BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:tmpFullPath isDirectory:&isDir]; BOOL exists = [[NSFileManager defaultManager] fileExistsAtPath:tmpFullPath isDirectory:&isDir];
if (!exists) { if (!exists) {
[[NSFileManager defaultManager] createDirectoryAtPath: tmpFullPath [[NSFileManager defaultManager] createDirectoryAtPath: tmpFullPath
withIntermediateDirectories:YES attributes:nil error:nil]; withIntermediateDirectories:YES attributes:nil error:nil];
} }
return tmpFullPath; return tmpFullPath;
} }
- (BOOL)cleanTmpDirectory { - (BOOL)cleanTmpDirectory {
NSString* tmpDirectoryPath = [self getTmpDirectory]; NSString* tmpDirectoryPath = [self getTmpDirectory];
NSArray* tmpDirectory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirectoryPath error:NULL]; NSArray* tmpDirectory = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirectoryPath error:NULL];
for (NSString *file in tmpDirectory) { for (NSString *file in tmpDirectory) {
BOOL deleted = [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@%@", tmpDirectoryPath, file] error:NULL]; BOOL deleted = [[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@%@", tmpDirectoryPath, file] error:NULL];
if (!deleted) { if (!deleted) {
return NO; return NO;
} }
} }
return YES; return YES;
} }
RCT_EXPORT_METHOD(cleanSingle:(NSString *) path RCT_EXPORT_METHOD(cleanSingle:(NSString *) path
resolver:(RCTPromiseResolveBlock)resolve resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) { rejecter:(RCTPromiseRejectBlock)reject) {
BOOL deleted = [[NSFileManager defaultManager] removeItemAtPath:path error:NULL]; BOOL deleted = [[NSFileManager defaultManager] removeItemAtPath:path error:NULL];
if (!deleted) { if (!deleted) {
reject(ERROR_CLEANUP_ERROR_KEY, ERROR_CLEANUP_ERROR_MSG, nil); reject(ERROR_CLEANUP_ERROR_KEY, ERROR_CLEANUP_ERROR_MSG, nil);
} else { } else {
@ -232,16 +232,16 @@ RCT_REMAP_METHOD(clean, resolver:(RCTPromiseResolveBlock)resolve
RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
resolver:(RCTPromiseResolveBlock)resolve resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) { rejecter:(RCTPromiseRejectBlock)reject) {
[self setConfiguration:options resolver:resolve rejecter:reject]; [self setConfiguration:options resolver:resolve rejecter:reject];
self.currentSelectionMode = PICKER; self.currentSelectionMode = PICKER;
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) { [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
if (status != PHAuthorizationStatusAuthorized) { if (status != PHAuthorizationStatusAuthorized) {
self.reject(ERROR_PICKER_UNAUTHORIZED_KEY, ERROR_PICKER_UNAUTHORIZED_MSG, nil); self.reject(ERROR_PICKER_UNAUTHORIZED_KEY, ERROR_PICKER_UNAUTHORIZED_MSG, nil);
return; return;
} }
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
// init picker // init picker
QBImagePickerController *imagePickerController = QBImagePickerController *imagePickerController =
@ -251,7 +251,7 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
imagePickerController.minimumNumberOfSelection = abs([[self.options objectForKey:@"minFiles"] intValue]); imagePickerController.minimumNumberOfSelection = abs([[self.options objectForKey:@"minFiles"] intValue]);
imagePickerController.maximumNumberOfSelection = abs([[self.options objectForKey:@"maxFiles"] intValue]); imagePickerController.maximumNumberOfSelection = abs([[self.options objectForKey:@"maxFiles"] intValue]);
imagePickerController.showsNumberOfSelectedAssets = [[self.options objectForKey:@"showsSelectedCount"] boolValue]; imagePickerController.showsNumberOfSelectedAssets = [[self.options objectForKey:@"showsSelectedCount"] boolValue];
if ([self.options objectForKey:@"smartAlbums"] != nil) { if ([self.options objectForKey:@"smartAlbums"] != nil) {
NSDictionary *smartAlbums = @{ NSDictionary *smartAlbums = @{
@"UserLibrary" : @(PHAssetCollectionSubtypeSmartAlbumUserLibrary), @"UserLibrary" : @(PHAssetCollectionSubtypeSmartAlbumUserLibrary),
@ -268,12 +268,12 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
} }
imagePickerController.assetCollectionSubtypes = albumsToShow; imagePickerController.assetCollectionSubtypes = albumsToShow;
} }
if ([[self.options objectForKey:@"cropping"] boolValue]) { if ([[self.options objectForKey:@"cropping"] boolValue]) {
imagePickerController.mediaType = QBImagePickerMediaTypeImage; imagePickerController.mediaType = QBImagePickerMediaTypeImage;
} else { } else {
NSString *mediaType = [self.options objectForKey:@"mediaType"]; NSString *mediaType = [self.options objectForKey:@"mediaType"];
if ([mediaType isEqualToString:@"any"]) { if ([mediaType isEqualToString:@"any"]) {
imagePickerController.mediaType = QBImagePickerMediaTypeAny; imagePickerController.mediaType = QBImagePickerMediaTypeAny;
} else if ([mediaType isEqualToString:@"photo"]) { } else if ([mediaType isEqualToString:@"photo"]) {
@ -281,9 +281,9 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
} else { } else {
imagePickerController.mediaType = QBImagePickerMediaTypeVideo; imagePickerController.mediaType = QBImagePickerMediaTypeVideo;
} }
} }
[[self getRootVC] presentViewController:imagePickerController animated:YES completion:nil]; [[self getRootVC] presentViewController:imagePickerController animated:YES completion:nil];
}); });
}]; }];
@ -292,12 +292,12 @@ RCT_EXPORT_METHOD(openPicker:(NSDictionary *)options
RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
resolver:(RCTPromiseResolveBlock)resolve resolver:(RCTPromiseResolveBlock)resolve
rejecter:(RCTPromiseRejectBlock)reject) { rejecter:(RCTPromiseRejectBlock)reject) {
[self setConfiguration:options resolver:resolve rejecter:reject]; [self setConfiguration:options resolver:resolve rejecter:reject];
self.currentSelectionMode = CROPPING; self.currentSelectionMode = CROPPING;
NSString *path = [options objectForKey:@"path"]; NSString *path = [options objectForKey:@"path"];
[self.bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:path] callback:^(NSError *error, UIImage *image) { [self.bridge.imageLoader loadImageWithURLRequest:[RCTConvert NSURLRequest:path] callback:^(NSError *error, UIImage *image) {
if (error) { if (error) {
self.reject(ERROR_CROPPER_IMAGE_NOT_FOUND_KEY, ERROR_CROPPER_IMAGE_NOT_FOUND_MSG, nil); self.reject(ERROR_CROPPER_IMAGE_NOT_FOUND_KEY, ERROR_CROPPER_IMAGE_NOT_FOUND_MSG, nil);
@ -319,7 +319,7 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
imageCropVC.delegate = self; imageCropVC.delegate = self;
[imageCropVC setModalPresentationStyle:UIModalPresentationCustom]; [imageCropVC setModalPresentationStyle:UIModalPresentationCustom];
[imageCropVC setModalTransitionStyle:UIModalTransitionStyleCrossDissolve]; [imageCropVC setModalTransitionStyle:UIModalTransitionStyleCrossDissolve];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[[self getRootVC] presentViewController:imageCropVC animated:YES completion:nil]; [[self getRootVC] presentViewController:imageCropVC animated:YES completion:nil];
}); });
@ -328,18 +328,18 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
- (void)showActivityIndicator:(void (^)(UIActivityIndicatorView*, UIView*))handler { - (void)showActivityIndicator:(void (^)(UIActivityIndicatorView*, UIView*))handler {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
UIView *mainView = [[self getRootVC] view]; UIView *mainView = [[self getRootVC] view];
// create overlay // create overlay
UIView *loadingView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds]; UIView *loadingView = [[UIView alloc] initWithFrame:[UIScreen mainScreen].bounds];
loadingView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5]; loadingView.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.5];
loadingView.clipsToBounds = YES; loadingView.clipsToBounds = YES;
// create loading spinner // create loading spinner
UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]; UIActivityIndicatorView *activityView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityView.frame = CGRectMake(65, 40, activityView.bounds.size.width, activityView.bounds.size.height); activityView.frame = CGRectMake(65, 40, activityView.bounds.size.width, activityView.bounds.size.height);
activityView.center = loadingView.center; activityView.center = loadingView.center;
[loadingView addSubview:activityView]; [loadingView addSubview:activityView];
// create message // create message
UILabel *loadingLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 115, 130, 22)]; UILabel *loadingLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 115, 130, 22)];
loadingLabel.backgroundColor = [UIColor clearColor]; loadingLabel.backgroundColor = [UIColor clearColor];
@ -352,11 +352,11 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
loadingLabel.text = [self.options objectForKey:@"loadingLabelText"]; loadingLabel.text = [self.options objectForKey:@"loadingLabelText"];
[loadingLabel setFont:[UIFont boldSystemFontOfSize:18]]; [loadingLabel setFont:[UIFont boldSystemFontOfSize:18]];
[loadingView addSubview:loadingLabel]; [loadingView addSubview:loadingLabel];
// show all // show all
[mainView addSubview:loadingView]; [mainView addSubview:loadingView];
[activityView startAnimating]; [activityView startAnimating];
handler(activityView, loadingView); handler(activityView, loadingView);
}); });
} }
@ -366,30 +366,30 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
PHImageManager *manager = [PHImageManager defaultManager]; PHImageManager *manager = [PHImageManager defaultManager];
PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init]; PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];
options.version = PHVideoRequestOptionsVersionOriginal; options.version = PHVideoRequestOptionsVersionOriginal;
[manager [manager
requestAVAssetForVideo:forAsset requestAVAssetForVideo:forAsset
options:options options:options
resultHandler:^(AVAsset * asset, AVAudioMix * audioMix, resultHandler:^(AVAsset * asset, AVAudioMix * audioMix,
NSDictionary *info) { NSDictionary *info) {
NSURL *sourceURL = [(AVURLAsset *)asset URL]; NSURL *sourceURL = [(AVURLAsset *)asset URL];
// create temp file // create temp file
NSString *tmpDirFullPath = [self getTmpDirectory]; NSString *tmpDirFullPath = [self getTmpDirectory];
NSString *filePath = [tmpDirFullPath stringByAppendingString:[[NSUUID UUID] UUIDString]]; NSString *filePath = [tmpDirFullPath stringByAppendingString:[[NSUUID UUID] UUIDString]];
filePath = [filePath stringByAppendingString:@".mp4"]; filePath = [filePath stringByAppendingString:@".mp4"];
NSURL *outputURL = [NSURL fileURLWithPath:filePath]; NSURL *outputURL = [NSURL fileURLWithPath:filePath];
[self.compression compressVideo:sourceURL outputURL:outputURL withOptions:self.options handler:^(AVAssetExportSession *exportSession) { [self.compression compressVideo:sourceURL outputURL:outputURL withOptions:self.options handler:^(AVAssetExportSession *exportSession) {
if (exportSession.status == AVAssetExportSessionStatusCompleted) { if (exportSession.status == AVAssetExportSessionStatusCompleted) {
AVAsset *compressedAsset = [AVAsset assetWithURL:outputURL]; AVAsset *compressedAsset = [AVAsset assetWithURL:outputURL];
AVAssetTrack *track = [[compressedAsset tracksWithMediaType:AVMediaTypeVideo] firstObject]; AVAssetTrack *track = [[compressedAsset tracksWithMediaType:AVMediaTypeVideo] firstObject];
NSNumber *fileSizeValue = nil; NSNumber *fileSizeValue = nil;
[outputURL getResourceValue:&fileSizeValue [outputURL getResourceValue:&fileSizeValue
forKey:NSURLFileSizeKey forKey:NSURLFileSizeKey
error:nil]; error:nil];
completion([self createAttachmentResponse:[outputURL absoluteString] completion([self createAttachmentResponse:[outputURL absoluteString]
withExif:nil withExif:nil
withSourceURL:[sourceURL absoluteString] withSourceURL:[sourceURL absoluteString]
@ -400,6 +400,7 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
withMime:@"video/mp4" withMime:@"video/mp4"
withSize:fileSizeValue withSize:fileSizeValue
withData:nil withData:nil
withRect:CGRectNull
withCreationDate:forAsset.creationDate withCreationDate:forAsset.creationDate
withModificationDate:forAsset.modificationDate withModificationDate:forAsset.modificationDate
]); ]);
@ -410,8 +411,7 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
}]; }];
} }
- (NSDictionary*) createAttachmentResponse:(NSString*)filePath withExif:(NSDictionary*) exif withSourceURL:(NSString*)sourceURL withLocalIdentifier:(NSString*)localIdentifier withFilename:(NSString*)filename withWidth:(NSNumber*)width withHeight:(NSNumber*)height withMime:(NSString*)mime withSize:(NSNumber*)size withData:(NSString*)data withCreationDate:(NSDate*)creationDate withModificationDate:(NSDate*)modificationDate - (NSDictionary*) createAttachmentResponse:(NSString*)filePath withExif:(NSDictionary*) exif withSourceURL:(NSString*)sourceURL withLocalIdentifier:(NSString*)localIdentifier withFilename:(NSString*)filename withWidth:(NSNumber*)width withHeight:(NSNumber*)height withMime:(NSString*)mime withSize:(NSNumber*)size withData:(NSString*)data withRect:(CGRect)cropRect withCreationDate:(NSDate*)creationDate withModificationDate:(NSDate*)modificationDate {
{
return @{ return @{
@"path": filePath, @"path": filePath,
@"sourceURL": (sourceURL) ? sourceURL : [NSNull null], @"sourceURL": (sourceURL) ? sourceURL : [NSNull null],
@ -423,6 +423,7 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
@"size": size, @"size": size,
@"data": (data) ? data : [NSNull null], @"data": (data) ? data : [NSNull null],
@"exif": (exif) ? exif : [NSNull null], @"exif": (exif) ? exif : [NSNull null],
@"cropRect": CGRectIsNull(cropRect) ? [NSNull null] : [ImageCropPicker cgRectToDictionary:cropRect],
@"creationDate:": (creationDate) ? [NSString stringWithFormat:@"%.0f", [creationDate timeIntervalSince1970]] : [NSNull null], @"creationDate:": (creationDate) ? [NSString stringWithFormat:@"%.0f", [creationDate timeIntervalSince1970]] : [NSNull null],
@"modificationDate": (modificationDate) ? [NSString stringWithFormat:@"%.0f", [modificationDate timeIntervalSince1970]] : [NSNull null], @"modificationDate": (modificationDate) ? [NSString stringWithFormat:@"%.0f", [modificationDate timeIntervalSince1970]] : [NSNull null],
}; };
@ -431,26 +432,26 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
- (void)qb_imagePickerController: - (void)qb_imagePickerController:
(QBImagePickerController *)imagePickerController (QBImagePickerController *)imagePickerController
didFinishPickingAssets:(NSArray *)assets { didFinishPickingAssets:(NSArray *)assets {
PHImageManager *manager = [PHImageManager defaultManager]; PHImageManager *manager = [PHImageManager defaultManager];
PHImageRequestOptions* options = [[PHImageRequestOptions alloc] init]; PHImageRequestOptions* options = [[PHImageRequestOptions alloc] init];
options.synchronous = NO; options.synchronous = NO;
options.networkAccessAllowed = YES; options.networkAccessAllowed = YES;
if ([[[self options] objectForKey:@"multiple"] boolValue]) { if ([[[self options] objectForKey:@"multiple"] boolValue]) {
NSMutableArray *selections = [[NSMutableArray alloc] init]; NSMutableArray *selections = [[NSMutableArray alloc] init];
[self showActivityIndicator:^(UIActivityIndicatorView *indicatorView, UIView *overlayView) { [self showActivityIndicator:^(UIActivityIndicatorView *indicatorView, UIView *overlayView) {
NSLock *lock = [[NSLock alloc] init]; NSLock *lock = [[NSLock alloc] init];
__block int processed = 0; __block int processed = 0;
for (PHAsset *phAsset in assets) { for (PHAsset *phAsset in assets) {
if (phAsset.mediaType == PHAssetMediaTypeVideo) { if (phAsset.mediaType == PHAssetMediaTypeVideo) {
[self getVideoAsset:phAsset completion:^(NSDictionary* video) { [self getVideoAsset:phAsset completion:^(NSDictionary* video) {
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[lock lock]; [lock lock];
if (video == nil) { if (video == nil) {
[indicatorView stopAnimating]; [indicatorView stopAnimating];
[overlayView removeFromSuperview]; [overlayView removeFromSuperview];
@ -459,11 +460,11 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
}]]; }]];
return; return;
} }
[selections addObject:video]; [selections addObject:video];
processed++; processed++;
[lock unlock]; [lock unlock];
if (processed == [assets count]) { if (processed == [assets count]) {
[indicatorView stopAnimating]; [indicatorView stopAnimating];
[overlayView removeFromSuperview]; [overlayView removeFromSuperview];
@ -479,18 +480,18 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
requestImageDataForAsset:phAsset requestImageDataForAsset:phAsset
options:options options:options
resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) { resultHandler:^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
NSURL *sourceURL = [info objectForKey:@"PHImageFileURLKey"]; NSURL *sourceURL = [info objectForKey:@"PHImageFileURLKey"];
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[lock lock]; [lock lock];
@autoreleasepool { @autoreleasepool {
UIImage *imgT = [UIImage imageWithData:imageData]; UIImage *imgT = [UIImage imageWithData:imageData];
UIImage *imageT = [imgT fixOrientation]; UIImage *imageT = [imgT fixOrientation];
ImageResult *imageResult = [self.compression compressImage:imageT withOptions:self.options]; ImageResult *imageResult = [self.compression compressImage:imageT withOptions:self.options];
NSString *filePath = [self persistFile:imageResult.data]; NSString *filePath = [self persistFile:imageResult.data];
if (filePath == nil) { if (filePath == nil) {
[indicatorView stopAnimating]; [indicatorView stopAnimating];
[overlayView removeFromSuperview]; [overlayView removeFromSuperview];
@ -499,12 +500,12 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
}]]; }]];
return; return;
} }
NSDictionary* exif = nil; NSDictionary* exif = nil;
if([[self.options objectForKey:@"includeExif"] boolValue]) { if([[self.options objectForKey:@"includeExif"] boolValue]) {
exif = [[CIImage imageWithData:imageData] properties]; exif = [[CIImage imageWithData:imageData] properties];
} }
[selections addObject:[self createAttachmentResponse:filePath [selections addObject:[self createAttachmentResponse:filePath
withExif: exif withExif: exif
withSourceURL:[sourceURL absoluteString] withSourceURL:[sourceURL absoluteString]
@ -515,15 +516,16 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
withMime:imageResult.mime withMime:imageResult.mime
withSize:[NSNumber numberWithUnsignedInteger:imageResult.data.length] withSize:[NSNumber numberWithUnsignedInteger:imageResult.data.length]
withData:[[self.options objectForKey:@"includeBase64"] boolValue] ? [imageResult.data base64EncodedStringWithOptions:0]: nil withData:[[self.options objectForKey:@"includeBase64"] boolValue] ? [imageResult.data base64EncodedStringWithOptions:0]: nil
withRect:CGRectNull
withCreationDate:phAsset.creationDate withCreationDate:phAsset.creationDate
withModificationDate:phAsset.modificationDate withModificationDate:phAsset.modificationDate
]]; ]];
} }
processed++; processed++;
[lock unlock]; [lock unlock];
if (processed == [assets count]) { if (processed == [assets count]) {
[indicatorView stopAnimating]; [indicatorView stopAnimating];
[overlayView removeFromSuperview]; [overlayView removeFromSuperview];
[imagePickerController dismissViewControllerAnimated:YES completion:[self waitAnimationEnd:^{ [imagePickerController dismissViewControllerAnimated:YES completion:[self waitAnimationEnd:^{
@ -538,7 +540,7 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
}]; }];
} else { } else {
PHAsset *phAsset = [assets objectAtIndex:0]; PHAsset *phAsset = [assets objectAtIndex:0];
[self showActivityIndicator:^(UIActivityIndicatorView *indicatorView, UIView *overlayView) { [self showActivityIndicator:^(UIActivityIndicatorView *indicatorView, UIView *overlayView) {
if (phAsset.mediaType == PHAssetMediaTypeVideo) { if (phAsset.mediaType == PHAssetMediaTypeVideo) {
[self getVideoAsset:phAsset completion:^(NSDictionary* video) { [self getVideoAsset:phAsset completion:^(NSDictionary* video) {
@ -566,11 +568,11 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
if([[self.options objectForKey:@"includeExif"] boolValue]) { if([[self.options objectForKey:@"includeExif"] boolValue]) {
exif = [[CIImage imageWithData:imageData] properties]; exif = [[CIImage imageWithData:imageData] properties];
} }
dispatch_async(dispatch_get_main_queue(), ^{ dispatch_async(dispatch_get_main_queue(), ^{
[indicatorView stopAnimating]; [indicatorView stopAnimating];
[overlayView removeFromSuperview]; [overlayView removeFromSuperview];
[self processSingleImagePick:[UIImage imageWithData:imageData] [self processSingleImagePick:[UIImage imageWithData:imageData]
withExif: exif withExif: exif
withViewController:imagePickerController withViewController:imagePickerController
@ -596,16 +598,16 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
// this method will take care of attaching image metadata, and sending image to cropping controller // this method will take care of attaching image metadata, and sending image to cropping controller
// or to user directly // or to user directly
- (void) processSingleImagePick:(UIImage*)image withExif:(NSDictionary*) exif withViewController:(UIViewController*)viewController withSourceURL:(NSString*)sourceURL withLocalIdentifier:(NSString*)localIdentifier withFilename:(NSString*)filename withCreationDate:(NSDate*)creationDate withModificationDate:(NSDate*)modificationDate { - (void) processSingleImagePick:(UIImage*)image withExif:(NSDictionary*) exif withViewController:(UIViewController*)viewController withSourceURL:(NSString*)sourceURL withLocalIdentifier:(NSString*)localIdentifier withFilename:(NSString*)filename withCreationDate:(NSDate*)creationDate withModificationDate:(NSDate*)modificationDate {
if (image == nil) { if (image == nil) {
[viewController dismissViewControllerAnimated:YES completion:[self waitAnimationEnd:^{ [viewController dismissViewControllerAnimated:YES completion:[self waitAnimationEnd:^{
self.reject(ERROR_PICKER_NO_DATA_KEY, ERROR_PICKER_NO_DATA_MSG, nil); self.reject(ERROR_PICKER_NO_DATA_KEY, ERROR_PICKER_NO_DATA_MSG, nil);
}]]; }]];
return; return;
} }
NSLog(@"id: %@ filename: %@", localIdentifier, filename); NSLog(@"id: %@ filename: %@", localIdentifier, filename);
if ([[[self options] objectForKey:@"cropping"] boolValue]) { if ([[[self options] objectForKey:@"cropping"] boolValue]) {
self.croppingFile = [[NSMutableDictionary alloc] init]; self.croppingFile = [[NSMutableDictionary alloc] init];
self.croppingFile[@"sourceURL"] = sourceURL; self.croppingFile[@"sourceURL"] = sourceURL;
@ -614,7 +616,7 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
self.croppingFile[@"creationDate"] = creationDate; self.croppingFile[@"creationDate"] = creationDate;
self.croppingFile[@"modifcationDate"] = modificationDate; self.croppingFile[@"modifcationDate"] = modificationDate;
NSLog(@"CroppingFile %@", self.croppingFile); NSLog(@"CroppingFile %@", self.croppingFile);
[self startCropping:image]; [self startCropping:image];
} else { } else {
ImageResult *imageResult = [self.compression compressImage:image withOptions:self.options]; ImageResult *imageResult = [self.compression compressImage:image withOptions:self.options];
@ -625,7 +627,7 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
}]]; }]];
return; return;
} }
// Wait for viewController to dismiss before resolving, or we lose the ability to display // Wait for viewController to dismiss before resolving, or we lose the ability to display
// Alert.alert in the .then() handler. // Alert.alert in the .then() handler.
[viewController dismissViewControllerAnimated:YES completion:[self waitAnimationEnd:^{ [viewController dismissViewControllerAnimated:YES completion:[self waitAnimationEnd:^{
@ -638,9 +640,11 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
withHeight:imageResult.height withHeight:imageResult.height
withMime:imageResult.mime withMime:imageResult.mime
withSize:[NSNumber numberWithUnsignedInteger:imageResult.data.length] withSize:[NSNumber numberWithUnsignedInteger:imageResult.data.length]
withData:[[self.options objectForKey:@"includeBase64"] boolValue] ? [imageResult.data base64EncodedStringWithOptions:0] : nil withData:[[self.options objectForKey:@"includeBase64"] boolValue] ? [imageResult.data base64EncodedStringWithOptions:0] : nil
withRect:CGRectNull
withCreationDate:creationDate withCreationDate:creationDate
withModificationDate:modificationDate]); withModificationDate:modificationDate
]);
}]]; }]];
} }
} }
@ -653,14 +657,14 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
CGSize maskSize = CGSizeMake( CGSize maskSize = CGSizeMake(
[[self.options objectForKey:@"width"] intValue], [[self.options objectForKey:@"width"] intValue],
[[self.options objectForKey:@"height"] intValue]); [[self.options objectForKey:@"height"] intValue]);
CGFloat viewWidth = CGRectGetWidth(controller.view.frame); CGFloat viewWidth = CGRectGetWidth(controller.view.frame);
CGFloat viewHeight = CGRectGetHeight(controller.view.frame); CGFloat viewHeight = CGRectGetHeight(controller.view.frame);
CGRect maskRect = CGRectMake((viewWidth - maskSize.width) * 0.5f, CGRect maskRect = CGRectMake((viewWidth - maskSize.width) * 0.5f,
(viewHeight - maskSize.height) * 0.5f, (viewHeight - maskSize.height) * 0.5f,
maskSize.width, maskSize.height); maskSize.width, maskSize.height);
return maskRect; return maskRect;
} }
@ -670,13 +674,13 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
CGRect rect = controller.maskRect; CGRect rect = controller.maskRect;
CGFloat viewWidth = CGRectGetWidth(controller.view.frame); CGFloat viewWidth = CGRectGetWidth(controller.view.frame);
CGFloat viewHeight = CGRectGetHeight(controller.view.frame); CGFloat viewHeight = CGRectGetHeight(controller.view.frame);
double scaleFactor = fmin(viewWidth / rect.size.width, viewHeight / rect.size.height); double scaleFactor = fmin(viewWidth / rect.size.width, viewHeight / rect.size.height);
rect.size.width *= scaleFactor; rect.size.width *= scaleFactor;
rect.size.height *= scaleFactor; rect.size.height *= scaleFactor;
rect.origin.x = (viewWidth - rect.size.width) / 2; rect.origin.x = (viewWidth - rect.size.width) / 2;
rect.origin.y = (viewHeight - rect.size.height) / 2; rect.origin.y = (viewHeight - rect.size.height) / 2;
return rect; return rect;
} }
@ -732,13 +736,13 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
- (void)imageCropViewController:(RSKImageCropViewController *)controller - (void)imageCropViewController:(RSKImageCropViewController *)controller
didCropImage:(UIImage *)croppedImage didCropImage:(UIImage *)croppedImage
usingCropRect:(CGRect)cropRect { usingCropRect:(CGRect)cropRect {
// we have correct rect, but not correct dimensions // we have correct rect, but not correct dimensions
// so resize image // so resize image
CGSize resizedImageSize = CGSizeMake([[[self options] objectForKey:@"width"] intValue], [[[self options] objectForKey:@"height"] intValue]); CGSize resizedImageSize = CGSizeMake([[[self options] objectForKey:@"width"] intValue], [[[self options] objectForKey:@"height"] intValue]);
UIImage *resizedImage = [croppedImage resizedImageToFitInSize:resizedImageSize scaleIfSmaller:YES]; UIImage *resizedImage = [croppedImage resizedImageToFitInSize:resizedImageSize scaleIfSmaller:YES];
ImageResult *imageResult = [self.compression compressImage:resizedImage withOptions:self.options]; ImageResult *imageResult = [self.compression compressImage:resizedImage withOptions:self.options];
NSString *filePath = [self persistFile:imageResult.data]; NSString *filePath = [self persistFile:imageResult.data];
if (filePath == nil) { if (filePath == nil) {
[self dismissCropper:controller selectionDone:YES completion:[self waitAnimationEnd:^{ [self dismissCropper:controller selectionDone:YES completion:[self waitAnimationEnd:^{
@ -746,12 +750,12 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
}]]; }]];
return; return;
} }
NSDictionary* exif = nil; NSDictionary* exif = nil;
if([[self.options objectForKey:@"includeExif"] boolValue]) { if([[self.options objectForKey:@"includeExif"] boolValue]) {
exif = [[CIImage imageWithData:imageResult.data] properties]; exif = [[CIImage imageWithData:imageResult.data] properties];
} }
[self dismissCropper:controller selectionDone:YES completion:[self waitAnimationEnd:^{ [self dismissCropper:controller selectionDone:YES completion:[self waitAnimationEnd:^{
self.resolve([self createAttachmentResponse:filePath self.resolve([self createAttachmentResponse:filePath
withExif: exif withExif: exif
@ -763,8 +767,10 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
withMime:imageResult.mime withMime:imageResult.mime
withSize:[NSNumber numberWithUnsignedInteger:imageResult.data.length] withSize:[NSNumber numberWithUnsignedInteger:imageResult.data.length]
withData:[[self.options objectForKey:@"includeBase64"] boolValue] ? [imageResult.data base64EncodedStringWithOptions:0] : nil withData:[[self.options objectForKey:@"includeBase64"] boolValue] ? [imageResult.data base64EncodedStringWithOptions:0] : nil
withRect:cropRect
withCreationDate:self.croppingFile[@"creationDate"] withCreationDate:self.croppingFile[@"creationDate"]
withModificationDate:self.croppingFile[@"modificationDate"]]); withModificationDate:self.croppingFile[@"modificationDate"]
]);
}]]; }]];
} }
@ -775,13 +781,13 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
NSString *tmpDirFullPath = [self getTmpDirectory]; NSString *tmpDirFullPath = [self getTmpDirectory];
NSString *filePath = [tmpDirFullPath stringByAppendingString:[[NSUUID UUID] UUIDString]]; NSString *filePath = [tmpDirFullPath stringByAppendingString:[[NSUUID UUID] UUIDString]];
filePath = [filePath stringByAppendingString:@".jpg"]; filePath = [filePath stringByAppendingString:@".jpg"];
// save cropped file // save cropped file
BOOL status = [data writeToFile:filePath atomically:YES]; BOOL status = [data writeToFile:filePath atomically:YES];
if (!status) { if (!status) {
return nil; return nil;
} }
return filePath; return filePath;
} }
@ -794,4 +800,15 @@ RCT_EXPORT_METHOD(openCropper:(NSDictionary *)options
[self imageCropViewController:controller didCropImage:croppedImage usingCropRect:cropRect]; [self imageCropViewController:controller didCropImage:croppedImage usingCropRect:cropRect];
} }
@end
+ (NSDictionary *)cgRectToDictionary:(CGRect)rect {
return @{
@"x": [NSNumber numberWithFloat: rect.origin.x],
@"y": [NSNumber numberWithFloat: rect.origin.y],
@"width": [NSNumber numberWithFloat: CGRectGetWidth(rect)],
@"height": [NSNumber numberWithFloat: CGRectGetHeight(rect)]
};
}
@end