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:&currentDataOffset];
+
+    //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:&currentDataOffset];
+    /*
+    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;