From 3900d47c4e7c8b196492fc7f8a1ef584837a7dac Mon Sep 17 00:00:00 2001 From: EddyVerbruggen Date: Thu, 29 Oct 2015 22:04:55 +0100 Subject: [PATCH] #2 Support for iCloud photos on iOS - modifications --- demo/index.html | 53 ++++ plugin.xml | 25 +- .../src/MultiImageChooserActivity.java | 72 +++--- src/ios/GMImagePicker/GMGridViewCell.m | 2 +- src/ios/GMImagePicker/GMGridViewController.m | 3 +- src/ios/SOSPicker.m | 243 ++++++++++-------- www/imagepicker.js | 4 +- 7 files changed, 245 insertions(+), 157 deletions(-) diff --git a/demo/index.html b/demo/index.html index e69de29..39d1f2c 100644 --- a/demo/index.html +++ b/demo/index.html @@ -0,0 +1,53 @@ + + + + + + + + ImagePicker demo + + +
+

ImagePicker demo

+ + +
+ + + + +
+
+ + + \ No newline at end of file diff --git a/plugin.xml b/plugin.xml index 36ac9f0..a0f941c 100644 --- a/plugin.xml +++ b/plugin.xml @@ -13,7 +13,7 @@ MIT - + @@ -31,8 +31,8 @@ - - + + @@ -76,6 +76,9 @@ + + @@ -187,11 +190,11 @@ - - - - - + + + + + @@ -217,8 +220,7 @@ - - + @@ -248,8 +250,5 @@ - - - diff --git a/src/android/Library/src/MultiImageChooserActivity.java b/src/android/Library/src/MultiImageChooserActivity.java index be98b34..c275422 100644 --- a/src/android/Library/src/MultiImageChooserActivity.java +++ b/src/android/Library/src/MultiImageChooserActivity.java @@ -64,7 +64,6 @@ import android.os.AsyncTask; import android.os.Bundle; import android.provider.MediaStore; import android.util.Base64; -import android.util.Log; import android.util.SparseBooleanArray; import android.view.Display; import android.view.LayoutInflater; @@ -105,7 +104,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi private int maxImages; private int maxImageCount; - + private int desiredWidth; private int desiredHeight; private int quality; @@ -117,9 +116,9 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi private int selectedColor = 0xff32b2e1; private boolean shouldRequestThumb = true; - + private FakeR fakeR; - + private ProgressDialog progress; @Override @@ -138,7 +137,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi Display display = getWindowManager().getDefaultDisplay(); int width = display.getWidth(); - + colWidth = width / 4; gridView = (GridView) findViewById(fakeR.getId("id", "gridview")); @@ -181,7 +180,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi progress.setTitle("Processing Images"); progress.setMessage("This may take a few moments"); } - + @Override public void onItemClick(AdapterView arg0, View view, int position, long id) { String name = getImageName(position); @@ -197,7 +196,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi builder.setTitle("Maximum " + maxImageCount + " Photos"); builder.setMessage("You can only select " + maxImageCount + " photos at a time."); builder.setPositiveButton("OK", new DialogInterface.OnClickListener() { - public void onClick(DialogInterface dialog, int which) { + public void onClick(DialogInterface dialog, int which) { dialog.cancel(); } }); @@ -290,7 +289,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi actualimagecursor = null; } } - + public void cancelClicked(View ignored) { setResult(RESULT_CANCELED); finish(); @@ -309,8 +308,8 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi new ResizeImagesTask().execute(fileNames.entrySet()); } } - - + + /********************* * Helper Methods ********************/ @@ -375,7 +374,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi } return name; } - + private int getImageRotation(int position) { actualimagecursor.moveToPosition(position); int rotation = 0; @@ -387,13 +386,13 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi } return rotation; } - + public boolean isChecked(int position) { boolean ret = checkStatus.get(position); return ret; } - + /********************* * Nested Classes ********************/ @@ -407,8 +406,8 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi super.onMeasure(widthMeasureSpec, widthMeasureSpec); } } - - + + private class ImageAdapter extends BaseAdapter { private final Bitmap mPlaceHolderBitmap; @@ -465,14 +464,14 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi if (android.os.Build.VERSION.SDK_INT>=16) { imageView.setImageAlpha(128); } else { - imageView.setAlpha(128); + imageView.setAlpha(128); } imageView.setBackgroundColor(selectedColor); } else { if (android.os.Build.VERSION.SDK_INT>=16) { imageView.setImageAlpha(255); } else { - imageView.setAlpha(255); + imageView.setAlpha(255); } imageView.setBackgroundColor(Color.TRANSPARENT); } @@ -483,8 +482,8 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi return imageView; } } - - + + private class ResizeImagesTask extends AsyncTask>, Void, ArrayList> { private Exception asyncTaskError = null; @@ -544,7 +543,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi if(outputType == OutputType.FILE_URI) { file = this.storeImage(bmp, file.getName()); - al.add(Uri.fromFile(file).toString()); + al.add(Uri.fromFile(file).toString()); } else if (outputType == OutputType.BASE64_STRING){ al.add(getBase64OfImage(bmp)); } @@ -558,14 +557,12 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi File file = new File(uri); file.delete(); } - } catch(Exception exception) { - // the finally does what we want to do - } finally { - return new ArrayList(); + } catch(Exception ignore) { } + return new ArrayList(); } } - + @Override protected void onPostExecute(ArrayList al) { Intent data = new Intent(); @@ -612,11 +609,11 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi } return bmp; } - + /* * The following functions are originally from * https://github.com/raananw/PhoneGap-Image-Resizer - * + * * They have been modified by Andrew Stephan for Sync OnSet * * The software is open source, MIT Licensed. @@ -637,7 +634,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi outStream.close(); return file; } - + private Bitmap getResizedBitmap(Bitmap bm, float factor) { int width = bm.getWidth(); int height = bm.getHeight(); @@ -646,35 +643,34 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi // resize the bit map matrix.postScale(factor, factor); // recreate the new Bitmap - Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); - return resizedBitmap; + return Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false); } private String getBase64OfImage(Bitmap bm) { - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - bm.compress(Bitmap.CompressFormat.JPEG, 100, byteArrayOutputStream); + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + bm.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream); byte[] byteArray = byteArrayOutputStream .toByteArray(); return Base64.encodeToString(byteArray, Base64.DEFAULT); } } - + private int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) { // Raw height and width of image final int height = options.outHeight; final int width = options.outWidth; int inSampleSize = 1; - + if (height > reqHeight || width > reqWidth) { final int halfHeight = height / 2; final int halfWidth = width / 2; - + // Calculate the largest inSampleSize value that is a power of 2 and keeps both // height and width larger than the requested height and width. while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth) { inSampleSize *= 2; } } - + return inSampleSize; } @@ -682,7 +678,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi double logBaseTwo = (int)(Math.log(sampleSize) / Math.log(2)); return (int)Math.pow(logBaseTwo + 1, 2); } - + private float calculateScale(int width, int height) { float widthScale = 1.0f; float heightScale = 1.0f; @@ -706,7 +702,7 @@ public class MultiImageChooserActivity extends Activity implements OnItemClickLi } } } - + return scale; } diff --git a/src/ios/GMImagePicker/GMGridViewCell.m b/src/ios/GMImagePicker/GMGridViewCell.m index 685af2c..7b44d88 100755 --- a/src/ios/GMImagePicker/GMGridViewCell.m +++ b/src/ios/GMImagePicker/GMGridViewCell.m @@ -140,7 +140,7 @@ static UIColor *disabledColor; _fetch.textColor = titleColor; _fetch.textAlignment = NSTextAlignmentCenter; _fetch.frame = CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height); - _fetch.text = @"fetching"; + _fetch.text = @""; // removed 'fetching' [self addSubview:_fetch]; } diff --git a/src/ios/GMImagePicker/GMGridViewController.m b/src/ios/GMImagePicker/GMGridViewController.m index 5f10e06..cc20f87 100755 --- a/src/ios/GMImagePicker/GMGridViewController.m +++ b/src/ios/GMImagePicker/GMGridViewController.m @@ -403,7 +403,8 @@ NSString * const GMGridViewCellIdentifier = @"GMGridViewCellIdentifier"; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ fetch_item.be_saving_img_thumb = false; - + + // TODO pass in quality if ( ![ UIImageJPEGRepresentation(result, 1.0f ) writeToFile:filePath atomically:YES ] ) { return; } diff --git a/src/ios/SOSPicker.m b/src/ios/SOSPicker.m index 1f017af..0f1bc01 100644 --- a/src/ios/SOSPicker.m +++ b/src/ios/SOSPicker.m @@ -7,9 +7,10 @@ // #import "SOSPicker.h" -#import "ELCAlbumPickerController.h" -#import "ELCImagePickerController.h" -#import "ELCAssetTablePicker.h" + + +#import "GMImagePickerController.h" +#import "GMFetchItem.h" #define CDV_PHOTO_PREFIX @"cdv_photo_" @@ -18,114 +19,51 @@ typedef enum : NSUInteger { BASE64_STRING = 1 } SOSPickerOutputType; -@implementation SOSPicker +@interface SOSPicker () +@end + +@implementation SOSPicker @synthesize callbackId; - (void) getPictures:(CDVInvokedUrlCommand *)command { - NSDictionary *options = [command.arguments objectAtIndex: 0]; - - NSInteger maximumImagesCount = [[options objectForKey:@"maximumImagesCount"] integerValue]; - self.width = [[options objectForKey:@"width"] integerValue]; - self.height = [[options objectForKey:@"height"] integerValue]; - self.quality = [[options objectForKey:@"quality"] integerValue]; + + NSDictionary *options = [command.arguments objectAtIndex: 0]; + self.outputType = [[options objectForKey:@"outputType"] integerValue]; + BOOL allow_video = [[options objectForKey:@"allow_video" ] boolValue ]; + NSString * title = [options objectForKey:@"title"]; + NSString * message = [options objectForKey:@"message"]; + if (message == (id)[NSNull null]) { + message = nil; + } + self.width = [[options objectForKey:@"width"] integerValue]; + self.height = [[options objectForKey:@"height"] integerValue]; + self.quality = [[options objectForKey:@"quality"] integerValue]; - // Create the an album controller and image picker - ELCAlbumPickerController *albumController = [[ELCAlbumPickerController alloc] init]; - - if (maximumImagesCount == 1) { - albumController.immediateReturn = true; - albumController.singleSelection = true; - } else { - albumController.immediateReturn = false; - albumController.singleSelection = false; - } - - ELCImagePickerController *imagePicker = [[ELCImagePickerController alloc] initWithRootViewController:albumController]; - imagePicker.maximumImagesCount = maximumImagesCount; - imagePicker.returnsOriginalImage = 1; - imagePicker.imagePickerDelegate = self; - - albumController.parent = imagePicker; - self.callbackId = command.callbackId; - // Present modally - [self.viewController presentViewController:imagePicker - animated:YES - completion:nil]; + self.callbackId = command.callbackId; + [self launchGMImagePicker:allow_video title:title message:message]; } - -- (void)elcImagePickerController:(ELCImagePickerController *)picker didFinishPickingMediaWithInfo:(NSArray *)info { - CDVPluginResult* result = nil; - NSMutableArray *resultStrings = [[NSMutableArray alloc] init]; - NSData* data = nil; - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; - NSError* err = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; - NSString* filePath; - ALAsset* asset = nil; - UIImageOrientation orientation = UIImageOrientationUp;; - CGSize targetSize = CGSizeMake(self.width, self.height); - for (NSDictionary *dict in info) { - asset = [dict objectForKey:@"ALAsset"]; - // From ELCImagePickerController.m - - int i = 1; - do { - filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, @"jpg"]; - } while ([fileMgr fileExistsAtPath:filePath]); - - @autoreleasepool { - ALAssetRepresentation *assetRep = [asset defaultRepresentation]; - CGImageRef imgRef = NULL; - - //defaultRepresentation returns image as it appears in photo picker, rotated and sized, - //so use UIImageOrientationUp when creating our image below. - if (picker.returnsOriginalImage) { - imgRef = [assetRep fullResolutionImage]; - orientation = [assetRep orientation]; - } else { - imgRef = [assetRep fullScreenImage]; - } - - UIImage* image = [UIImage imageWithCGImage:imgRef scale:1.0f orientation:orientation]; - if (self.width == 0 && self.height == 0) { - data = UIImageJPEGRepresentation(image, self.quality/100.0f); - } else { - UIImage* scaledImage = [self imageByScalingNotCroppingForSize:image toSize:targetSize]; - data = UIImageJPEGRepresentation(scaledImage, self.quality/100.0f); - } - - if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]]; - break; - } else { - if(self.outputType == BASE64_STRING){ - [resultStrings addObject:[data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]]; - } else { - [resultStrings addObject:[[NSURL fileURLWithPath:filePath] absoluteString]]; - } - } - } - - } - - if (nil == result) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:resultStrings]; - } - - [self.viewController dismissViewControllerAnimated:YES completion:nil]; - [self.commandDelegate sendPluginResult:result callbackId:self.callbackId]; +- (void)launchGMImagePicker:(bool)allow_video title:(NSString *)title message:(NSString *)message +{ + GMImagePickerController *picker = [[GMImagePickerController alloc] init:allow_video]; + picker.delegate = self; + picker.title = title; + picker.customNavigationBarPrompt = message; + picker.colsInPortrait = 4; + picker.colsInLandscape = 6; + picker.minimumInteritemSpacing = 2.0; + picker.modalPresentationStyle = UIModalPresentationPopover; + + UIPopoverPresentationController *popPC = picker.popoverPresentationController; + popPC.permittedArrowDirections = UIPopoverArrowDirectionAny; + popPC.sourceView = picker.view; + //popPC.sourceRect = nil; + + [self.viewController showViewController:picker sender:nil]; } -- (void)elcImagePickerControllerDidCancel:(ELCImagePickerController *)picker { - [self.viewController dismissViewControllerAnimated:YES completion:nil]; - CDVPluginResult* pluginResult = nil; - NSArray* emptyArray = [NSArray array]; - pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:emptyArray]; - [self.commandDelegate sendPluginResult:pluginResult callbackId:self.callbackId]; -} - (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize { @@ -170,4 +108,105 @@ typedef enum : NSUInteger { return newImage; } -@end + +#pragma mark - UIImagePickerControllerDelegate + + +- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info +{ + [picker.presentingViewController dismissViewControllerAnimated:YES completion:nil]; + NSLog(@"UIImagePickerController: User finished picking assets"); +} + +- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker +{ + [picker.presentingViewController dismissViewControllerAnimated:YES completion:nil]; + NSLog(@"UIImagePickerController: User pressed cancel button"); +} + +#pragma mark - GMImagePickerControllerDelegate + +- (void)assetsPickerController:(GMImagePickerController *)picker didFinishPickingAssets:(NSArray *)fetchArray +{ + [picker.presentingViewController dismissViewControllerAnimated:YES completion:nil]; + + NSLog(@"GMImagePicker: User finished picking assets. Number of selected items is: %lu", (unsigned long)fetchArray.count); + + NSMutableArray * result_all = [[NSMutableArray alloc] init]; + CGSize targetSize = CGSizeMake(self.width, self.height); + NSFileManager* fileMgr = [[NSFileManager alloc] init]; + NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; + + NSError* err = nil; + int i = 1; + NSString* filePath; + CDVPluginResult* result = nil; + + for (GMFetchItem *item in fetchArray) { + + if ( !item.image_fullsize ) { + continue; + } + + do { + filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, @"jpg"]; + } while ([fileMgr fileExistsAtPath:filePath]); + + NSData* data = nil; + if (self.width == 0 && self.height == 0) { + // no scaling required + if (self.outputType == BASE64_STRING){ + UIImage* image = [UIImage imageNamed:item.image_fullsize]; + [result_all addObject:[UIImageJPEGRepresentation(image, self.quality/100.0f) base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]]; + } else { + if (self.quality == 100) { + // no scaling, no downsampling, this is the fastest option + [result_all addObject:item.image_fullsize]; + } else { + // resample first + UIImage* image = [UIImage imageNamed:item.image_fullsize]; + data = UIImageJPEGRepresentation(image, self.quality/100.0f); + if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]]; + break; + } else { + [result_all addObject:[[NSURL fileURLWithPath:filePath] absoluteString]]; + } + } + } + } else { + // scale + UIImage* image = [UIImage imageNamed:item.image_fullsize]; + UIImage* scaledImage = [self imageByScalingNotCroppingForSize:image toSize:targetSize]; + data = UIImageJPEGRepresentation(scaledImage, self.quality/100.0f); + + if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]]; + break; + } else { + if(self.outputType == BASE64_STRING){ + [result_all addObject:[data base64EncodedStringWithOptions:NSDataBase64Encoding64CharacterLineLength]]; + } else { + [result_all addObject:[[NSURL fileURLWithPath:filePath] absoluteString]]; + } + } + } + } + + if (result == nil) { + result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsArray:result_all]; + } + + [self.viewController dismissViewControllerAnimated:YES completion:nil]; + [self.commandDelegate sendPluginResult:result callbackId:self.callbackId]; + +} + +//Optional implementation: +-(void)assetsPickerControllerDidCancel:(GMImagePickerController *)picker +{ + NSLog(@"GMImagePicker: User pressed cancel button"); +} + + +@end \ No newline at end of file diff --git a/www/imagepicker.js b/www/imagepicker.js index 1ac6053..ce7b99f 100644 --- a/www/imagepicker.js +++ b/www/imagepicker.js @@ -51,8 +51,8 @@ ImagePicker.prototype.getPictures = function(success, fail, options) { height: options.height ? options.height : 0, quality: options.quality ? options.quality : 100, allow_video: options.allow_video ? options.allow_video : false, - title: options.title ? options.title : 'Custom Title', - message: options.message ? options.message : 'Custom helper message', + title: options.title ? options.title : 'Select an Album', // the default is the message of the old plugin impl + message: options.message ? options.message : null, // the old plugin impl didn't have it, so passing null by default outputType: options.outputType ? options.outputType : this.OutputType.FILE_URI };