You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cordova.apache.org by he...@apache.org on 2013/05/22 22:47:20 UTC
[1/3] git commit: add iOS classes to plugin
Updated Branches:
refs/heads/master 5455bbeb3 -> c26377ae9
add iOS classes to plugin
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/commit/fc2c9bd0
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/tree/fc2c9bd0
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/diff/fc2c9bd0
Branch: refs/heads/master
Commit: fc2c9bd0827b0d9beb348bdddc1a8509f3262cea
Parents: 5455bbe
Author: hermwong <he...@gmail.com>
Authored: Tue May 21 12:10:15 2013 -0700
Committer: hermwong <he...@gmail.com>
Committed: Tue May 21 12:10:15 2013 -0700
----------------------------------------------------------------------
src/ios/CDVCamera.h | 102 +++++
src/ios/CDVCamera.m | 729 ++++++++++++++++++++++++++++++++++++
src/ios/CDVExif.h | 43 +++
src/ios/CDVJpegHeaderWriter.h | 62 +++
src/ios/CDVJpegHeaderWriter.m | 547 +++++++++++++++++++++++++++
5 files changed, 1483 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/fc2c9bd0/src/ios/CDVCamera.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVCamera.h b/src/ios/CDVCamera.h
new file mode 100644
index 0000000..2932e3b
--- /dev/null
+++ b/src/ios/CDVCamera.h
@@ -0,0 +1,102 @@
+/*
+ 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 <Foundation/Foundation.h>
+#import <CoreLocation/CoreLocation.h>
+#import <CoreLocation/CLLocationManager.h>
+#import "CDVPlugin.h"
+
+enum CDVDestinationType {
+ DestinationTypeDataUrl = 0,
+ DestinationTypeFileUri,
+ DestinationTypeNativeUri
+};
+typedef NSUInteger CDVDestinationType;
+
+enum CDVEncodingType {
+ EncodingTypeJPEG = 0,
+ EncodingTypePNG
+};
+typedef NSUInteger CDVEncodingType;
+
+enum CDVMediaType {
+ MediaTypePicture = 0,
+ MediaTypeVideo,
+ MediaTypeAll
+};
+typedef NSUInteger CDVMediaType;
+
+@interface CDVCameraPicker : UIImagePickerController
+{}
+
+@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 (assign) CGSize targetSize;
+@property (assign) bool correctOrientation;
+@property (assign) bool saveToPhotoAlbum;
+@property (assign) bool cropToSize;
+@property (strong) UIWebView* webView;
+@property (assign) BOOL popoverSupported;
+
+@end
+
+// ======================================================================= //
+
+@interface CDVCamera : CDVPlugin <UIImagePickerControllerDelegate,
+ UINavigationControllerDelegate,
+ UIPopoverControllerDelegate,
+ CLLocationManagerDelegate>
+{}
+
+@property (strong) CDVCameraPicker* pickerController;
+@property (strong) NSMutableDictionary *metadata;
+@property (strong, nonatomic) CLLocationManager *locationManager;
+@property (strong) NSData* data;
+
+/*
+ * getPicture
+ *
+ * arguments:
+ * 1: this is the javascript function that will be called with the results, the first parameter passed to the
+ * javascript function is the picture as a Base64 encoded string
+ * 2: this is the javascript function to be called if there was an error
+ * options:
+ * quality: integer between 1 and 100
+ */
+- (void)takePicture:(CDVInvokedUrlCommand*)command;
+- (void)postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url;
+- (void)cleanup:(CDVInvokedUrlCommand*)command;
+- (void)repositionPopover:(CDVInvokedUrlCommand*)command;
+
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info;
+- (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;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/fc2c9bd0/src/ios/CDVCamera.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVCamera.m b/src/ios/CDVCamera.m
new file mode 100644
index 0000000..1ee641c
--- /dev/null
+++ b/src/ios/CDVCamera.m
@@ -0,0 +1,729 @@
+/*
+ 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 "CDVCamera.h"
+#import "CDVJpegHeaderWriter.h"
+#import "NSArray+Comparisons.h"
+#import "NSData+Base64.h"
+#import "NSDictionary+Extensions.h"
+#import <ImageIO/CGImageProperties.h>
+#import <AssetsLibrary/ALAssetRepresentation.h>
+#import <ImageIO/CGImageSource.h>
+#import <ImageIO/CGImageProperties.h>
+#import <ImageIO/CGImageDestination.h>
+#import <MobileCoreServices/UTCoreTypes.h>
+
+#define CDV_PHOTO_PREFIX @"cdv_photo_"
+
+static NSSet* org_apache_cordova_validArrowDirections;
+
+@interface CDVCamera ()
+
+@property (readwrite, assign) BOOL hasPendingOperation;
+
+@end
+
+@implementation CDVCamera
+
++ (void)initialize
+{
+ org_apache_cordova_validArrowDirections = [[NSSet alloc] initWithObjects:[NSNumber numberWithInt:UIPopoverArrowDirectionUp], [NSNumber numberWithInt:UIPopoverArrowDirectionDown], [NSNumber numberWithInt:UIPopoverArrowDirectionLeft], [NSNumber numberWithInt:UIPopoverArrowDirectionRight], [NSNumber numberWithInt:UIPopoverArrowDirectionAny], nil];
+}
+
+@synthesize hasPendingOperation, pickerController, locationManager;
+
+- (BOOL)popoverSupported
+{
+ return (NSClassFromString(@"UIPopoverController") != nil) &&
+ (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 = NO;
+
+ 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 %d not available.", 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.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];
+ }
+ NSDictionary* options = [command.arguments objectAtIndex:10 withDefault:nil];
+ [self displayPopover:options];
+ } else {
+ if ([self.viewController respondsToSelector:@selector(presentViewController:::)]) {
+ [self.viewController presentViewController:cameraPicker animated:YES completion:nil];
+ } else {
+ [self.viewController presentModalViewController:cameraPicker animated:YES];
+ }
+ }
+ self.hasPendingOperation = YES;
+}
+
+- (void)repositionPopover:(CDVInvokedUrlCommand*)command
+{
+ NSDictionary* options = [command.arguments objectAtIndex:0 withDefault:nil];
+
+ [self displayPopover:options];
+}
+
+- (void)displayPopover:(NSDictionary*)options
+{
+ int x = 0;
+ int y = 32;
+ int width = 320;
+ int height = 480;
+ UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny;
+
+ if (options) {
+ x = [options integerValueForKey:@"x" defaultValue:0];
+ y = [options integerValueForKey:@"y" defaultValue:32];
+ width = [options integerValueForKey:@"width" defaultValue:320];
+ height = [options integerValueForKey:@"height" defaultValue:480];
+ arrowDirection = [options integerValueForKey:@"arrowDir" defaultValue:UIPopoverArrowDirectionAny];
+ if (![org_apache_cordova_validArrowDirections containsObject:[NSNumber numberWithInt:arrowDirection]]) {
+ arrowDirection = UIPopoverArrowDirectionAny;
+ }
+ }
+
+ [[[self pickerController] popoverController] setDelegate:self];
+ [[[self pickerController] popoverController] presentPopoverFromRect:CGRectMake(x, y, width, height)
+ inView:[self.webView superview]
+ permittedArrowDirections:arrowDirection
+ animated:YES];
+}
+
+- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
+{
+ if([navigationController isKindOfClass:[UIImagePickerController class]]){
+ UIImagePickerController * cameraPicker = (UIImagePickerController*)navigationController;
+
+ if(![cameraPicker.mediaTypes containsObject:(NSString*) kUTTypeImage]){
+ [viewController.navigationItem setTitle:NSLocalizedString(@"Videos title", nil)];
+ }
+ }
+}
+
+- (void)cleanup:(CDVInvokedUrlCommand*)command
+{
+ // empty the tmp directory
+ NSFileManager* fileMgr = [[NSFileManager alloc] init];
+ NSError* err = nil;
+ BOOL hasErrors = NO;
+
+ // clear contents of NSTemporaryDirectory
+ NSString* tempDirectoryPath = NSTemporaryDirectory();
+ NSDirectoryEnumerator* directoryEnumerator = [fileMgr enumeratorAtPath:tempDirectoryPath];
+ NSString* fileName = nil;
+ BOOL result;
+
+ while ((fileName = [directoryEnumerator nextObject])) {
+ // only delete the files we created
+ if (![fileName hasPrefix:CDV_PHOTO_PREFIX]) {
+ continue;
+ }
+ NSString* filePath = [tempDirectoryPath stringByAppendingPathComponent:fileName];
+ result = [fileMgr removeItemAtPath:filePath error:&err];
+ if (!result && err) {
+ NSLog(@"Failed to delete: %@ (error: %@)", filePath, err);
+ hasErrors = YES;
+ }
+ }
+
+ CDVPluginResult* pluginResult;
+ if (hasErrors) {
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:@"One or more files failed to be deleted."];
+ } else {
+ pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
+ }
+ [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
+}
+
+- (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;
+ 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];
+ }
+ self.hasPendingOperation = NO;
+}
+
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
+{
+ CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
+
+ if (cameraPicker.popoverSupported && (cameraPicker.popoverController != nil)) {
+ [cameraPicker.popoverController dismissPopoverAnimated:YES];
+ cameraPicker.popoverController.delegate = nil;
+ cameraPicker.popoverController = nil;
+ } else {
+ if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) {
+ [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES];
+ } else {
+ [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES];
+ }
+ }
+
+ 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;
+
+ if (cameraPicker.encodingType == EncodingTypePNG) {
+ data = UIImagePNGRepresentation(scaledImage == nil ? image : scaledImage);
+ } else {
+ self.data = UIImageJPEGRepresentation(scaledImage == nil ? image : scaledImage, cameraPicker.quality / 100.0f);
+
+ NSDictionary *controllerMetadata = [info objectForKey:@"UIImagePickerControllerMediaMetadata"];
+ if (controllerMetadata) {
+ self.metadata = [[NSMutableDictionary alloc] init];
+
+ NSMutableDictionary *EXIFDictionary = [[controllerMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy];
+ if (EXIFDictionary) [self.metadata setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary];
+
+ [[self locationManager] startUpdatingLocation];
+ return;
+ }
+ }
+
+ if (cameraPicker.saveToPhotoAlbum) {
+ UIImageWriteToSavedPhotosAlbum([UIImage imageWithData:data], nil, nil, nil);
+ }
+
+ if (cameraPicker.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++, 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 {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[data base64EncodedString]];
+ }
+ }
+ }
+ // NOT IMAGE TYPE (MOVIE)
+ else {
+ NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:moviePath];
+ }
+
+ if (result) {
+ [self.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId];
+ }
+
+ self.hasPendingOperation = NO;
+ self.pickerController = nil;
+}
+
+// older api calls newer didFinishPickingMediaWithInfo
+- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo
+{
+ NSDictionary* imageInfo = [NSDictionary dictionaryWithObject:image forKey:UIImagePickerControllerOriginalImage];
+
+ [self imagePickerController:picker didFinishPickingMediaWithInfo:imageInfo];
+}
+
+- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker
+{
+ CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
+
+ if ([cameraPicker respondsToSelector:@selector(presentingViewController)]) {
+ [[cameraPicker presentingViewController] dismissModalViewControllerAnimated:YES];
+ } else {
+ [[cameraPicker parentViewController] dismissModalViewControllerAnimated:YES];
+ }
+ // popoverControllerDidDismissPopover:(id)popoverController is called if popover is cancelled
+
+ CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"]; // error callback expects string ATM
+ [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
+ } 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:(UIImage*)anImage
+{
+ 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));
+ }
+
+ 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;
+}
+
+- (void)postImage:(UIImage*)anImage withFilename:(NSString*)filename toUrl:(NSURL*)url
+{
+ self.hasPendingOperation = YES;
+
+ NSString* boundary = @"----BOUNDARY_IS_I";
+
+ NSMutableURLRequest* req = [NSMutableURLRequest requestWithURL:url];
+ [req setHTTPMethod:@"POST"];
+
+ NSString* contentType = [NSString stringWithFormat:@"multipart/form-data; boundary=%@", boundary];
+ [req setValue:contentType forHTTPHeaderField:@"Content-type"];
+
+ NSData* imageData = UIImagePNGRepresentation(anImage);
+
+ // adding the body
+ NSMutableData* postBody = [NSMutableData data];
+
+ // first parameter an image
+ [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
+ [postBody appendData:[[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"upload\"; filename=\"%@\"\r\n", filename] dataUsingEncoding:NSUTF8StringEncoding]];
+ [postBody appendData:[@"Content-Type: image/png\r\n\r\n" dataUsingEncoding : NSUTF8StringEncoding]];
+ [postBody appendData:imageData];
+
+ // // second parameter information
+ // [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@\r\n", boundary] dataUsingEncoding:NSUTF8StringEncoding]];
+ // [postBody appendData:[@"Content-Disposition: form-data; name=\"some_other_name\"\r\n\r\n" dataUsingEncoding:NSUTF8StringEncoding]];
+ // [postBody appendData:[@"some_other_value" dataUsingEncoding:NSUTF8StringEncoding]];
+ // [postBody appendData:[[NSString stringWithFormat:@"\r\n--%@--\r \n",boundary] dataUsingEncoding:NSUTF8StringEncoding]];
+
+ [req setHTTPBody:postBody];
+
+ NSURLResponse* response;
+ NSError* error;
+ [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
+
+ // NSData* result = [NSURLConnection sendSynchronousRequest:req returningResponse:&response error:&error];
+ // NSString * resultStr = [[[NSString alloc] initWithData:result encoding:NSUTF8StringEncoding] autorelease];
+
+ self.hasPendingOperation = NO;
+}
+
+
+- (CLLocationManager *)locationManager {
+
+ if (locationManager != nil) {
+ return locationManager;
+ }
+
+ locationManager = [[CLLocationManager alloc] init];
+ [locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
+ [locationManager setDelegate:self];
+
+ return locationManager;
+}
+
+- (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];
+ }
+
+ // 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)imagePickerControllerReturnImageResult
+{
+ CDVPluginResult* result = nil;
+
+ if (self.metadata) {
+ CGImageSourceRef sourceImage = CGImageSourceCreateWithData((__bridge_retained CFDataRef)self.data, NULL);
+ CFStringRef sourceType = CGImageSourceGetType(sourceImage);
+
+ CGImageDestinationRef destinationImage = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)self.data, sourceType, 1, NULL);
+ CGImageDestinationAddImageFromSource(destinationImage, sourceImage, 0, (__bridge CFDictionaryRef)self.metadata);
+ CGImageDestinationFinalize(destinationImage);
+
+ CFRelease(sourceImage);
+ CFRelease(destinationImage);
+ }
+
+ if (self.pickerController.saveToPhotoAlbum) {
+ UIImageWriteToSavedPhotosAlbum([UIImage imageWithData:[self data]], nil, nil, 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]];
+ }
+ else {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[NSURL fileURLWithPath:filePath] absoluteString]];
+ }
+ }
+ else {
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[self.data base64EncodedString]];
+ }
+ if (result) {
+ [self.commandDelegate sendPluginResult:result callbackId:self.pickerController.callbackId];
+ }
+
+ if (result) {
+ [self.commandDelegate sendPluginResult:result callbackId:self.pickerController.callbackId];
+ }
+
+ self.hasPendingOperation = NO;
+ self.pickerController = nil;
+ self.data = nil;
+ self.metadata = 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;
+
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/fc2c9bd0/src/ios/CDVExif.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVExif.h b/src/ios/CDVExif.h
new file mode 100644
index 0000000..3e8adbd
--- /dev/null
+++ b/src/ios/CDVExif.h
@@ -0,0 +1,43 @@
+/*
+ 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.
+ */
+
+#ifndef CordovaLib_ExifData_h
+#define CordovaLib_ExifData_h
+
+// exif data types
+typedef enum exifDataTypes {
+ EDT_UBYTE = 1, // 8 bit unsigned integer
+ EDT_ASCII_STRING, // 8 bits containing 7 bit ASCII code, null terminated
+ EDT_USHORT, // 16 bit unsigned integer
+ EDT_ULONG, // 32 bit unsigned integer
+ EDT_URATIONAL, // 2 longs, first is numerator and second is denominator
+ EDT_SBYTE,
+ EDT_UNDEFINED, // 8 bits
+ EDT_SSHORT,
+ EDT_SLONG, // 32bit signed integer (2's complement)
+ EDT_SRATIONAL, // 2 SLONGS, first long is numerator, second is denominator
+ EDT_SINGLEFLOAT,
+ EDT_DOUBLEFLOAT
+} ExifDataTypes;
+
+// maps integer code for exif data types to width in bytes
+static const int DataTypeToWidth[] = {1,1,2,4,8,1,1,2,4,8,4,8};
+
+static const int RECURSE_HORIZON = 8;
+#endif
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/fc2c9bd0/src/ios/CDVJpegHeaderWriter.h
----------------------------------------------------------------------
diff --git a/src/ios/CDVJpegHeaderWriter.h b/src/ios/CDVJpegHeaderWriter.h
new file mode 100644
index 0000000..3b43ef0
--- /dev/null
+++ b/src/ios/CDVJpegHeaderWriter.h
@@ -0,0 +1,62 @@
+/*
+ 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 <Foundation/Foundation.h>
+
+@interface CDVJpegHeaderWriter : NSObject {
+ NSDictionary * SubIFDTagFormatDict;
+ NSDictionary * IFD0TagFormatDict;
+}
+
+- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata
+ withExifBlock: (NSString*) exifstr;
+- (NSString*) createExifAPP1 : (NSDictionary*) datadict;
+- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb
+ withPlaces: (NSNumber*) width;
+- (NSString*) formatNumberWithLeadingZeroes: (NSNumber*) numb
+ withPlaces: (NSNumber*) places;
+- (NSString*) decimalToUnsignedRational: (NSNumber*) numb
+ withResultNumerator: (NSNumber**) numerator
+ withResultDenominator: (NSNumber**) denominator;
+- (void) continuedFraction: (double) val
+ withFractionList: (NSMutableArray*) fractionlist
+ withHorizon: (int) horizon;
+//- (void) expandContinuedFraction: (NSArray*) fractionlist;
+- (void) splitDouble: (double) val
+ withIntComponent: (int*) rightside
+ withFloatRemainder: (double*) leftside;
+- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator
+ withDenominator: (NSNumber*) denominator
+ asSigned: (Boolean) signedFlag;
+- (NSString*) hexStringFromData : (NSData*) data;
+- (NSNumber*) numericFromHexString : (NSString *) hexstring;
+
+/*
+- (void) readExifMetaData : (NSData*) imgdata;
+- (void) spliceImageData : (NSData*) imgdata withExifData: (NSDictionary*) exifdata;
+- (void) locateExifMetaData : (NSData*) imgdata;
+- (NSString*) createExifAPP1 : (NSDictionary*) datadict;
+- (void) createExifDataString : (NSDictionary*) datadict;
+- (NSString*) createDataElement : (NSString*) element
+ withElementData: (NSString*) data
+ withExternalDataBlock: (NSDictionary*) memblock;
+- (NSString*) hexStringFromData : (NSData*) data;
+- (NSNumber*) numericFromHexString : (NSString *) hexstring;
+*/
+@end
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/fc2c9bd0/src/ios/CDVJpegHeaderWriter.m
----------------------------------------------------------------------
diff --git a/src/ios/CDVJpegHeaderWriter.m b/src/ios/CDVJpegHeaderWriter.m
new file mode 100644
index 0000000..93cafb8
--- /dev/null
+++ b/src/ios/CDVJpegHeaderWriter.m
@@ -0,0 +1,547 @@
+/*
+ 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 "CDVJpegHeaderWriter.h"
+#include "CDVExif.h"
+
+/* macros for tag info shorthand:
+ tagno : tag number
+ typecode : data type
+ components : number of components
+ appendString (TAGINF_W_APPEND only) : string to append to data
+ Exif date data format include an extra 0x00 to the end of the data
+ */
+#define TAGINF(tagno, typecode, components) [NSArray arrayWithObjects: tagno, typecode, components, nil]
+#define TAGINF_W_APPEND(tagno, typecode, components, appendString) [NSArray arrayWithObjects: tagno, typecode, components, appendString, nil]
+
+const uint mJpegId = 0xffd8; // JPEG format marker
+const uint mExifMarker = 0xffe1; // APP1 jpeg header marker
+const uint mExif = 0x45786966; // ASCII 'Exif', first characters of valid exif header after size
+const uint mMotorallaByteAlign = 0x4d4d; // 'MM', motorola byte align, msb first or 'sane'
+const uint mIntelByteAlgin = 0x4949; // 'II', Intel byte align, lsb first or 'batshit crazy reverso world'
+const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a(MM) or 0x2a00(II), tiff version number
+
+
+@implementation CDVJpegHeaderWriter
+
+- (id) init {
+ self = [super init];
+ // supported tags for exif IFD
+ IFD0TagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
+ // TAGINF(@"010e", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"ImageDescription",
+ TAGINF_W_APPEND(@"0132", [NSNumber numberWithInt:EDT_ASCII_STRING], @20, @"00"), @"DateTime",
+ TAGINF(@"010f", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Make",
+ TAGINF(@"0110", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Model",
+ TAGINF(@"0131", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Software",
+ TAGINF(@"011a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"XResolution",
+ TAGINF(@"011b", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"YResolution",
+ // currently supplied outside of Exif data block by UIImagePickerControllerMediaMetadata, this is set manually in CDVCamera.m
+ /* TAGINF(@"0112", [NSNumber numberWithInt:EDT_USHORT], @1), @"Orientation",
+
+ // rest of the tags are supported by exif spec, but are not specified by UIImagePickerControllerMediaMedadata
+ // should camera hardware supply these values in future versions, or if they can be derived, ImageHeaderWriter will include them gracefully
+ TAGINF(@"0128", [NSNumber numberWithInt:EDT_USHORT], @1), @"ResolutionUnit",
+ TAGINF(@"013e", [NSNumber numberWithInt:EDT_URATIONAL], @2), @"WhitePoint",
+ TAGINF(@"013f", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"PrimaryChromaticities",
+ TAGINF(@"0211", [NSNumber numberWithInt:EDT_URATIONAL], @3), @"YCbCrCoefficients",
+ TAGINF(@"0213", [NSNumber numberWithInt:EDT_USHORT], @1), @"YCbCrPositioning",
+ TAGINF(@"0214", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"ReferenceBlackWhite",
+ TAGINF(@"8298", [NSNumber numberWithInt:EDT_URATIONAL], @0), @"Copyright",
+
+ // offset to exif subifd, we determine this dynamically based on the size of the main exif IFD
+ TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",*/
+ nil];
+
+
+ // supported tages for exif subIFD
+ SubIFDTagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
+ //TAGINF(@"9000", [NSNumber numberWithInt:], @), @"ExifVersion",
+ //TAGINF(@"9202",[NSNumber numberWithInt:EDT_URATIONAL],@1), @"ApertureValue",
+ //TAGINF(@"9203",[NSNumber numberWithInt:EDT_SRATIONAL],@1), @"BrightnessValue",
+ TAGINF(@"a001",[NSNumber numberWithInt:EDT_USHORT],@1), @"ColorSpace",
+ TAGINF_W_APPEND(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeDigitized",
+ TAGINF_W_APPEND(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeOriginal",
+ TAGINF(@"a402", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureMode",
+ TAGINF(@"8822", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureProgram",
+ //TAGINF(@"829a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"ExposureTime",
+ //TAGINF(@"829d", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FNumber",
+ TAGINF(@"9209", [NSNumber numberWithInt:EDT_USHORT], @1), @"Flash",
+ // FocalLengthIn35mmFilm
+ TAGINF(@"a405", [NSNumber numberWithInt:EDT_USHORT], @1), @"FocalLenIn35mmFilm",
+ //TAGINF(@"920a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FocalLength",
+ //TAGINF(@"8827", [NSNumber numberWithInt:EDT_USHORT], @2), @"ISOSpeedRatings",
+ TAGINF(@"9207", [NSNumber numberWithInt:EDT_USHORT],@1), @"MeteringMode",
+ // specific to compressed data
+ TAGINF(@"a002", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelXDimension",
+ TAGINF(@"a003", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelYDimension",
+ // data type undefined, but this is a DSC camera, so value is always 1, treat as ushort
+ TAGINF(@"a301", [NSNumber numberWithInt:EDT_USHORT],@1), @"SceneType",
+ TAGINF(@"a217",[NSNumber numberWithInt:EDT_USHORT],@1), @"SensingMethod",
+ //TAGINF(@"9201", [NSNumber numberWithInt:EDT_SRATIONAL], @1), @"ShutterSpeedValue",
+ // specifies location of main subject in scene (x,y,wdith,height) expressed before rotation processing
+ //TAGINF(@"9214", [NSNumber numberWithInt:EDT_USHORT], @4), @"SubjectArea",
+ TAGINF(@"a403", [NSNumber numberWithInt:EDT_USHORT], @1), @"WhiteBalance",
+ nil];
+ return self;
+}
+
+- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata withExifBlock: (NSString*) exifstr {
+
+ CDVJpegHeaderWriter * exifWriter = [[CDVJpegHeaderWriter alloc] init];
+
+ NSMutableData * exifdata = [NSMutableData dataWithCapacity: [exifstr length]/2];
+ int idx;
+ for (idx = 0; idx+1 < [exifstr length]; idx+=2) {
+ NSRange range = NSMakeRange(idx, 2);
+ NSString* hexStr = [exifstr substringWithRange:range];
+ NSScanner* scanner = [NSScanner scannerWithString:hexStr];
+ unsigned int intValue;
+ [scanner scanHexInt:&intValue];
+ [exifdata appendBytes:&intValue length:1];
+ }
+
+ NSMutableData * ddata = [NSMutableData dataWithCapacity: [jpegdata length]];
+ NSMakeRange(0,4);
+ int loc = 0;
+ bool done = false;
+ // read the jpeg data until we encounter the app1==0xFFE1 marker
+ while (loc+1 < [jpegdata length]) {
+ NSData * blag = [jpegdata subdataWithRange: NSMakeRange(loc,2)];
+ if( [[blag description] isEqualToString : @"<ffe1>"]) {
+ // read the APP1 block size bits
+ NSString * the = [exifWriter hexStringFromData:[jpegdata subdataWithRange: NSMakeRange(loc+2,2)]];
+ NSNumber * app1width = [exifWriter numericFromHexString:the];
+ //consume the original app1 block
+ [ddata appendData:exifdata];
+ // advance our loc marker past app1
+ loc += [app1width intValue] + 2;
+ done = true;
+ } else {
+ if(!done) {
+ [ddata appendData:blag];
+ loc += 2;
+ } else {
+ break;
+ }
+ }
+ }
+ // copy the remaining data
+ [ddata appendData:[jpegdata subdataWithRange: NSMakeRange(loc,[jpegdata length]-loc)]];
+ return ddata;
+}
+
+
+
+/**
+ * Create the Exif data block as a hex string
+ * jpeg uses Application Markers (APP's) as markers for application data
+ * APP1 is the application marker reserved for exif data
+ *
+ * (NSDictionary*) datadict - with subdictionaries marked '{TIFF}' and '{EXIF}' as returned by imagePickerController with a valid
+ * didFinishPickingMediaWithInfo data dict, under key @"UIImagePickerControllerMediaMetadata"
+ *
+ * the following constructs a hex string to Exif specifications, and is therefore brittle
+ * altering the order of arguments to the string constructors, modifying field sizes or formats,
+ * and any other minor change will likely prevent the exif data from being read
+ */
+- (NSString*) createExifAPP1 : (NSDictionary*) datadict {
+ NSMutableString * app1; // holds finalized product
+ NSString * exifIFD; // exif information file directory
+ NSString * subExifIFD; // subexif information file directory
+
+ // FFE1 is the hex APP1 marker code, and will allow client apps to read the data
+ NSString * app1marker = @"ffe1";
+ // SSSS size, to be determined
+ // EXIF ascii characters followed by 2bytes of zeros
+ NSString * exifmarker = @"457869660000";
+ // Tiff header: 4d4d is motorolla byte align (big endian), 002a is hex for 42
+ NSString * tiffheader = @"4d4d002a";
+ //first IFD offset from the Tiff header to IFD0. Since we are writing it, we know it's address 0x08
+ NSString * ifd0offset = @"00000008";
+ // current offset to next data area
+ int currentDataOffset = 0;
+
+ //data labeled as TIFF in UIImagePickerControllerMediaMetaData is part of the EXIF IFD0 portion of APP1
+ exifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{TIFF}"] withFormatDict: IFD0TagFormatDict isIFD0:YES currentDataOffset:¤tDataOffset];
+
+ //data labeled as EXIF in UIImagePickerControllerMediaMetaData is part of the EXIF Sub IFD portion of APP1
+ subExifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{Exif}"] withFormatDict: SubIFDTagFormatDict isIFD0:NO currentDataOffset:¤tDataOffset];
+ /*
+ NSLog(@"SUB EXIF IFD %@ WITH SIZE: %d",exifIFD,[exifIFD length]);
+
+ NSLog(@"SUB EXIF IFD %@ WITH SIZE: %d",subExifIFD,[subExifIFD length]);
+ */
+ // construct the complete app1 data block
+ app1 = [[NSMutableString alloc] initWithFormat: @"%@%04x%@%@%@%@%@",
+ app1marker,
+ 16 + ([exifIFD length]/2) + ([subExifIFD length]/2) /*16+[exifIFD length]/2*/,
+ exifmarker,
+ tiffheader,
+ ifd0offset,
+ exifIFD,
+ subExifIFD];
+
+ return app1;
+}
+
+// returns hex string representing a valid exif information file directory constructed from the datadict and formatdict
+- (NSString*) createExifIFDFromDict : (NSDictionary*) datadict
+ withFormatDict : (NSDictionary*) formatdict
+ isIFD0 : (BOOL) ifd0flag
+ currentDataOffset : (int*) dataoffset {
+ NSArray * datakeys = [datadict allKeys]; // all known data keys
+ NSArray * knownkeys = [formatdict allKeys]; // only keys in knowkeys are considered for entry in this IFD
+ NSMutableArray * ifdblock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // all ifd entries
+ NSMutableArray * ifddatablock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // data block entries
+ // ifd0flag = NO; // ifd0 requires a special flag and has offset to next ifd appended to end
+
+ // iterate through known provided data keys
+ for (int i = 0; i < [datakeys count]; i++) {
+ NSString * key = [datakeys objectAtIndex:i];
+ // don't muck about with unknown keys
+ if ([knownkeys indexOfObject: key] != NSNotFound) {
+ // create new IFD entry
+ NSString * entry = [self createIFDElement: key
+ withFormat: [formatdict objectForKey:key]
+ withElementData: [datadict objectForKey:key]];
+ // create the IFD entry's data block
+ NSString * data = [self createIFDElementDataWithFormat: [formatdict objectForKey:key]
+ withData: [datadict objectForKey:key]];
+ if (entry) {
+ [ifdblock addObject:entry];
+ if(!data) {
+ [ifdblock addObject:@""];
+ } else {
+ [ifddatablock addObject:data];
+ }
+ }
+ }
+ }
+
+ NSMutableString * exifstr = [[NSMutableString alloc] initWithCapacity: [ifdblock count] * 24];
+ NSMutableString * dbstr = [[NSMutableString alloc] initWithCapacity: 100];
+
+ int addr=*dataoffset; // current offset/address in datablock
+ if (ifd0flag) {
+ // calculate offset to datablock based on ifd file entry count
+ addr += 14+(12*([ifddatablock count]+1)); // +1 for tag 0x8769, exifsubifd offset
+ } else {
+ // current offset + numSubIFDs (2-bytes) + 12*numSubIFDs + endMarker (4-bytes)
+ addr += 2+(12*[ifddatablock count])+4;
+ }
+
+ for (int i = 0; i < [ifdblock count]; i++) {
+ NSString * entry = [ifdblock objectAtIndex:i];
+ NSString * data = [ifddatablock objectAtIndex:i];
+
+ // check if the data fits into 4 bytes
+ if( [data length] <= 8) {
+ // concatenate the entry and the (4byte) data entry into the final IFD entry and append to exif ifd string
+ [exifstr appendFormat : @"%@%@", entry, data];
+ } else {
+ [exifstr appendFormat : @"%@%08x", entry, addr];
+ [dbstr appendFormat: @"%@", data];
+ addr+= [data length] / 2;
+ /*
+ NSLog(@"=====data-length[%i]=======",[data length]);
+ NSLog(@"addr-offset[%i]",addr);
+ NSLog(@"entry[%@]",entry);
+ NSLog(@"data[%@]",data);
+ */
+ }
+ }
+
+ // calculate IFD0 terminal offset tags, currently ExifSubIFD
+ int entrycount = [ifdblock count];
+ if (ifd0flag) {
+ // 18 accounts for 8769's width + offset to next ifd, 8 accounts for start of header
+ NSNumber * offset = [NSNumber numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 + 18+8];
+
+ [self appendExifOffsetTagTo: exifstr
+ withOffset : offset];
+ entrycount++;
+ }
+ *dataoffset = addr;
+ return [[NSString alloc] initWithFormat: @"%04x%@%@%@",
+ entrycount,
+ exifstr,
+ @"00000000", // offset to next IFD, 0 since there is none
+ dbstr]; // lastly, the datablock
+}
+
+// Creates an exif formatted exif information file directory entry
+- (NSString*) createIFDElement: (NSString*) elementName withFormat: (NSArray*) formtemplate withElementData: (NSString*) data {
+ //NSArray * fielddata = [formatdict objectForKey: elementName];// format data of desired field
+ if (formtemplate) {
+ // format string @"%@%@%@%@", tag number, data format, components, value
+ NSNumber * dataformat = [formtemplate objectAtIndex:1];
+ NSNumber * components = [formtemplate objectAtIndex:2];
+ if([components intValue] == 0) {
+ components = [NSNumber numberWithInt: [data length] * DataTypeToWidth[[dataformat intValue]-1]];
+ }
+
+ return [[NSString alloc] initWithFormat: @"%@%@%08x",
+ [formtemplate objectAtIndex:0], // the field code
+ [self formatNumberWithLeadingZeroes: dataformat withPlaces: @4], // the data type code
+ [components intValue]]; // number of components
+ }
+ return NULL;
+}
+
+/**
+ * appends exif IFD0 tag 8769 "ExifOffset" to the string provided
+ * (NSMutableString*) str - string you wish to append the 8769 tag to: APP1 or IFD0 hex data string
+ * // TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",
+ */
+- (void) appendExifOffsetTagTo: (NSMutableString*) str withOffset : (NSNumber*) offset {
+ NSArray * format = TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1);
+
+ NSString * entry = [self createIFDElement: @"ExifOffset"
+ withFormat: format
+ withElementData: [offset stringValue]];
+
+ NSString * data = [self createIFDElementDataWithFormat: format
+ withData: [offset stringValue]];
+ [str appendFormat:@"%@%@", entry, data];
+}
+
+// formats the Information File Directory Data to exif format
+- (NSString*) createIFDElementDataWithFormat: (NSArray*) dataformat withData: (NSString*) data {
+ NSMutableString * datastr = nil;
+ NSNumber * tmp = nil;
+ NSNumber * formatcode = [dataformat objectAtIndex:1];
+ NSUInteger formatItemsCount = [dataformat count];
+ NSNumber * num = @0;
+ NSNumber * denom = @0;
+
+ switch ([formatcode intValue]) {
+ case EDT_UBYTE:
+ break;
+ case EDT_ASCII_STRING:
+ datastr = [[NSMutableString alloc] init];
+ for (int i = 0; i < [data length]; i++) {
+ [datastr appendFormat:@"%02x",[data characterAtIndex:i]];
+ }
+ if (formatItemsCount > 3) {
+ // We have additional data to append.
+ // currently used by Date format to append final 0x00 but can be used by other data types as well in the future
+ [datastr appendString:[dataformat objectAtIndex:3]];
+ }
+ if ([datastr length] < 8) {
+ NSString * format = [NSString stringWithFormat:@"%%0%dd", 8 - [datastr length]];
+ [datastr appendFormat:format,0];
+ }
+ return datastr;
+ case EDT_USHORT:
+ return [[NSString alloc] initWithFormat : @"%@%@",
+ [self formattedHexStringFromDecimalNumber: [NSNumber numberWithInt: [data intValue]] withPlaces: @4],
+ @"0000"];
+ case EDT_ULONG:
+ tmp = [NSNumber numberWithUnsignedLong:[data intValue]];
+ return [NSString stringWithFormat : @"%@",
+ [self formattedHexStringFromDecimalNumber: tmp withPlaces: @8]];
+ case EDT_URATIONAL:
+ return [self decimalToUnsignedRational: [NSNumber numberWithDouble:[data doubleValue]]
+ withResultNumerator: &num
+ withResultDenominator: &denom];
+ case EDT_SBYTE:
+
+ break;
+ case EDT_UNDEFINED:
+ break; // 8 bits
+ case EDT_SSHORT:
+ break;
+ case EDT_SLONG:
+ break; // 32bit signed integer (2's complement)
+ case EDT_SRATIONAL:
+ break; // 2 SLONGS, first long is numerator, second is denominator
+ case EDT_SINGLEFLOAT:
+ break;
+ case EDT_DOUBLEFLOAT:
+ break;
+ }
+ return datastr;
+}
+
+//======================================================================================================================
+// Utility Methods
+//======================================================================================================================
+
+// creates a formatted little endian hex string from a number and width specifier
+- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb withPlaces: (NSNumber*) width {
+ NSMutableString * str = [[NSMutableString alloc] initWithCapacity:[width intValue]];
+ NSString * formatstr = [[NSString alloc] initWithFormat: @"%%%@%dx", @"0", [width intValue]];
+ [str appendFormat:formatstr, [numb intValue]];
+ return str;
+}
+
+// format number as string with leading 0's
+- (NSString*) formatNumberWithLeadingZeroes: (NSNumber *) numb withPlaces: (NSNumber *) places {
+ NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init];
+ NSString *formatstr = [@"" stringByPaddingToLength:[places unsignedIntegerValue] withString:@"0" startingAtIndex:0];
+ [formatter setPositiveFormat:formatstr];
+ return [formatter stringFromNumber:numb];
+}
+
+// approximate a decimal with a rational by method of continued fraction
+// can be collasped into decimalToUnsignedRational after testing
+- (void) decimalToRational: (NSNumber *) numb
+ withResultNumerator: (NSNumber**) numerator
+ withResultDenominator: (NSNumber**) denominator {
+ NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8];
+
+ [self continuedFraction: [numb doubleValue]
+ withFractionList: fractionlist
+ withHorizon: 8];
+
+ // simplify complex fraction represented by partial fraction list
+ [self expandContinuedFraction: fractionlist
+ withResultNumerator: numerator
+ withResultDenominator: denominator];
+
+}
+
+// approximate a decimal with an unsigned rational by method of continued fraction
+- (NSString*) decimalToUnsignedRational: (NSNumber *) numb
+ withResultNumerator: (NSNumber**) numerator
+ withResultDenominator: (NSNumber**) denominator {
+ NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8];
+
+ // generate partial fraction list
+ [self continuedFraction: [numb doubleValue]
+ withFractionList: fractionlist
+ withHorizon: 8];
+
+ // simplify complex fraction represented by partial fraction list
+ [self expandContinuedFraction: fractionlist
+ withResultNumerator: numerator
+ withResultDenominator: denominator];
+
+ return [self formatFractionList: fractionlist];
+}
+
+// recursive implementation of decimal approximation by continued fraction
+- (void) continuedFraction: (double) val
+ withFractionList: (NSMutableArray*) fractionlist
+ withHorizon: (int) horizon {
+ int whole;
+ double remainder;
+ // 1. split term
+ [self splitDouble: val withIntComponent: &whole withFloatRemainder: &remainder];
+ [fractionlist addObject: [NSNumber numberWithInt:whole]];
+
+ // 2. calculate reciprocal of remainder
+ if (!remainder) return; // early exit, exact fraction found, avoids recip/0
+ double recip = 1 / remainder;
+
+ // 3. exit condition
+ if ([fractionlist count] > horizon) {
+ return;
+ }
+
+ // 4. recurse
+ [self continuedFraction:recip withFractionList: fractionlist withHorizon: horizon];
+
+}
+
+// expand continued fraction list, creating a single level rational approximation
+-(void) expandContinuedFraction: (NSArray*) fractionlist
+ withResultNumerator: (NSNumber**) numerator
+ withResultDenominator: (NSNumber**) denominator {
+ int i = 0;
+ int den = 0;
+ int num = 0;
+ if ([fractionlist count] == 1) {
+ *numerator = [NSNumber numberWithInt:[[fractionlist objectAtIndex:0] intValue]];
+ *denominator = @1;
+ return;
+ }
+
+ //begin at the end of the list
+ i = [fractionlist count] - 1;
+ num = 1;
+ den = [[fractionlist objectAtIndex:i] intValue];
+
+ while (i > 0) {
+ int t = [[fractionlist objectAtIndex: i-1] intValue];
+ num = t * den + num;
+ if (i==1) {
+ break;
+ } else {
+ t = num;
+ num = den;
+ den = t;
+ }
+ i--;
+ }
+ // set result parameters values
+ *numerator = [NSNumber numberWithInt: num];
+ *denominator = [NSNumber numberWithInt: den];
+}
+
+// formats expanded fraction list to string matching exif specification
+- (NSString*) formatFractionList: (NSArray *) fractionlist {
+ NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16];
+
+ if ([fractionlist count] == 1){
+ [str appendFormat: @"%08x00000001", [[fractionlist objectAtIndex:0] intValue]];
+ }
+ return str;
+}
+
+// format rational as
+- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator withDenominator: (NSNumber*) denominator asSigned: (Boolean) signedFlag {
+ NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16];
+ if (signedFlag) {
+ long num = [numerator longValue];
+ long den = [denominator longValue];
+ [str appendFormat: @"%08lx%08lx", num >= 0 ? num : ~ABS(num) + 1, num >= 0 ? den : ~ABS(den) + 1];
+ } else {
+ [str appendFormat: @"%08lx%08lx", [numerator unsignedLongValue], [denominator unsignedLongValue]];
+ }
+ return str;
+}
+
+// split a floating point number into two integer values representing the left and right side of the decimal
+- (void) splitDouble: (double) val withIntComponent: (int*) rightside withFloatRemainder: (double*) leftside {
+ *rightside = val; // convert numb to int representation, which truncates the decimal portion
+ *leftside = val - *rightside;
+}
+
+
+//
+- (NSString*) hexStringFromData : (NSData*) data {
+ //overflow detection
+ const unsigned char *dataBuffer = [data bytes];
+ return [[NSString alloc] initWithFormat: @"%02x%02x",
+ (unsigned char)dataBuffer[0],
+ (unsigned char)dataBuffer[1]];
+}
+
+// convert a hex string to a number
+- (NSNumber*) numericFromHexString : (NSString *) hexstring {
+ NSScanner * scan = NULL;
+ unsigned int numbuf= 0;
+
+ scan = [NSScanner scannerWithString:hexstring];
+ [scan scanHexInt:&numbuf];
+ return [NSNumber numberWithInt:numbuf];
+}
+
+@end
[3/3] git commit: updated to include iOS config & js source files
config
Posted by he...@apache.org.
updated to include iOS config & js source files config
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/commit/c26377ae
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/tree/c26377ae
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/diff/c26377ae
Branch: refs/heads/master
Commit: c26377ae98e5dd807ad76fcbf73684b93af112af
Parents: 33c2270
Author: hermwong <he...@gmail.com>
Authored: Wed May 22 13:47:10 2013 -0700
Committer: hermwong <he...@gmail.com>
Committed: Wed May 22 13:47:10 2013 -0700
----------------------------------------------------------------------
plugin.xml | 31 +++++++++++++++++++++++++++++--
1 files changed, 29 insertions(+), 2 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/c26377ae/plugin.xml
----------------------------------------------------------------------
diff --git a/plugin.xml b/plugin.xml
index 035b487..a4c4362 100644
--- a/plugin.xml
+++ b/plugin.xml
@@ -2,10 +2,22 @@
<plugin xmlns="http://www.phonegap.com/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
-id="org.apache.cordova.core">
+id="org.apache.cordova.core"
version="0.1.0">
<name>Camera</name>
+ <js-module src="www/CameraConstants.js" name="camera">
+ <clobbers target="window.camera" />
+ </js-module>
+
+ <js-module src="www/CameraPopoverOptions.js" name="camera">
+ <clobbers target="window.camera" />
+ </js-module>
+
+ <js-module src="www/Camera.js" name="camera">
+ <clobbers target="navigator.camera" />
+ </js-module>
+
<!-- android -->
<platform name="android">
<config-file target="res/xml/config.xml" parent="/cordova/plugins">
@@ -13,5 +25,20 @@ id="org.apache.cordova.core">
</config-file>
<source-file src="CameraLauncher.java" target-dir="org/apache/cordova/core" />
- </platform>
+ </platform>
+
+ <!-- ios -->
+ <platform name="ios">
+ <config-file target="config.xml" parent="/*">
+ <feature name="Camera">
+ <param name="ios-package" value="CDVCamera" />
+ </feature>
+ </config-file>
+ <header-file src="src/ios/CDVCamera.h" />
+ <source-file src="src/ios/CDVCamera.m" />
+ <header-file src="src/ios/CDVJpegHeaderWriter.h" />
+ <source-file src="src/ios/CDVJpegHeaderWriter.m" />
+ <header-file src="src/ios/CDVExif.h" />
+ </platform>
+
</plugin>
[2/3] git commit: add Camera related JS files from Cordova-JS
Posted by he...@apache.org.
add Camera related JS files from Cordova-JS
Project: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/repo
Commit: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/commit/33c2270b
Tree: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/tree/33c2270b
Diff: http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/diff/33c2270b
Branch: refs/heads/master
Commit: 33c2270b6e936613ce31e5ff98459961046d1b7d
Parents: fc2c9bd
Author: hermwong <he...@gmail.com>
Authored: Tue May 21 12:11:20 2013 -0700
Committer: hermwong <he...@gmail.com>
Committed: Tue May 21 12:11:20 2013 -0700
----------------------------------------------------------------------
www/Camera.js | 73 ++++++++++++++++++++++++++++++++++++++
www/CameraConstants.js | 53 +++++++++++++++++++++++++++
www/CameraPopoverHandle.js | 33 +++++++++++++++++
www/CameraPopoverOptions.js | 37 +++++++++++++++++++
4 files changed, 196 insertions(+), 0 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/33c2270b/www/Camera.js
----------------------------------------------------------------------
diff --git a/www/Camera.js b/www/Camera.js
new file mode 100644
index 0000000..77f4a98
--- /dev/null
+++ b/www/Camera.js
@@ -0,0 +1,73 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+var argscheck = require('cordova/argscheck'),
+ exec = require('cordova/exec'),
+ Camera = require('org.apache.cordova.core.CameraConstants'),
+ CameraPopoverHandle = require('org.apache.cordova.core.CameraPopoverHandle');
+
+var cameraExport = {};
+
+// Tack on the Camera Constants to the base camera plugin.
+for (var key in Camera) {
+ cameraExport[key] = Camera[key];
+}
+
+/**
+ * Gets a picture from source defined by "options.sourceType", and returns the
+ * image as defined by the "options.destinationType" option.
+
+ * The defaults are sourceType=CAMERA and destinationType=FILE_URI.
+ *
+ * @param {Function} successCallback
+ * @param {Function} errorCallback
+ * @param {Object} options
+ */
+cameraExport.getPicture = function(successCallback, errorCallback, options) {
+ argscheck.checkArgs('fFO', 'Camera.getPicture', arguments);
+ options = options || {};
+ var getValue = argscheck.getValue;
+
+ var quality = getValue(options.quality, 50);
+ var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
+ var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
+ var targetWidth = getValue(options.targetWidth, -1);
+ var targetHeight = getValue(options.targetHeight, -1);
+ var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
+ var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
+ var allowEdit = !!options.allowEdit;
+ var correctOrientation = !!options.correctOrientation;
+ var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
+ var popoverOptions = getValue(options.popoverOptions, null);
+ var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
+
+ var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
+ mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
+
+ exec(successCallback, errorCallback, "Camera", "takePicture", args);
+ return new CameraPopoverHandle();
+};
+
+cameraExport.cleanup = function(successCallback, errorCallback) {
+ exec(successCallback, errorCallback, "Camera", "cleanup", []);
+};
+
+module.exports = cameraExport;
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/33c2270b/www/CameraConstants.js
----------------------------------------------------------------------
diff --git a/www/CameraConstants.js b/www/CameraConstants.js
new file mode 100644
index 0000000..ae4e534
--- /dev/null
+++ b/www/CameraConstants.js
@@ -0,0 +1,53 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+module.exports = {
+ DestinationType:{
+ DATA_URL: 0, // Return base64 encoded string
+ FILE_URI: 1, // Return file uri (content://media/external/images/media/2 for Android)
+ NATIVE_URI: 2 // Return native uri (eg. asset-library://... for iOS)
+ },
+ EncodingType:{
+ JPEG: 0, // Return JPEG encoded image
+ PNG: 1 // Return PNG encoded image
+ },
+ MediaType:{
+ PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType
+ VIDEO: 1, // allow selection of video only, ONLY RETURNS URL
+ ALLMEDIA : 2 // allow selection from all media types
+ },
+ PictureSourceType:{
+ PHOTOLIBRARY : 0, // Choose image from picture library (same as SAVEDPHOTOALBUM for Android)
+ CAMERA : 1, // Take picture from camera
+ SAVEDPHOTOALBUM : 2 // Choose image from picture library (same as PHOTOLIBRARY for Android)
+ },
+ PopoverArrowDirection:{
+ ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants to specify arrow location on popover
+ ARROW_DOWN : 2,
+ ARROW_LEFT : 4,
+ ARROW_RIGHT : 8,
+ ARROW_ANY : 15
+ },
+ Direction:{
+ BACK: 0,
+ FRONT: 1
+ }
+};
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/33c2270b/www/CameraPopoverHandle.js
----------------------------------------------------------------------
diff --git a/www/CameraPopoverHandle.js b/www/CameraPopoverHandle.js
new file mode 100644
index 0000000..7a4c32d
--- /dev/null
+++ b/www/CameraPopoverHandle.js
@@ -0,0 +1,33 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+var exec = require('cordova/exec');
+
+/**
+ * A handle to an image picker popover.
+ */
+var CameraPopoverHandle = function() {
+ this.setPosition = function(popoverOptions) {
+ console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
+ };
+};
+
+module.exports = CameraPopoverHandle;
http://git-wip-us.apache.org/repos/asf/cordova-plugin-camera/blob/33c2270b/www/CameraPopoverOptions.js
----------------------------------------------------------------------
diff --git a/www/CameraPopoverOptions.js b/www/CameraPopoverOptions.js
new file mode 100644
index 0000000..3df3745
--- /dev/null
+++ b/www/CameraPopoverOptions.js
@@ -0,0 +1,37 @@
+/*
+ *
+ * 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.
+ *
+*/
+
+var Camera = require('org.apache.cordova.core.CameraConstants');
+
+/**
+ * Encapsulates options for iOS Popover image picker
+ */
+var CameraPopoverOptions = function(x,y,width,height,arrowDir){
+ // information of rectangle that popover should be anchored to
+ this.x = x || 0;
+ this.y = y || 32;
+ this.width = width || 320;
+ this.height = height || 480;
+ // The direction of the popover arrow
+ this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
+};
+
+module.exports = CameraPopoverOptions;