diff --git a/plugin.xml b/plugin.xml
index d84c44d..2844e1f 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -133,6 +133,8 @@
+
+
diff --git a/src/ios/CDVCamera.h b/src/ios/CDVCamera.h
index c2a71ac..231e9f6 100644
--- a/src/ios/CDVCamera.h
+++ b/src/ios/CDVCamera.h
@@ -42,22 +42,39 @@ enum CDVMediaType {
};
typedef NSUInteger CDVMediaType;
-@interface CDVCameraPicker : UIImagePickerController
-{}
+@interface CDVPictureOptions : NSObject
-@property (assign) NSInteger quality;
-@property (copy) NSString* callbackId;
-@property (copy) NSString* postUrl;
-@property (nonatomic) enum CDVDestinationType returnType;
-@property (nonatomic) enum CDVEncodingType encodingType;
-@property (strong) UIPopoverController* popoverController;
+@property (strong) NSNumber* quality;
+@property (assign) CDVDestinationType destinationType;
+@property (assign) UIImagePickerControllerSourceType sourceType;
@property (assign) CGSize targetSize;
-@property (assign) bool correctOrientation;
-@property (assign) bool saveToPhotoAlbum;
-@property (assign) bool cropToSize;
-@property (strong) UIView* webView;
+@property (assign) CDVEncodingType encodingType;
+@property (assign) CDVMediaType mediaType;
+@property (assign) BOOL allowsEditing;
+@property (assign) BOOL correctOrientation;
+@property (assign) BOOL saveToPhotoAlbum;
+@property (strong) NSDictionary* popoverOptions;
+@property (assign) UIImagePickerControllerCameraDevice cameraDirection;
+
@property (assign) BOOL popoverSupported;
@property (assign) BOOL usesGeolocation;
+@property (assign) BOOL cropToSize;
+
++ (instancetype) createFromTakePictureArguments:(NSArray*)arguments;
+
+@end
+
+@interface CDVCameraPicker : UIImagePickerController
+
+@property (strong) CDVPictureOptions* pictureOptions;
+
+@property (copy) NSString* callbackId;
+@property (copy) NSString* postUrl;
+@property (strong) UIPopoverController* pickerPopoverController;
+@property (assign) BOOL cropToSize;
+@property (strong) UIView* webView;
+
++ (instancetype) createFromPictureOptions:(CDVPictureOptions*)options;
@end
@@ -92,9 +109,6 @@ typedef NSUInteger CDVMediaType;
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo;
- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker;
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
-- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize;
-- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize;
-- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage;
- (void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation;
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error;
diff --git a/src/ios/CDVCamera.m b/src/ios/CDVCamera.m
index 301187a..857c9b1 100644
--- a/src/ios/CDVCamera.m
+++ b/src/ios/CDVCamera.m
@@ -19,6 +19,7 @@
#import "CDVCamera.h"
#import "CDVJpegHeaderWriter.h"
+#import "UIImage+CropScaleOrientation.h"
#import
#import
#import
@@ -34,6 +35,40 @@
static NSSet* org_apache_cordova_validArrowDirections;
+@implementation CDVPictureOptions
+
++ (instancetype) createFromTakePictureArguments:(NSArray*)arguments
+{
+ CDVPictureOptions* pictureOptions = [[CDVPictureOptions alloc] init];
+
+ pictureOptions.quality = [arguments objectAtIndex:0 withDefault:@(50)];
+ pictureOptions.destinationType = [[arguments objectAtIndex:1 withDefault:@(DestinationTypeFileUri)] unsignedIntegerValue];
+ pictureOptions.sourceType = [[arguments objectAtIndex:2 withDefault:@(UIImagePickerControllerSourceTypeCamera)] unsignedIntegerValue];
+
+ NSNumber* targetWidth = [arguments objectAtIndex:3 withDefault:nil];
+ NSNumber* targetHeight = [arguments objectAtIndex:4 withDefault:nil];
+ pictureOptions.targetSize = CGSizeMake(0, 0);
+ if ((targetWidth != nil) && (targetHeight != nil)) {
+ pictureOptions.targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]);
+ }
+
+ pictureOptions.encodingType = [[arguments objectAtIndex:5 withDefault:@(EncodingTypeJPEG)] unsignedIntegerValue];
+ pictureOptions.mediaType = [[arguments objectAtIndex:6 withDefault:@(MediaTypePicture)] unsignedIntegerValue];
+ pictureOptions.allowsEditing = [[arguments objectAtIndex:7 withDefault:@(NO)] boolValue];
+ pictureOptions.correctOrientation = [[arguments objectAtIndex:8 withDefault:@(NO)] boolValue];
+ pictureOptions.saveToPhotoAlbum = [[arguments objectAtIndex:9 withDefault:@(NO)] boolValue];
+ pictureOptions.popoverOptions = [arguments objectAtIndex:10 withDefault:nil];
+ pictureOptions.cameraDirection = [[arguments objectAtIndex:11 withDefault:@(UIImagePickerControllerCameraDeviceRear)] unsignedIntegerValue];
+
+ pictureOptions.popoverSupported = NO;
+ pictureOptions.usesGeolocation = NO;
+
+ return pictureOptions;
+}
+
+@end
+
+
@interface CDVCamera ()
@property (readwrite, assign) BOOL hasPendingOperation;
@@ -49,7 +84,6 @@ static NSSet* org_apache_cordova_validArrowDirections;
@synthesize hasPendingOperation, pickerController, locationManager;
-
- (BOOL)usesGeolocation
{
id useGeo = [self.commandDelegate.settings objectForKey:[@"CameraUsesGeolocation" lowercaseString]];
@@ -62,106 +96,55 @@ static NSSet* org_apache_cordova_validArrowDirections;
(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
}
-/* takePicture arguments:
- * INDEX ARGUMENT
- * 0 quality
- * 1 destination type
- * 2 source type
- * 3 targetWidth
- * 4 targetHeight
- * 5 encodingType
- * 6 mediaType
- * 7 allowsEdit
- * 8 correctOrientation
- * 9 saveToPhotoAlbum
- * 10 popoverOptions
- * 11 cameraDirection
- */
- (void)takePicture:(CDVInvokedUrlCommand*)command
{
- NSString* callbackId = command.callbackId;
- NSArray* arguments = command.arguments;
-
self.hasPendingOperation = YES;
+
+ __weak CDVCamera* weakSelf = self;
- NSString* sourceTypeString = [arguments objectAtIndex:2];
- UIImagePickerControllerSourceType sourceType = UIImagePickerControllerSourceTypeCamera; // default
- if (sourceTypeString != nil) {
- sourceType = (UIImagePickerControllerSourceType)[sourceTypeString intValue];
- }
-
- bool hasCamera = [UIImagePickerController isSourceTypeAvailable:sourceType];
- if (!hasCamera) {
- NSLog(@"Camera.getPicture: source type %lu not available.", (unsigned long)sourceType);
- CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no camera available"];
- [self.commandDelegate sendPluginResult:result callbackId:callbackId];
- return;
- }
-
- bool allowEdit = [[arguments objectAtIndex:7] boolValue];
- NSNumber* targetWidth = [arguments objectAtIndex:3];
- NSNumber* targetHeight = [arguments objectAtIndex:4];
- NSNumber* mediaValue = [arguments objectAtIndex:6];
- CDVMediaType mediaType = (mediaValue) ? [mediaValue intValue] : MediaTypePicture;
-
- CGSize targetSize = CGSizeMake(0, 0);
- if ((targetWidth != nil) && (targetHeight != nil)) {
- targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]);
- }
-
- // If a popover is already open, close it; we only want one at a time.
- if (([[self pickerController] popoverController] != nil) && [[[self pickerController] popoverController] isPopoverVisible]) {
- [[[self pickerController] popoverController] dismissPopoverAnimated:YES];
- [[[self pickerController] popoverController] setDelegate:nil];
- [[self pickerController] setPopoverController:nil];
- }
-
- CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init];
- self.pickerController = cameraPicker;
-
- cameraPicker.delegate = self;
- cameraPicker.sourceType = sourceType;
- cameraPicker.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm
- cameraPicker.callbackId = callbackId;
- cameraPicker.targetSize = targetSize;
- cameraPicker.cropToSize = NO;
- // we need to capture this state for memory warnings that dealloc this object
- cameraPicker.webView = self.webView;
- cameraPicker.popoverSupported = [self popoverSupported];
- cameraPicker.usesGeolocation = [self usesGeolocation];
-
- cameraPicker.correctOrientation = [[arguments objectAtIndex:8] boolValue];
- cameraPicker.saveToPhotoAlbum = [[arguments objectAtIndex:9] boolValue];
-
- cameraPicker.encodingType = ([arguments objectAtIndex:5]) ? [[arguments objectAtIndex:5] intValue] : EncodingTypeJPEG;
-
- cameraPicker.quality = ([arguments objectAtIndex:0]) ? [[arguments objectAtIndex:0] intValue] : 50;
- cameraPicker.returnType = ([arguments objectAtIndex:1]) ? [[arguments objectAtIndex:1] intValue] : DestinationTypeFileUri;
-
- if (sourceType == UIImagePickerControllerSourceTypeCamera) {
- // We only allow taking pictures (no video) in this API.
- cameraPicker.mediaTypes = [NSArray arrayWithObjects:(NSString*)kUTTypeImage, nil];
-
- // We can only set the camera device if we're actually using the camera.
- NSNumber* cameraDirection = [command argumentAtIndex:11 withDefault:[NSNumber numberWithInteger:UIImagePickerControllerCameraDeviceRear]];
- cameraPicker.cameraDevice = (UIImagePickerControllerCameraDevice)[cameraDirection intValue];
- } else if (mediaType == MediaTypeAll) {
- cameraPicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:sourceType];
- } else {
- NSArray* mediaArray = [NSArray arrayWithObjects:(NSString*)(mediaType == MediaTypeVideo ? kUTTypeMovie : kUTTypeImage), nil];
- cameraPicker.mediaTypes = mediaArray;
- }
-
- if ([self popoverSupported] && (sourceType != UIImagePickerControllerSourceTypeCamera)) {
- if (cameraPicker.popoverController == nil) {
- cameraPicker.popoverController = [[NSClassFromString(@"UIPopoverController")alloc] initWithContentViewController:cameraPicker];
+ [self.commandDelegate runInBackground:^{
+
+ CDVPictureOptions* pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command.arguments];
+ pictureOptions.popoverSupported = [self popoverSupported];
+ pictureOptions.usesGeolocation = [self usesGeolocation];
+ pictureOptions.cropToSize = NO;
+
+ BOOL hasCamera = [UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType];
+ if (!hasCamera) {
+ NSLog(@"Camera.getPicture: source type %lu not available.", (unsigned long)pictureOptions.sourceType);
+ CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"No camera available"];
+ [weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId];
+ return;
}
- NSDictionary* options = [command.arguments objectAtIndex:10 withDefault:nil];
- [self displayPopover:options];
- } else {
- [self.viewController presentViewController:cameraPicker animated:YES completion:nil];
- }
- self.hasPendingOperation = NO;
+
+ // If a popover is already open, close it; we only want one at a time.
+ if (([[weakSelf pickerController] pickerPopoverController] != nil) && [[[weakSelf pickerController] pickerPopoverController] isPopoverVisible]) {
+ [[[weakSelf pickerController] pickerPopoverController] dismissPopoverAnimated:YES];
+ [[[weakSelf pickerController] pickerPopoverController] setDelegate:nil];
+ [[weakSelf pickerController] setPickerPopoverController:nil];
+ }
+
+ CDVCameraPicker* cameraPicker = [CDVCameraPicker createFromPictureOptions:pictureOptions];
+ weakSelf.pickerController = cameraPicker;
+
+ cameraPicker.delegate = weakSelf;
+ cameraPicker.callbackId = command.callbackId;
+ // we need to capture this state for memory warnings that dealloc this object
+ cameraPicker.webView = weakSelf.webView;
+
+ if ([weakSelf popoverSupported] && (pictureOptions.sourceType != UIImagePickerControllerSourceTypeCamera)) {
+ if (cameraPicker.pickerPopoverController == nil) {
+ cameraPicker.pickerPopoverController = [[NSClassFromString(@"UIPopoverController") alloc] initWithContentViewController:cameraPicker];
+ }
+ [weakSelf displayPopover:pictureOptions.popoverOptions];
+ weakSelf.hasPendingOperation = NO;
+
+ } else {
+ [weakSelf.viewController presentViewController:cameraPicker animated:YES completion:^{
+ weakSelf.hasPendingOperation = NO;
+ }];
+ }
+ }];
}
- (void)repositionPopover:(CDVInvokedUrlCommand*)command
@@ -190,8 +173,8 @@ static NSSet* org_apache_cordova_validArrowDirections;
}
}
- [[[self pickerController] popoverController] setDelegate:self];
- [[[self pickerController] popoverController] presentPopoverFromRect:CGRectMake(x, y, width, height)
+ [[[self pickerController] pickerPopoverController] setDelegate:self];
+ [[[self pickerController] pickerPopoverController] presentPopoverFromRect:CGRectMake(x, y, width, height)
inView:[self.webView superview]
permittedArrowDirections:arrowDirection
animated:YES];
@@ -200,9 +183,9 @@ static NSSet* org_apache_cordova_validArrowDirections;
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if([navigationController isKindOfClass:[UIImagePickerController class]]){
- UIImagePickerController * cameraPicker = (UIImagePickerController*)navigationController;
+ UIImagePickerController* cameraPicker = (UIImagePickerController*)navigationController;
- if(![cameraPicker.mediaTypes containsObject:(NSString*) kUTTypeImage]){
+ if(![cameraPicker.mediaTypes containsObject:(NSString*)kUTTypeImage]){
[viewController.navigationItem setTitle:NSLocalizedString(@"Videos title", nil)];
}
}
@@ -245,13 +228,12 @@ static NSSet* org_apache_cordova_validArrowDirections;
- (void)popoverControllerDidDismissPopover:(id)popoverController
{
- // [ self imagePickerControllerDidCancel:self.pickerController ]; '
UIPopoverController* pc = (UIPopoverController*)popoverController;
[pc dismissPopoverAnimated:YES];
pc.delegate = nil;
- if (self.pickerController && self.pickerController.callbackId && self.pickerController.popoverController) {
- self.pickerController.popoverController = nil;
+ if (self.pickerController && self.pickerController.callbackId && self.pickerController.pickerPopoverController) {
+ self.pickerController.pickerPopoverController = nil;
NSString* callbackId = self.pickerController.callbackId;
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"]; // error callback expects string ATM
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
@@ -259,122 +241,184 @@ static NSSet* org_apache_cordova_validArrowDirections;
self.hasPendingOperation = NO;
}
-- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
+- (NSData*)processImage:(UIImage*)image info:(NSDictionary*)info options:(CDVPictureOptions*)options
{
- CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
-
- if (cameraPicker.popoverSupported && (cameraPicker.popoverController != nil)) {
- [cameraPicker.popoverController dismissPopoverAnimated:YES];
- cameraPicker.popoverController.delegate = nil;
- cameraPicker.popoverController = nil;
- } else {
- [[cameraPicker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
- }
-
- CDVPluginResult* result = nil;
-
- NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
- // IMAGE TYPE
- if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
- if (cameraPicker.returnType == DestinationTypeNativeUri) {
- NSString* nativeUri = [(NSURL*)[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri];
- } else {
- // get the image
- UIImage* image = nil;
- if (cameraPicker.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) {
- image = [info objectForKey:UIImagePickerControllerEditedImage];
- } else {
- image = [info objectForKey:UIImagePickerControllerOriginalImage];
- }
-
- if (cameraPicker.correctOrientation) {
- image = [self imageCorrectedForCaptureOrientation:image];
- }
-
- UIImage* scaledImage = nil;
-
- if ((cameraPicker.targetSize.width > 0) && (cameraPicker.targetSize.height > 0)) {
- // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
- if (cameraPicker.cropToSize) {
- scaledImage = [self imageByScalingAndCroppingForSize:image toSize:cameraPicker.targetSize];
- } else {
- scaledImage = [self imageByScalingNotCroppingForSize:image toSize:cameraPicker.targetSize];
- }
- }
-
- NSData* data = nil;
- // returnedImage is the image that is returned to caller and (optionally) saved to photo album
- UIImage* returnedImage = (scaledImage == nil ? image : scaledImage);
-
- if (cameraPicker.encodingType == EncodingTypePNG) {
- data = UIImagePNGRepresentation(returnedImage);
- } else if ((cameraPicker.allowsEditing==false) && (cameraPicker.targetSize.width <= 0) && (cameraPicker.targetSize.height <= 0) && (cameraPicker.correctOrientation==false)){
+ NSData* data = nil;
+
+ switch (options.encodingType) {
+ case EncodingTypePNG:
+ data = UIImagePNGRepresentation(image);
+ break;
+ case EncodingTypeJPEG:
+ {
+ if ((options.allowsEditing == NO) && (options.targetSize.width <= 0) && (options.targetSize.height <= 0) && (options.correctOrientation == NO)){
// use image unedited as requested , don't resize
- data = UIImageJPEGRepresentation(returnedImage, 1.0);
+ data = UIImageJPEGRepresentation(image, 1.0);
} else {
- data = UIImageJPEGRepresentation(returnedImage, cameraPicker.quality / 100.0f);
-
- if (cameraPicker.usesGeolocation) {
- NSDictionary *controllerMetadata = [info objectForKey:@"UIImagePickerControllerMediaMetadata"];
+ if (options.usesGeolocation) {
+ NSDictionary* controllerMetadata = [info objectForKey:@"UIImagePickerControllerMediaMetadata"];
if (controllerMetadata) {
self.data = data;
self.metadata = [[NSMutableDictionary alloc] init];
- NSMutableDictionary *EXIFDictionary = [[controllerMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy];
- if (EXIFDictionary) [self.metadata setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary];
+ NSMutableDictionary* EXIFDictionary = [[controllerMetadata objectForKey:(NSString*)kCGImagePropertyExifDictionary]mutableCopy];
+ if (EXIFDictionary) {
+ [self.metadata setObject:EXIFDictionary forKey:(NSString*)kCGImagePropertyExifDictionary];
+ }
if (IsAtLeastiOSVersion(@"8.0")) {
[[self locationManager] performSelector:NSSelectorFromString(@"requestWhenInUseAuthorization") withObject:nil afterDelay:0];
}
[[self locationManager] startUpdatingLocation];
- return;
}
+ } else {
+ data = UIImageJPEGRepresentation(image, [options.quality floatValue] / 100.0f);
}
}
-
- if (cameraPicker.saveToPhotoAlbum) {
- ALAssetsLibrary *library = [ALAssetsLibrary new];
- [library writeImageToSavedPhotosAlbum:returnedImage.CGImage orientation:(ALAssetOrientation)(returnedImage.imageOrientation) completionBlock:nil];
- }
+ }
+ break;
+ default:
+ break;
+ };
+
+ return data;
+}
- if (cameraPicker.returnType == DestinationTypeFileUri) {
- // write to temp directory and return URI
- // get the temp directory path
- NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
+- (NSString*)tempFilePath:(NSString*)extension
+{
+ NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
+ NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by Apple (vs [NSFileManager defaultManager]) to be threadsafe
+ NSString* filePath;
+
+ // generate unique file name
+ int i = 1;
+ do {
+ filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, extension];
+ } while ([fileMgr fileExistsAtPath:filePath]);
+
+ return filePath;
+}
+
+- (UIImage*)retrieveImage:(NSDictionary*)info options:(CDVPictureOptions*)options
+{
+ // get the image
+ UIImage* image = nil;
+ if (options.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) {
+ image = [info objectForKey:UIImagePickerControllerEditedImage];
+ } else {
+ image = [info objectForKey:UIImagePickerControllerOriginalImage];
+ }
+
+ if (options.correctOrientation) {
+ image = [image imageCorrectedForCaptureOrientation];
+ }
+
+ UIImage* scaledImage = nil;
+
+ if ((options.targetSize.width > 0) && (options.targetSize.height > 0)) {
+ // if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
+ if (options.cropToSize) {
+ scaledImage = [image imageByScalingAndCroppingForSize:options.targetSize];
+ } else {
+ scaledImage = [image imageByScalingNotCroppingForSize:options.targetSize];
+ }
+ }
+
+ return (scaledImage == nil ? image : scaledImage);
+}
+
+- (CDVPluginResult*)resultForImage:(CDVPictureOptions*)options info:(NSDictionary*)info
+{
+ CDVPluginResult* result = nil;
+ BOOL saveToPhotoAlbum = options.saveToPhotoAlbum;
+ UIImage* image = nil;
+
+ switch (options.destinationType) {
+ case DestinationTypeNativeUri:
+ {
+ NSString* nativeUri = [(NSURL*)[info objectForKey:UIImagePickerControllerReferenceURL] absoluteString];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri];
+ saveToPhotoAlbum = NO;
+ }
+ break;
+ case DestinationTypeFileUri:
+ {
+ image = [self retrieveImage:info options:options];
+ NSData* data = [self processImage:image info:info options:options];
+ if (data) {
+
+ NSString* extension = options.encodingType == EncodingTypePNG? @"png" : @"jpg";
+ NSString* filePath = [self tempFilePath:extension];
NSError* err = nil;
- NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe
- // generate unique file name
- NSString* filePath;
-
- int i = 1;
- do {
- filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, cameraPicker.encodingType == EncodingTypePNG ? @"png":@"jpg"];
- } while ([fileMgr fileExistsAtPath:filePath]);
-
+
// save file
if (![data writeToFile:filePath options:NSAtomicWrite error:&err]) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
} else {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]];
}
- } else {
+ }
+ }
+ break;
+ case DestinationTypeDataUrl:
+ {
+ image = [self retrieveImage:info options:options];
+ NSData* data = [self processImage:image info:info options:options];
+
+ if (data) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[data base64EncodedString]];
}
}
+ break;
+ default:
+ break;
+ };
+
+ if (saveToPhotoAlbum && image) {
+ ALAssetsLibrary* library = [ALAssetsLibrary new];
+ [library writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)(image.imageOrientation) completionBlock:nil];
}
- // NOT IMAGE TYPE (MOVIE)
- else {
- NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:moviePath];
- }
+
+ return result;
+}
- if (result) {
- [self.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId];
- }
+- (CDVPluginResult*)resultForVideo:(NSDictionary*)info
+{
+ NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
+ return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:moviePath];
+}
- self.hasPendingOperation = NO;
- self.pickerController = nil;
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
+{
+ __weak CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
+ __weak CDVCamera* weakSelf = self;
+
+ dispatch_block_t invoke = ^(void) {
+ __block CDVPluginResult* result = nil;
+
+ NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
+ if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
+ result = [self resultForImage:cameraPicker.pictureOptions info:info];
+ }
+ else {
+ result = [self resultForVideo:info];
+ }
+
+ if (result) {
+ [weakSelf.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId];
+ weakSelf.hasPendingOperation = NO;
+ weakSelf.pickerController = nil;
+ }
+ };
+
+ if (cameraPicker.pictureOptions.popoverSupported && (cameraPicker.pickerPopoverController != nil)) {
+ [cameraPicker.pickerPopoverController dismissPopoverAnimated:YES];
+ cameraPicker.pickerPopoverController.delegate = nil;
+ cameraPicker.pickerPopoverController = nil;
+ invoke();
+ } else {
+ [[cameraPicker presentingViewController] dismissViewControllerAnimated:YES completion:invoke];
+ }
}
// older api calls newer didFinishPickingMediaWithInfo
@@ -387,171 +431,28 @@ static NSSet* org_apache_cordova_validArrowDirections;
- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker
{
- CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
-
- [[cameraPicker presentingViewController] dismissViewControllerAnimated:YES completion:nil];
-
- CDVPluginResult* result;
- if ([ALAssetsLibrary authorizationStatus] == ALAuthorizationStatusAuthorized) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"]; // error callback expects string ATM
- } else {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"has no access to assets"]; // error callback expects string ATM
- }
+ __weak CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
+ __weak CDVCamera* weakSelf = self;
- [self.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId];
-
- self.hasPendingOperation = NO;
- self.pickerController = nil;
-}
-
-- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize
-{
- UIImage* sourceImage = anImage;
- UIImage* newImage = nil;
- CGSize imageSize = sourceImage.size;
- CGFloat width = imageSize.width;
- CGFloat height = imageSize.height;
- CGFloat targetWidth = targetSize.width;
- CGFloat targetHeight = targetSize.height;
- CGFloat scaleFactor = 0.0;
- CGFloat scaledWidth = targetWidth;
- CGFloat scaledHeight = targetHeight;
- CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
-
- if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
- CGFloat widthFactor = targetWidth / width;
- CGFloat heightFactor = targetHeight / height;
-
- if (widthFactor > heightFactor) {
- scaleFactor = widthFactor; // scale to fit height
+ dispatch_block_t invoke = ^ (void) {
+ CDVPluginResult* result;
+ if ([ALAssetsLibrary authorizationStatus] == ALAuthorizationStatusAuthorized) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"];
} else {
- scaleFactor = heightFactor; // scale to fit width
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"has no access to assets"];
}
- scaledWidth = width * scaleFactor;
- scaledHeight = height * scaleFactor;
+
+ [weakSelf.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId];
+
+ weakSelf.hasPendingOperation = NO;
+ weakSelf.pickerController = nil;
+ };
- // center the image
- if (widthFactor > heightFactor) {
- thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
- } else if (widthFactor < heightFactor) {
- thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
- }
- }
-
- UIGraphicsBeginImageContext(targetSize); // this will crop
-
- CGRect thumbnailRect = CGRectZero;
- thumbnailRect.origin = thumbnailPoint;
- thumbnailRect.size.width = scaledWidth;
- thumbnailRect.size.height = scaledHeight;
-
- [sourceImage drawInRect:thumbnailRect];
-
- newImage = UIGraphicsGetImageFromCurrentImageContext();
- if (newImage == nil) {
- NSLog(@"could not scale image");
- }
-
- // pop the context to get back to the default
- UIGraphicsEndImageContext();
- return newImage;
+ [[cameraPicker presentingViewController] dismissViewControllerAnimated:YES completion:invoke];
}
-- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage
+- (CLLocationManager*)locationManager
{
- float rotation_radians = 0;
- bool perpendicular = false;
-
- switch ([anImage imageOrientation]) {
- case UIImageOrientationUp :
- rotation_radians = 0.0;
- break;
-
- case UIImageOrientationDown:
- rotation_radians = M_PI; // don't be scared of radians, if you're reading this, you're good at math
- break;
-
- case UIImageOrientationRight:
- rotation_radians = M_PI_2;
- perpendicular = true;
- break;
-
- case UIImageOrientationLeft:
- rotation_radians = -M_PI_2;
- perpendicular = true;
- break;
-
- default:
- break;
- }
-
- UIGraphicsBeginImageContext(CGSizeMake(anImage.size.width, anImage.size.height));
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- // Rotate around the center point
- CGContextTranslateCTM(context, anImage.size.width / 2, anImage.size.height / 2);
- CGContextRotateCTM(context, rotation_radians);
-
- CGContextScaleCTM(context, 1.0, -1.0);
- float width = perpendicular ? anImage.size.height : anImage.size.width;
- float height = perpendicular ? anImage.size.width : anImage.size.height;
- CGContextDrawImage(context, CGRectMake(-width / 2, -height / 2, width, height), [anImage CGImage]);
-
- // Move the origin back since the rotation might've change it (if its 90 degrees)
- if (perpendicular) {
- CGContextTranslateCTM(context, -anImage.size.height / 2, -anImage.size.width / 2);
- }
-
- UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
- UIGraphicsEndImageContext();
- return newImage;
-}
-
-- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize
-{
- UIImage* sourceImage = anImage;
- UIImage* newImage = nil;
- CGSize imageSize = sourceImage.size;
- CGFloat width = imageSize.width;
- CGFloat height = imageSize.height;
- CGFloat targetWidth = frameSize.width;
- CGFloat targetHeight = frameSize.height;
- CGFloat scaleFactor = 0.0;
- CGSize scaledSize = frameSize;
-
- if (CGSizeEqualToSize(imageSize, frameSize) == NO) {
- CGFloat widthFactor = targetWidth / width;
- CGFloat heightFactor = targetHeight / height;
-
- // opposite comparison to imageByScalingAndCroppingForSize in order to contain the image within the given bounds
- if (widthFactor > heightFactor) {
- scaleFactor = heightFactor; // scale to fit height
- } else {
- scaleFactor = widthFactor; // scale to fit width
- }
- scaledSize = CGSizeMake(MIN(width * scaleFactor, targetWidth), MIN(height * scaleFactor, targetHeight));
- }
-
- // If the pixels are floats, it causes a white line in iOS8 and probably other versions too
- scaledSize.width = (int)scaledSize.width;
- scaledSize.height = (int)scaledSize.height;
-
- UIGraphicsBeginImageContext(scaledSize); // this will resize
-
- [sourceImage drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)];
-
- newImage = UIGraphicsGetImageFromCurrentImageContext();
- if (newImage == nil) {
- NSLog(@"could not scale image");
- }
-
- // pop the context to get back to the default
- UIGraphicsEndImageContext();
- return newImage;
-}
-
-- (CLLocationManager *)locationManager {
-
if (locationManager != nil) {
return locationManager;
}
@@ -565,70 +466,76 @@ static NSSet* org_apache_cordova_validArrowDirections;
- (void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation
{
- if (locationManager != nil) {
- [self.locationManager stopUpdatingLocation];
- self.locationManager = nil;
-
- NSMutableDictionary *GPSDictionary = [[NSMutableDictionary dictionary] init];
-
- CLLocationDegrees latitude = newLocation.coordinate.latitude;
- CLLocationDegrees longitude = newLocation.coordinate.longitude;
-
- // latitude
- if (latitude < 0.0) {
- latitude = latitude * -1.0f;
- [GPSDictionary setObject:@"S" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
- } else {
- [GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
- }
- [GPSDictionary setObject:[NSNumber numberWithFloat:latitude] forKey:(NSString*)kCGImagePropertyGPSLatitude];
-
- // longitude
- if (longitude < 0.0) {
- longitude = longitude * -1.0f;
- [GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
- }
- else {
- [GPSDictionary setObject:@"E" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
- }
- [GPSDictionary setObject:[NSNumber numberWithFloat:longitude] forKey:(NSString*)kCGImagePropertyGPSLongitude];
-
- // altitude
- CGFloat altitude = newLocation.altitude;
- if (!isnan(altitude)){
- if (altitude < 0) {
- altitude = -altitude;
- [GPSDictionary setObject:@"1" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef];
- } else {
- [GPSDictionary setObject:@"0" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef];
- }
- [GPSDictionary setObject:[NSNumber numberWithFloat:altitude] forKey:(NSString *)kCGImagePropertyGPSAltitude];
+ if (locationManager == nil) {
+ return;
+ }
+
+ [self.locationManager stopUpdatingLocation];
+ self.locationManager = nil;
+
+ NSMutableDictionary *GPSDictionary = [[NSMutableDictionary dictionary] init];
+
+ CLLocationDegrees latitude = newLocation.coordinate.latitude;
+ CLLocationDegrees longitude = newLocation.coordinate.longitude;
+
+ // latitude
+ if (latitude < 0.0) {
+ latitude = latitude * -1.0f;
+ [GPSDictionary setObject:@"S" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
+ } else {
+ [GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
+ }
+ [GPSDictionary setObject:[NSNumber numberWithFloat:latitude] forKey:(NSString*)kCGImagePropertyGPSLatitude];
+
+ // longitude
+ if (longitude < 0.0) {
+ longitude = longitude * -1.0f;
+ [GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
+ }
+ else {
+ [GPSDictionary setObject:@"E" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
+ }
+ [GPSDictionary setObject:[NSNumber numberWithFloat:longitude] forKey:(NSString*)kCGImagePropertyGPSLongitude];
+
+ // altitude
+ CGFloat altitude = newLocation.altitude;
+ if (!isnan(altitude)){
+ if (altitude < 0) {
+ altitude = -altitude;
+ [GPSDictionary setObject:@"1" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef];
+ } else {
+ [GPSDictionary setObject:@"0" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef];
}
-
- // Time and date
- NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
- [formatter setDateFormat:@"HH:mm:ss.SSSSSS"];
- [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
- [GPSDictionary setObject:[formatter stringFromDate:newLocation.timestamp] forKey:(NSString *)kCGImagePropertyGPSTimeStamp];
- [formatter setDateFormat:@"yyyy:MM:dd"];
- [GPSDictionary setObject:[formatter stringFromDate:newLocation.timestamp] forKey:(NSString *)kCGImagePropertyGPSDateStamp];
-
- [self.metadata setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
- [self imagePickerControllerReturnImageResult];
- }
+ [GPSDictionary setObject:[NSNumber numberWithFloat:altitude] forKey:(NSString *)kCGImagePropertyGPSAltitude];
+ }
+
+ // Time and date
+ NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
+ [formatter setDateFormat:@"HH:mm:ss.SSSSSS"];
+ [formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
+ [GPSDictionary setObject:[formatter stringFromDate:newLocation.timestamp] forKey:(NSString *)kCGImagePropertyGPSTimeStamp];
+ [formatter setDateFormat:@"yyyy:MM:dd"];
+ [GPSDictionary setObject:[formatter stringFromDate:newLocation.timestamp] forKey:(NSString *)kCGImagePropertyGPSDateStamp];
+
+ [self.metadata setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
+ [self imagePickerControllerReturnImageResult];
}
-- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error {
- if (locationManager != nil) {
- [self.locationManager stopUpdatingLocation];
- self.locationManager = nil;
-
- [self imagePickerControllerReturnImageResult];
- }
+- (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error
+{
+ if (locationManager == nil) {
+ return;
+ }
+
+ [self.locationManager stopUpdatingLocation];
+ self.locationManager = nil;
+
+ [self imagePickerControllerReturnImageResult];
}
- (void)imagePickerControllerReturnImageResult
{
+ CDVPictureOptions* options = self.pickerController.pictureOptions;
CDVPluginResult* result = nil;
if (self.metadata) {
@@ -643,39 +550,31 @@ static NSSet* org_apache_cordova_validArrowDirections;
CFRelease(destinationImage);
}
- if (self.pickerController.saveToPhotoAlbum) {
- ALAssetsLibrary *library = [ALAssetsLibrary new];
- [library writeImageDataToSavedPhotosAlbum:self.data metadata:self.metadata completionBlock:nil];
- }
-
- if (self.pickerController.returnType == DestinationTypeFileUri) {
- // write to temp directory and return URI
- // get the temp directory path
- NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
- NSError* err = nil;
- NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe
- // generate unique file name
- NSString* filePath;
-
- int i = 1;
- do {
- filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, self.pickerController.encodingType == EncodingTypePNG ? @"png":@"jpg"];
- } while ([fileMgr fileExistsAtPath:filePath]);
-
- // save file
- if (![self.data writeToFile:filePath options:NSAtomicWrite error:&err]) {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
+ switch (options.destinationType) {
+ case DestinationTypeFileUri:
+ {
+ NSError* err = nil;
+ NSString* extension = self.pickerController.pictureOptions.encodingType == EncodingTypePNG ? @"png":@"jpg";
+ NSString* filePath = [self tempFilePath:extension];
+
+ // save file
+ if (![self.data writeToFile:filePath options:NSAtomicWrite error:&err]) {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
+ }
+ else {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]];
+ }
}
- else {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]];
+ break;
+ case DestinationTypeDataUrl:
+ {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[self.data base64EncodedString]];
}
- }
- else {
- result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[self.data base64EncodedString]];
- }
- if (result) {
- [self.commandDelegate sendPluginResult:result callbackId:self.pickerController.callbackId];
- }
+ break;
+ case DestinationTypeNativeUri:
+ default:
+ break;
+ };
if (result) {
[self.commandDelegate sendPluginResult:result callbackId:self.pickerController.callbackId];
@@ -685,33 +584,29 @@ static NSSet* org_apache_cordova_validArrowDirections;
self.pickerController = nil;
self.data = nil;
self.metadata = nil;
+
+ if (options.saveToPhotoAlbum) {
+ ALAssetsLibrary *library = [ALAssetsLibrary new];
+ [library writeImageDataToSavedPhotosAlbum:self.data metadata:self.metadata completionBlock:nil];
+ }
}
@end
@implementation CDVCameraPicker
-@synthesize quality, postUrl;
-@synthesize returnType;
-@synthesize callbackId;
-@synthesize popoverController;
-@synthesize targetSize;
-@synthesize correctOrientation;
-@synthesize saveToPhotoAlbum;
-@synthesize encodingType;
-@synthesize cropToSize;
-@synthesize webView;
-@synthesize popoverSupported;
-
-- (BOOL)prefersStatusBarHidden {
+- (BOOL)prefersStatusBarHidden
+{
return YES;
}
-- (UIViewController*)childViewControllerForStatusBarHidden {
+- (UIViewController*)childViewControllerForStatusBarHidden
+{
return nil;
}
-- (void)viewWillAppear:(BOOL)animated {
+- (void)viewWillAppear:(BOOL)animated
+{
SEL sel = NSSelectorFromString(@"setNeedsStatusBarAppearanceUpdate");
if ([self respondsToSelector:sel]) {
[self performSelector:sel withObject:nil afterDelay:0];
@@ -720,4 +615,26 @@ static NSSet* org_apache_cordova_validArrowDirections;
[super viewWillAppear:animated];
}
++ (instancetype) createFromPictureOptions:(CDVPictureOptions*)pictureOptions;
+{
+ CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init];
+ cameraPicker.pictureOptions = pictureOptions;
+ cameraPicker.sourceType = pictureOptions.sourceType;
+ cameraPicker.allowsEditing = pictureOptions.allowsEditing;
+
+ if (cameraPicker.sourceType == UIImagePickerControllerSourceTypeCamera) {
+ // We only allow taking pictures (no video) in this API.
+ cameraPicker.mediaTypes = @[(NSString*)kUTTypeImage];
+ // We can only set the camera device if we're actually using the camera.
+ cameraPicker.cameraDevice = pictureOptions.cameraDirection;
+ } else if (pictureOptions.mediaType == MediaTypeAll) {
+ cameraPicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:cameraPicker.sourceType];
+ } else {
+ NSArray* mediaArray = @[(NSString*)(pictureOptions.mediaType == MediaTypeVideo ? kUTTypeMovie : kUTTypeImage)];
+ cameraPicker.mediaTypes = mediaArray;
+ }
+
+ return cameraPicker;
+}
+
@end
diff --git a/src/ios/UIImage+CropScaleOrientation.h b/src/ios/UIImage+CropScaleOrientation.h
new file mode 100644
index 0000000..0f7fca5
--- /dev/null
+++ b/src/ios/UIImage+CropScaleOrientation.h
@@ -0,0 +1,28 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import
+
+@interface UIImage (CropScaleOrientation)
+
+- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize;
+- (UIImage*)imageCorrectedForCaptureOrientation;
+- (UIImage*)imageByScalingNotCroppingForSize:(CGSize)targetSize;
+
+@end
\ No newline at end of file
diff --git a/src/ios/UIImage+CropScaleOrientation.m b/src/ios/UIImage+CropScaleOrientation.m
new file mode 100644
index 0000000..3ab3ad5
--- /dev/null
+++ b/src/ios/UIImage+CropScaleOrientation.m
@@ -0,0 +1,170 @@
+/*
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+ */
+
+#import "UIImage+CropScaleOrientation.h"
+
+@implementation UIImage (CropScaleOrientation)
+
+- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
+{
+ UIImage* sourceImage = self;
+ UIImage* newImage = nil;
+ CGSize imageSize = sourceImage.size;
+ CGFloat width = imageSize.width;
+ CGFloat height = imageSize.height;
+ CGFloat targetWidth = targetSize.width;
+ CGFloat targetHeight = targetSize.height;
+ CGFloat scaleFactor = 0.0;
+ CGFloat scaledWidth = targetWidth;
+ CGFloat scaledHeight = targetHeight;
+ CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
+
+ if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
+ CGFloat widthFactor = targetWidth / width;
+ CGFloat heightFactor = targetHeight / height;
+
+ if (widthFactor > heightFactor) {
+ scaleFactor = widthFactor; // scale to fit height
+ } else {
+ scaleFactor = heightFactor; // scale to fit width
+ }
+ scaledWidth = width * scaleFactor;
+ scaledHeight = height * scaleFactor;
+
+ // center the image
+ if (widthFactor > heightFactor) {
+ thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
+ } else if (widthFactor < heightFactor) {
+ thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
+ }
+ }
+
+ UIGraphicsBeginImageContext(targetSize); // this will crop
+
+ CGRect thumbnailRect = CGRectZero;
+ thumbnailRect.origin = thumbnailPoint;
+ thumbnailRect.size.width = scaledWidth;
+ thumbnailRect.size.height = scaledHeight;
+
+ [sourceImage drawInRect:thumbnailRect];
+
+ newImage = UIGraphicsGetImageFromCurrentImageContext();
+ if (newImage == nil) {
+ NSLog(@"could not scale image");
+ }
+
+ // pop the context to get back to the default
+ UIGraphicsEndImageContext();
+ return newImage;
+}
+
+- (UIImage*)imageCorrectedForCaptureOrientation
+{
+ float rotation_radians = 0;
+ bool perpendicular = false;
+
+ switch ([self imageOrientation]) {
+ case UIImageOrientationUp :
+ rotation_radians = 0.0;
+ break;
+
+ case UIImageOrientationDown:
+ rotation_radians = M_PI; // don't be scared of radians, if you're reading this, you're good at math
+ break;
+
+ case UIImageOrientationRight:
+ rotation_radians = M_PI_2;
+ perpendicular = true;
+ break;
+
+ case UIImageOrientationLeft:
+ rotation_radians = -M_PI_2;
+ perpendicular = true;
+ break;
+
+ default:
+ break;
+ }
+
+ UIGraphicsBeginImageContext(CGSizeMake(self.size.width, self.size.height));
+ CGContextRef context = UIGraphicsGetCurrentContext();
+
+ // Rotate around the center point
+ CGContextTranslateCTM(context, self.size.width / 2, self.size.height / 2);
+ CGContextRotateCTM(context, rotation_radians);
+
+ CGContextScaleCTM(context, 1.0, -1.0);
+ float width = perpendicular ? self.size.height : self.size.width;
+ float height = perpendicular ? self.size.width : self.size.height;
+ CGContextDrawImage(context, CGRectMake(-width / 2, -height / 2, width, height), [self CGImage]);
+
+ // Move the origin back since the rotation might've change it (if its 90 degrees)
+ if (perpendicular) {
+ CGContextTranslateCTM(context, -self.size.height / 2, -self.size.width / 2);
+ }
+
+ UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
+ UIGraphicsEndImageContext();
+ return newImage;
+}
+
+- (UIImage*)imageByScalingNotCroppingForSize:(CGSize)targetSize
+{
+ UIImage* sourceImage = self;
+ UIImage* newImage = nil;
+ CGSize imageSize = sourceImage.size;
+ CGFloat width = imageSize.width;
+ CGFloat height = imageSize.height;
+ CGFloat targetWidth = targetSize.width;
+ CGFloat targetHeight = targetSize.height;
+ CGFloat scaleFactor = 0.0;
+ CGSize scaledSize = targetSize;
+
+ if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
+ CGFloat widthFactor = targetWidth / width;
+ CGFloat heightFactor = targetHeight / height;
+
+ // opposite comparison to imageByScalingAndCroppingForSize in order to contain the image within the given bounds
+ if (widthFactor > heightFactor) {
+ scaleFactor = heightFactor; // scale to fit height
+ } else {
+ scaleFactor = widthFactor; // scale to fit width
+ }
+ scaledSize = CGSizeMake(MIN(width * scaleFactor, targetWidth), MIN(height * scaleFactor, targetHeight));
+ }
+
+ // If the pixels are floats, it causes a white line in iOS8 and probably other versions too
+ scaledSize.width = (int)scaledSize.width;
+ scaledSize.height = (int)scaledSize.height;
+
+ UIGraphicsBeginImageContext(scaledSize); // this will resize
+
+ [sourceImage drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)];
+
+ newImage = UIGraphicsGetImageFromCurrentImageContext();
+ if (newImage == nil) {
+ NSLog(@"could not scale image");
+ }
+
+ // pop the context to get back to the default
+ UIGraphicsEndImageContext();
+ return newImage;
+}
+
+@end