From 20aa744b556fee77536c6d52276e644442136115 Mon Sep 17 00:00:00 2001 From: Ian Clelland Date: Fri, 25 Apr 2014 14:09:46 -0400 Subject: [PATCH] CB-6521: Remove development branch --- LICENSE | 202 -------- NOTICE | 5 - README.md | 2 + RELEASENOTES.md | 82 --- doc/index.md | 441 ---------------- plugin.xml | 219 -------- src/android/CameraLauncher.java | 866 -------------------------------- src/android/ExifHelper.java | 185 ------- src/android/FileHelper.java | 158 ------ src/blackberry10/index.js | 129 ----- src/firefoxos/CameraProxy.js | 51 -- src/ios/CDVCamera.h | 102 ---- src/ios/CDVCamera.m | 756 ---------------------------- src/ios/CDVExif.h | 43 -- src/ios/CDVJpegHeaderWriter.h | 62 --- src/ios/CDVJpegHeaderWriter.m | 547 -------------------- src/ubuntu/CaptureWidget.qml | 119 ----- src/ubuntu/back.png | Bin 12428 -> 0 bytes src/ubuntu/camera.cpp | 143 ------ src/ubuntu/camera.h | 76 --- src/ubuntu/shoot.png | Bin 14430 -> 0 bytes src/ubuntu/toolbar-left.png | Bin 1212 -> 0 bytes src/ubuntu/toolbar-middle.png | Bin 4416 -> 0 bytes src/ubuntu/toolbar-right.png | Bin 1161 -> 0 bytes src/windows8/CameraProxy.js | 354 ------------- src/wp/Camera.cs | 515 ------------------- www/Camera.js | 75 --- www/CameraConstants.js | 53 -- www/CameraPopoverHandle.js | 33 -- www/CameraPopoverOptions.js | 37 -- www/ios/CameraPopoverHandle.js | 34 -- 31 files changed, 2 insertions(+), 5287 deletions(-) delete mode 100644 LICENSE delete mode 100644 NOTICE delete mode 100644 RELEASENOTES.md delete mode 100644 doc/index.md delete mode 100644 plugin.xml delete mode 100755 src/android/CameraLauncher.java delete mode 100644 src/android/ExifHelper.java delete mode 100644 src/android/FileHelper.java delete mode 100644 src/blackberry10/index.js delete mode 100644 src/firefoxos/CameraProxy.js delete mode 100644 src/ios/CDVCamera.h delete mode 100644 src/ios/CDVCamera.m delete mode 100644 src/ios/CDVExif.h delete mode 100644 src/ios/CDVJpegHeaderWriter.h delete mode 100644 src/ios/CDVJpegHeaderWriter.m delete mode 100644 src/ubuntu/CaptureWidget.qml delete mode 100644 src/ubuntu/back.png delete mode 100644 src/ubuntu/camera.cpp delete mode 100644 src/ubuntu/camera.h delete mode 100644 src/ubuntu/shoot.png delete mode 100644 src/ubuntu/toolbar-left.png delete mode 100644 src/ubuntu/toolbar-middle.png delete mode 100644 src/ubuntu/toolbar-right.png delete mode 100644 src/windows8/CameraProxy.js delete mode 100644 src/wp/Camera.cs delete mode 100644 www/Camera.js delete mode 100644 www/CameraConstants.js delete mode 100644 www/CameraPopoverHandle.js delete mode 100644 www/CameraPopoverOptions.js delete mode 100644 www/ios/CameraPopoverHandle.js diff --git a/LICENSE b/LICENSE deleted file mode 100644 index 7a4a3ea..0000000 --- a/LICENSE +++ /dev/null @@ -1,202 +0,0 @@ - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "[]" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright [yyyy] [name of copyright owner] - - Licensed 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. \ No newline at end of file diff --git a/NOTICE b/NOTICE deleted file mode 100644 index 8ec56a5..0000000 --- a/NOTICE +++ /dev/null @@ -1,5 +0,0 @@ -Apache Cordova -Copyright 2012 The Apache Software Foundation - -This product includes software developed at -The Apache Software Foundation (http://www.apache.org/). diff --git a/README.md b/README.md index f84180e..dcda226 100644 --- a/README.md +++ b/README.md @@ -20,3 +20,5 @@ # org.apache.cordova.camera Plugin documentation: [doc/index.md](doc/index.md) + +This is `dev` - the deprecated development branch of this plugin; development of this plugin has moved to the `master` branch diff --git a/RELEASENOTES.md b/RELEASENOTES.md deleted file mode 100644 index 836bc27..0000000 --- a/RELEASENOTES.md +++ /dev/null @@ -1,82 +0,0 @@ - -# Release Notes - -### 0.2.1 (Sept 5, 2013) -* [CB-4656] Don't add line-breaks to base64-encoded images (Fixes type=DataURI) -* [CB-4432] copyright notice change - -### 0.2.3 (Sept 25, 2013) -* CB-4889 bumping&resetting version -* CB-4889 forgot index.html -* CB-4889 renaming core inside cameraProxy -* [Windows8] commandProxy has moved -* [Windows8] commandProxy has moved -* added Camera API for FirefoxOS -* Rename CHANGELOG.md -> RELEASENOTES.md -* [CB-4823] Fix XCode 5 camera plugin warnings -* Fix compiler warnings -* [CB-4765] Move ExifHelper.java into Camera Plugin -* [CB-4764] Remove reference to DirectoryManager from CameraLauncher -* [CB-4763] Use a copy of FileHelper.java within camera-plugin. -* [CB-4752] Incremented plugin version on dev branch. -* CB-4633: We really should close cursors. It's just the right thing to do. -* No longer causes a stack trace, but it doesn't cause the error to be called. -* CB-4889 renaming org.apache.cordova.core.camera to org.apache.cordova.camera - - ### 0.2.4 (Oct 28, 2013) -* CB-5128: added repo + issue tag to plugin.xml for camera plugin -* CB-4958 - iOS - Camera plugin should not show the status bar -* [CB-4919] updated plugin.xml for FxOS -* [CB-4915] Incremented plugin version on dev branch. - -### 0.2.5 (Dec 4, 2013) -* fix camera for firefox os -* getPicture via web activities -* [ubuntu] specify policy_group -* add ubuntu platform -* 1. User Agent detection now detects AmazonWebView. 2. Change to use amazon-fireos as the platform if user agent string contains 'cordova-amazon-fireos' -* Added amazon-fireos platform. - -### 0.2.6 (Jan 02, 2014) -* CB-5658 Add doc/index.md for Camera plugin -* CB-2442 CB-2419 Use Windows.Storage.ApplicationData.current.localFolder, instead of writing to app package. -* [BlackBerry10] Adding platform level permissions -* CB-5599 Android: Catch and ignore OutOfMemoryError in getRotatedBitmap() - -### 0.2.7 (Feb 05, 2014) -* CB-4919 firefox os quirks added and supported platforms list is updated -* getPicture via web activities -* Documented quirk for CB-5335 + CB-5206 for WP7+8 -* reference the correct firefoxos implementation -* [BlackBerry10] Add permission to access_shared - -### 0.2.8 (Feb 26, 2014) -* CB-1826 Catch OOM on gallery image resize - -### 0.2.9 (Apr 17, 2014) -* CB-6460: Update license headers -* CB-6422: [windows8] use cordova/exec/proxy -* [WP8] When only targetWidth or targetHeight is provided, use it as the only bound -* CB-4027, CB-5102, CB-2737, CB-2387: [WP] Fix camera issues, cropping, memory leaks -* CB-6212: [iOS] fix warnings compiled under arm64 64-bit -* [BlackBerry10] Add rim xml namespaces declaration -* Add NOTICE file diff --git a/doc/index.md b/doc/index.md deleted file mode 100644 index edd881f..0000000 --- a/doc/index.md +++ /dev/null @@ -1,441 +0,0 @@ - - -# org.apache.cordova.camera - -This plugin provides an API for taking pictures and for choosing images from -the system's image library. - - cordova plugin add org.apache.cordova.camera - - -## navigator.camera.getPicture - -Takes a photo using the camera, or retrieves a photo from the device's -image gallery. The image is passed to the success callback as a -base64-encoded `String`, or as the URI for the image file. The method -itself returns a `CameraPopoverHandle` object that can be used to -reposition the file selection popover. - - navigator.camera.getPicture( cameraSuccess, cameraError, [ cameraOptions ] ); - -### Description - -The `camera.getPicture` function opens the device's default camera -application that allows users to snap pictures. This behavior occurs -by default, when `Camera.sourceType` equals -`Camera.PictureSourceType.CAMERA`. Once the user snaps the photo, the -camera application closes and the application is restored. - -If `Camera.sourceType` is `Camera.PictureSourceType.PHOTOLIBRARY` or -`Camera.PictureSourceType.SAVEDPHOTOALBUM`, then a dialog displays -that allows users to select an existing image. The -`camera.getPicture` function returns a `CameraPopoverHandle` object, -which can be used to reposition the image selection dialog, for -example, when the device orientation changes. - -The return value is sent to the `cameraSuccess` callback function, in -one of the following formats, depending on the specified -`cameraOptions`: - -- A `String` containing the base64-encoded photo image. - -- A `String` representing the image file location on local storage (default). - -You can do whatever you want with the encoded image or URI, for -example: - -- Render the image in an `` tag, as in the example below - -- Save the data locally (`LocalStorage`, [Lawnchair](http://brianleroux.github.com/lawnchair/), etc.) - -- Post the data to a remote server - -__NOTE__: Photo resolution on newer devices is quite good. Photos -selected from the device's gallery are not downscaled to a lower -quality, even if a `quality` parameter is specified. To avoid common -memory problems, set `Camera.destinationType` to `FILE_URI` rather -than `DATA_URL`. - -### Supported Platforms - -- Amazon Fire OS -- Android -- BlackBerry 10 -- Firefox OS -- iOS -- Tizen -- Windows Phone 7 and 8 -- Windows 8 - -### Amazon Fire OS Quirks - -Amazon Fire OS uses intents to launch the camera activity on the device to capture -images, and on phones with low memory, the Cordova activity may be killed. In this -scenario, the image may not appear when the cordova activity is restored. - -### Android Quirks - -*Android 4.4 only*: Android 4.4 introduced a new [Storage Access Framework](https://developer.android.com/guide/topics/providers/document-provider.html) that makes it -easier for users to browse and open documents across all of their preferred document storage providers. -Cordova has not yet been fully integrated with this new Storage Access Framework. Because of this, the `getPicture()` -method will not correctly return pictures when the user selects from the "Recent", "Drive", "Images", or "External -Storage" folders when the `destinationType` is `FILE_URI`. However, the user will be able to correctly select any pictures -if they go through the "Gallery" app first. Potential workarounds for this issue are documented on [this StackOverflow question](http://stackoverflow.com/questions/19834842/android-gallery-on-kitkat-returns-different-uri-for-intent-action-get-content/20177611). Please see [CB-5398](https://issues.apache.org/jira/browse/CB-5398) to track this issue. - -Android uses intents to launch the camera activity on the device to capture -images, and on phones with low memory, the Cordova activity may be killed. In this -scenario, the image may not appear when the Cordova activity is restored. - -### Firefox OS Quirks - -Camera plugin is currently implemented using [Web Activities](https://hacks.mozilla.org/2013/01/introducing-web-activities/). - -### iOS Quirks - -Including a JavaScript `alert()` in either of the callback functions -can cause problems. Wrap the alert within a `setTimeout()` to allow -the iOS image picker or popover to fully close before the alert -displays: - - setTimeout(function() { - // do your thing here! - }, 0); - -### Windows Phone 7 Quirks - -Invoking the native camera application while the device is connected -via Zune does not work, and triggers an error callback. - -### Tizen Quirks - -Tizen only supports a `destinationType` of -`Camera.DestinationType.FILE_URI` and a `sourceType` of -`Camera.PictureSourceType.PHOTOLIBRARY`. - -### Example - -Take a photo and retrieve it as a base64-encoded image: - - navigator.camera.getPicture(onSuccess, onFail, { quality: 50, - destinationType: Camera.DestinationType.DATA_URL - }); - - function onSuccess(imageData) { - var image = document.getElementById('myImage'); - image.src = "data:image/jpeg;base64," + imageData; - } - - function onFail(message) { - alert('Failed because: ' + message); - } - -Take a photo and retrieve the image's file location: - - navigator.camera.getPicture(onSuccess, onFail, { quality: 50, - destinationType: Camera.DestinationType.FILE_URI }); - - function onSuccess(imageURI) { - var image = document.getElementById('myImage'); - image.src = imageURI; - } - - function onFail(message) { - alert('Failed because: ' + message); - } - -## CameraOptions - -Optional parameters to customize the camera settings. - - { quality : 75, - destinationType : Camera.DestinationType.DATA_URL, - sourceType : Camera.PictureSourceType.CAMERA, - allowEdit : true, - encodingType: Camera.EncodingType.JPEG, - targetWidth: 100, - targetHeight: 100, - popoverOptions: CameraPopoverOptions, - saveToPhotoAlbum: false }; - -### Options - -- __quality__: Quality of the saved image, expressed as a range of 0-100, where 100 is typically full resolution with no loss from file compression. _(Number)_ (Note that information about the camera's resolution is unavailable.) - -- __destinationType__: Choose the format of the return value. Defined in `navigator.camera.DestinationType` _(Number)_ - - Camera.DestinationType = { - DATA_URL : 0, // Return image as base64-encoded string - FILE_URI : 1, // Return image file URI - NATIVE_URI : 2 // Return image native URI (e.g., assets-library:// on iOS or content:// on Android) - }; - -- __sourceType__: Set the source of the picture. Defined in `navigator.camera.PictureSourceType` _(Number)_ - - Camera.PictureSourceType = { - PHOTOLIBRARY : 0, - CAMERA : 1, - SAVEDPHOTOALBUM : 2 - }; - -- __allowEdit__: Allow simple editing of image before selection. _(Boolean)_ - -- __encodingType__: Choose the returned image file's encoding. Defined in `navigator.camera.EncodingType` _(Number)_ - - Camera.EncodingType = { - JPEG : 0, // Return JPEG encoded image - PNG : 1 // Return PNG encoded image - }; - -- __targetWidth__: Width in pixels to scale image. Must be used with __targetHeight__. Aspect ratio remains constant. _(Number)_ - -- __targetHeight__: Height in pixels to scale image. Must be used with __targetWidth__. Aspect ratio remains constant. _(Number)_ - -- __mediaType__: Set the type of media to select from. Only works when `PictureSourceType` is `PHOTOLIBRARY` or `SAVEDPHOTOALBUM`. Defined in `nagivator.camera.MediaType` _(Number)_ - - Camera.MediaType = { - PICTURE: 0, // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType - VIDEO: 1, // allow selection of video only, WILL ALWAYS RETURN FILE_URI - ALLMEDIA : 2 // allow selection from all media types -}; - -- __correctOrientation__: Rotate the image to correct for the orientation of the device during capture. _(Boolean)_ - -- __saveToPhotoAlbum__: Save the image to the photo album on the device after capture. _(Boolean)_ - -- __popoverOptions__: iOS-only options that specify popover location in iPad. Defined in `CameraPopoverOptions`. - -- __cameraDirection__: Choose the camera to use (front- or back-facing). Defined in `navigator.camera.Direction` _(Number)_ - - Camera.Direction = { - BACK : 0, // Use the back-facing camera - FRONT : 1 // Use the front-facing camera - }; - -### Amazon Fire OSQuirks - -- Any `cameraDirection` value results in a back-facing photo. - -- Ignores the `allowEdit` parameter. - -- `Camera.PictureSourceType.PHOTOLIBRARY` and `Camera.PictureSourceType.SAVEDPHOTOALBUM` both display the same photo album. - -### Android Quirks - -- Any `cameraDirection` value results in a back-facing photo. - -- Ignores the `allowEdit` parameter. - -- `Camera.PictureSourceType.PHOTOLIBRARY` and `Camera.PictureSourceType.SAVEDPHOTOALBUM` both display the same photo album. - -### BlackBerry 10 Quirks - -- Ignores the `quality` parameter. - -- Ignores the `sourceType` parameter. - -- Ignores the `allowEdit` parameter. - -- `Camera.MediaType` is not supported. - -- Ignores the `correctOrientation` parameter. - -- Ignores the `cameraDirection` parameter. - -### Firefox OS Quirks - -- Ignores the `quality` parameter. - -- `Camera.DestinationType` is ignored and equals `1` (image file URI) - -- Ignores the `allowEdit` parameter. - -- Ignores the `PictureSourceType` parameter (user chooses it in a dialog window) - -- Ignores the `encodingType` - -- Ignores the `targetWidth` and `targetHeight` - -- `Camera.MediaType` is not supported. - -- Ignores the `correctOrientation` parameter. - -- Ignores the `cameraDirection` parameter. - -### iOS Quirks - -- Set `quality` below 50 to avoid memory errors on some devices. - -- When using `destinationType.FILE_URI`, photos are saved in the application's temporary directory. You may delete the contents of this directory using the `navigator.fileMgr` APIs if storage space is a concern. - -### Tizen Quirks - -- options not supported - -- always returns a FILE URI - -### Windows Phone 7 and 8 Quirks - -- Ignores the `allowEdit` parameter. - -- Ignores the `correctOrientation` parameter. - -- Ignores the `cameraDirection` parameter. - -- Ignores the `mediaType` property of `cameraOptions` as the Windows Phone SDK does not provide a way to choose videos from PHOTOLIBRARY. - - -## CameraError - -onError callback function that provides an error message. - - function(message) { - // Show a helpful message - } - -### Parameters - -- __message__: The message is provided by the device's native code. _(String)_ - - -## cameraSuccess - -onSuccess callback function that provides the image data. - - function(imageData) { - // Do something with the image - } - -### Parameters - -- __imageData__: Base64 encoding of the image data, _or_ the image file URI, depending on `cameraOptions` in effect. _(String)_ - -### Example - - // Show image - // - function cameraCallback(imageData) { - var image = document.getElementById('myImage'); - image.src = "data:image/jpeg;base64," + imageData; - } - - -## CameraPopoverHandle - -A handle to the popover dialog created by `navigator.camera.getPicture`. - -### Methods - -- __setPosition__: Set the position of the popover. - -### Supported Platforms - -- iOS - -### setPosition - -Set the position of the popover. - -__Parameters__: - -- `cameraPopoverOptions`: the `CameraPopoverOptions` that specify the new position - -### Example - - var cameraPopoverHandle = navigator.camera.getPicture(onSuccess, onFail, - { destinationType: Camera.DestinationType.FILE_URI, - sourceType: Camera.PictureSourceType.PHOTOLIBRARY, - popoverOptions: new CameraPopoverOptions(300, 300, 100, 100, Camera.PopoverArrowDirection.ARROW_ANY) - }); - - // Reposition the popover if the orientation changes. - window.onorientationchange = function() { - var cameraPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, Camera.PopoverArrowDirection.ARROW_ANY); - cameraPopoverHandle.setPosition(cameraPopoverOptions); - } - - -## CameraPopoverOptions - -iOS-only parameters that specify the anchor element location and arrow -direction of the popover when selecting images from an iPad's library -or album. - - { x : 0, - y : 32, - width : 320, - height : 480, - arrowDir : Camera.PopoverArrowDirection.ARROW_ANY - }; - -### CameraPopoverOptions - -- __x__: x pixel coordinate of screen element onto which to anchor the popover. _(Number)_ - -- __y__: y pixel coordinate of screen element onto which to anchor the popover. _(Number)_ - -- __width__: width, in pixels, of the screen element onto which to anchor the popover. _(Number)_ - -- __height__: height, in pixels, of the screen element onto which to anchor the popover. _(Number)_ - -- __arrowDir__: Direction the arrow on the popover should point. Defined in `Camera.PopoverArrowDirection` _(Number)_ - - Camera.PopoverArrowDirection = { - ARROW_UP : 1, // matches iOS UIPopoverArrowDirection constants - ARROW_DOWN : 2, - ARROW_LEFT : 4, - ARROW_RIGHT : 8, - ARROW_ANY : 15 - }; - -Note that the size of the popover may change to adjust to the -direction of the arrow and orientation of the screen. Make sure to -account for orientation changes when specifying the anchor element -location. - -## navigator.camera.cleanup - -Removes intermediate photos taken by the camera from temporary -storage. - - navigator.camera.cleanup( cameraSuccess, cameraError ); - -### Description - -Removes intermediate image files that are kept in temporary storage -after calling `camera.getPicture`. Applies only when the value of -`Camera.sourceType` equals `Camera.PictureSourceType.CAMERA` and the -`Camera.destinationType` equals `Camera.DestinationType.FILE_URI`. - -### Supported Platforms - -- iOS - -### Example - - navigator.camera.cleanup(onSuccess, onFail); - - function onSuccess() { - console.log("Camera cleanup success.") - } - - function onFail(message) { - alert('Failed because: ' + message); - } - diff --git a/plugin.xml b/plugin.xml deleted file mode 100644 index a51f172..0000000 --- a/plugin.xml +++ /dev/null @@ -1,219 +0,0 @@ - - - - - Camera - Cordova Camera Plugin - Apache 2.0 - cordova,camera - https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git - https://issues.apache.org/jira/browse/CB/component/12320645 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - access_shared - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/android/CameraLauncher.java b/src/android/CameraLauncher.java deleted file mode 100755 index 57878ab..0000000 --- a/src/android/CameraLauncher.java +++ /dev/null @@ -1,866 +0,0 @@ -/* - 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. -*/ -package org.apache.cordova.camera; - -import java.io.ByteArrayOutputStream; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; -import java.io.FileOutputStream; -import java.io.IOException; -import java.io.OutputStream; - -import org.apache.cordova.CallbackContext; -import org.apache.cordova.CordovaPlugin; -import org.apache.cordova.LOG; -import org.apache.cordova.PluginResult; -import org.json.JSONArray; -import org.json.JSONException; - -import android.app.Activity; -import android.content.ContentValues; -import android.content.Intent; -import android.database.Cursor; -import android.graphics.Bitmap; -import android.graphics.BitmapFactory; -import android.graphics.Matrix; -import android.graphics.Bitmap.CompressFormat; -import android.media.MediaScannerConnection; -import android.media.MediaScannerConnection.MediaScannerConnectionClient; -import android.net.Uri; -import android.os.Environment; -import android.provider.MediaStore; -import android.util.Base64; -import android.util.Log; - -/** - * This class launches the camera view, allows the user to take a picture, closes the camera view, - * and returns the captured image. When the camera view is closed, the screen displayed before - * the camera view was shown is redisplayed. - */ -public class CameraLauncher extends CordovaPlugin implements MediaScannerConnectionClient { - - private static final int DATA_URL = 0; // Return base64 encoded string - private static final int FILE_URI = 1; // Return file uri (content://media/external/images/media/2 for Android) - private static final int NATIVE_URI = 2; // On Android, this is the same as FILE_URI - - private static final int PHOTOLIBRARY = 0; // Choose image from picture library (same as SAVEDPHOTOALBUM for Android) - private static final int CAMERA = 1; // Take picture from camera - private static final int SAVEDPHOTOALBUM = 2; // Choose image from picture library (same as PHOTOLIBRARY for Android) - - private static final int PICTURE = 0; // allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType - private static final int VIDEO = 1; // allow selection of video only, ONLY RETURNS URL - private static final int ALLMEDIA = 2; // allow selection from all media types - - private static final int JPEG = 0; // Take a picture of type JPEG - private static final int PNG = 1; // Take a picture of type PNG - private static final String GET_PICTURE = "Get Picture"; - private static final String GET_VIDEO = "Get Video"; - private static final String GET_All = "Get All"; - - private static final String LOG_TAG = "CameraLauncher"; - - private int mQuality; // Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) - private int targetWidth; // desired width of the image - private int targetHeight; // desired height of the image - private Uri imageUri; // Uri of captured image - private int encodingType; // Type of encoding to use - private int mediaType; // What type of media to retrieve - private boolean saveToPhotoAlbum; // Should the picture be saved to the device's photo album - private boolean correctOrientation; // Should the pictures orientation be corrected - private boolean orientationCorrected; // Has the picture's orientation been corrected - //private boolean allowEdit; // Should we allow the user to crop the image. UNUSED. - - public CallbackContext callbackContext; - private int numPics; - - private MediaScannerConnection conn; // Used to update gallery app with newly-written files - private Uri scanMe; // Uri of image to be added to content store - - /** - * Executes the request and returns PluginResult. - * - * @param action The action to execute. - * @param args JSONArry of arguments for the plugin. - * @param callbackContext The callback id used when calling back into JavaScript. - * @return A PluginResult object with a status and message. - */ - public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException { - this.callbackContext = callbackContext; - - if (action.equals("takePicture")) { - int srcType = CAMERA; - int destType = FILE_URI; - this.saveToPhotoAlbum = false; - this.targetHeight = 0; - this.targetWidth = 0; - this.encodingType = JPEG; - this.mediaType = PICTURE; - this.mQuality = 80; - - this.mQuality = args.getInt(0); - destType = args.getInt(1); - srcType = args.getInt(2); - this.targetWidth = args.getInt(3); - this.targetHeight = args.getInt(4); - this.encodingType = args.getInt(5); - this.mediaType = args.getInt(6); - //this.allowEdit = args.getBoolean(7); // This field is unused. - this.correctOrientation = args.getBoolean(8); - this.saveToPhotoAlbum = args.getBoolean(9); - - // If the user specifies a 0 or smaller width/height - // make it -1 so later comparisons succeed - if (this.targetWidth < 1) { - this.targetWidth = -1; - } - if (this.targetHeight < 1) { - this.targetHeight = -1; - } - - try { - if (srcType == CAMERA) { - this.takePicture(destType, encodingType); - } - else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) { - this.getImage(srcType, destType); - } - } - catch (IllegalArgumentException e) - { - callbackContext.error("Illegal Argument Exception"); - PluginResult r = new PluginResult(PluginResult.Status.ERROR); - callbackContext.sendPluginResult(r); - return true; - } - - PluginResult r = new PluginResult(PluginResult.Status.NO_RESULT); - r.setKeepCallback(true); - callbackContext.sendPluginResult(r); - - return true; - } - return false; - } - - //-------------------------------------------------------------------------- - // LOCAL METHODS - //-------------------------------------------------------------------------- - - private String getTempDirectoryPath() { - File cache = null; - - // SD Card Mounted - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - cache = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + - "/Android/data/" + cordova.getActivity().getPackageName() + "/cache/"); - } - // Use internal storage - else { - cache = cordova.getActivity().getCacheDir(); - } - - // Create the cache directory if it doesn't exist - cache.mkdirs(); - return cache.getAbsolutePath(); - } - - /** - * Take a picture with the camera. - * When an image is captured or the camera view is cancelled, the result is returned - * in CordovaActivity.onActivityResult, which forwards the result to this.onActivityResult. - * - * The image can either be returned as a base64 string or a URI that points to the file. - * To display base64 string in an img tag, set the source to: - * img.src="data:image/jpeg;base64,"+result; - * or to display URI in an img tag - * img.src=result; - * - * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) - * @param returnType Set the type of image to return. - */ - public void takePicture(int returnType, int encodingType) { - // Save the number of images currently on disk for later - this.numPics = queryImgDB(whichContentStore()).getCount(); - - // Display camera - Intent intent = new Intent("android.media.action.IMAGE_CAPTURE"); - - // Specify file so that large image is captured and returned - File photo = createCaptureFile(encodingType); - intent.putExtra(android.provider.MediaStore.EXTRA_OUTPUT, Uri.fromFile(photo)); - this.imageUri = Uri.fromFile(photo); - - if (this.cordova != null) { - this.cordova.startActivityForResult((CordovaPlugin) this, intent, (CAMERA + 1) * 16 + returnType + 1); - } -// else -// LOG.d(LOG_TAG, "ERROR: You must use the CordovaInterface for this to work correctly. Please implement it in your activity"); - } - - /** - * Create a file in the applications temporary directory based upon the supplied encoding. - * - * @param encodingType of the image to be taken - * @return a File object pointing to the temporary picture - */ - private File createCaptureFile(int encodingType) { - File photo = null; - if (encodingType == JPEG) { - photo = new File(getTempDirectoryPath(), ".Pic.jpg"); - } else if (encodingType == PNG) { - photo = new File(getTempDirectoryPath(), ".Pic.png"); - } else { - throw new IllegalArgumentException("Invalid Encoding Type: " + encodingType); - } - return photo; - } - - /** - * Get image from photo library. - * - * @param quality Compression quality hint (0-100: 0=low quality & high compression, 100=compress of max quality) - * @param srcType The album to get image from. - * @param returnType Set the type of image to return. - */ - // TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do! - public void getImage(int srcType, int returnType) { - Intent intent = new Intent(); - String title = GET_PICTURE; - if (this.mediaType == PICTURE) { - intent.setType("image/*"); - } - else if (this.mediaType == VIDEO) { - intent.setType("video/*"); - title = GET_VIDEO; - } - else if (this.mediaType == ALLMEDIA) { - // I wanted to make the type 'image/*, video/*' but this does not work on all versions - // of android so I had to go with the wildcard search. - intent.setType("*/*"); - title = GET_All; - } - - intent.setAction(Intent.ACTION_GET_CONTENT); - intent.addCategory(Intent.CATEGORY_OPENABLE); - if (this.cordova != null) { - this.cordova.startActivityForResult((CordovaPlugin) this, Intent.createChooser(intent, - new String(title)), (srcType + 1) * 16 + returnType + 1); - } - } - - /** - * Applies all needed transformation to the image received from the camera. - * - * @param destType In which form should we return the image - * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). - */ - private void processResultFromCamera(int destType, Intent intent) throws IOException { - int rotate = 0; - - // Create an ExifHelper to save the exif data that is lost during compression - ExifHelper exif = new ExifHelper(); - try { - if (this.encodingType == JPEG) { - exif.createInFile(getTempDirectoryPath() + "/.Pic.jpg"); - exif.readExifData(); - rotate = exif.getOrientation(); - } - } catch (IOException e) { - e.printStackTrace(); - } - - Bitmap bitmap = null; - Uri uri = null; - - // If sending base64 image back - if (destType == DATA_URL) { - bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString())); - if (bitmap == null) { - // Try to get the bitmap from intent. - bitmap = (Bitmap)intent.getExtras().get("data"); - } - - // Double-check the bitmap. - if (bitmap == null) { - Log.d(LOG_TAG, "I either have a null image path or bitmap"); - this.failPicture("Unable to create bitmap!"); - return; - } - - if (rotate != 0 && this.correctOrientation) { - bitmap = getRotatedBitmap(rotate, bitmap, exif); - } - - this.processPicture(bitmap); - checkForDuplicateImage(DATA_URL); - } - - // If sending filename back - else if (destType == FILE_URI || destType == NATIVE_URI) { - if (this.saveToPhotoAlbum) { - Uri inputUri = getUriFromMediaStore(); - //Just because we have a media URI doesn't mean we have a real file, we need to make it - uri = Uri.fromFile(new File(FileHelper.getRealPath(inputUri, this.cordova))); - } else { - uri = Uri.fromFile(new File(getTempDirectoryPath(), System.currentTimeMillis() + ".jpg")); - } - - if (uri == null) { - this.failPicture("Error capturing image - no media storage found."); - } - - // If all this is true we shouldn't compress the image. - if (this.targetHeight == -1 && this.targetWidth == -1 && this.mQuality == 100 && - !this.correctOrientation) { - writeUncompressedImage(uri); - - this.callbackContext.success(uri.toString()); - } else { - bitmap = getScaledBitmap(FileHelper.stripFileProtocol(imageUri.toString())); - - if (rotate != 0 && this.correctOrientation) { - bitmap = getRotatedBitmap(rotate, bitmap, exif); - } - - // Add compressed version of captured image to returned media store Uri - OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri); - bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os); - os.close(); - - // Restore exif data to file - if (this.encodingType == JPEG) { - String exifPath; - if (this.saveToPhotoAlbum) { - exifPath = FileHelper.getRealPath(uri, this.cordova); - } else { - exifPath = uri.getPath(); - } - exif.createOutFile(exifPath); - exif.writeExifData(); - } - - } - // Send Uri back to JavaScript for viewing image - this.callbackContext.success(uri.toString()); - } - - this.cleanup(FILE_URI, this.imageUri, uri, bitmap); - bitmap = null; - } - - private String ouputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException { - // Create an ExifHelper to save the exif data that is lost during compression - String modifiedPath = getTempDirectoryPath() + "/modified.jpg"; - - OutputStream os = new FileOutputStream(modifiedPath); - bitmap.compress(Bitmap.CompressFormat.JPEG, this.mQuality, os); - os.close(); - - // Some content: URIs do not map to file paths (e.g. picasa). - String realPath = FileHelper.getRealPath(uri, this.cordova); - ExifHelper exif = new ExifHelper(); - if (realPath != null && this.encodingType == JPEG) { - try { - exif.createInFile(realPath); - exif.readExifData(); - if (this.correctOrientation && this.orientationCorrected) { - exif.resetOrientation(); - } - exif.createOutFile(modifiedPath); - exif.writeExifData(); - } catch (IOException e) { - e.printStackTrace(); - } - } - return modifiedPath; - } - - /** - * Applies all needed transformation to the image received from the gallery. - * - * @param destType In which form should we return the image - * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). - */ - private void processResultFromGallery(int destType, Intent intent) { - Uri uri = intent.getData(); - int rotate = 0; - - // If you ask for video or all media type you will automatically get back a file URI - // and there will be no attempt to resize any returned data - if (this.mediaType != PICTURE) { - this.callbackContext.success(uri.toString()); - } - else { - // This is a special case to just return the path as no scaling, - // rotating, nor compressing needs to be done - if (this.targetHeight == -1 && this.targetWidth == -1 && - (destType == FILE_URI || destType == NATIVE_URI) && !this.correctOrientation) { - this.callbackContext.success(uri.toString()); - } else { - String uriString = uri.toString(); - // Get the path to the image. Makes loading so much easier. - String mimeType = FileHelper.getMimeType(uriString, this.cordova); - // If we don't have a valid image so quit. - if (!("image/jpeg".equalsIgnoreCase(mimeType) || "image/png".equalsIgnoreCase(mimeType))) { - Log.d(LOG_TAG, "I either have a null image path or bitmap"); - this.failPicture("Unable to retrieve path to picture!"); - return; - } - Bitmap bitmap = null; - try { - bitmap = getScaledBitmap(uriString); - } catch (IOException e) { - e.printStackTrace(); - } - if (bitmap == null) { - Log.d(LOG_TAG, "I either have a null image path or bitmap"); - this.failPicture("Unable to create bitmap!"); - return; - } - - if (this.correctOrientation) { - rotate = getImageOrientation(uri); - if (rotate != 0) { - Matrix matrix = new Matrix(); - matrix.setRotate(rotate); - try { - bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); - this.orientationCorrected = true; - } catch (OutOfMemoryError oom) { - this.orientationCorrected = false; - } - } - } - - // If sending base64 image back - if (destType == DATA_URL) { - this.processPicture(bitmap); - } - - // If sending filename back - else if (destType == FILE_URI || destType == NATIVE_URI) { - // Did we modify the image? - if ( (this.targetHeight > 0 && this.targetWidth > 0) || - (this.correctOrientation && this.orientationCorrected) ) { - try { - String modifiedPath = this.ouputModifiedBitmap(bitmap, uri); - // The modified image is cached by the app in order to get around this and not have to delete you - // application cache I'm adding the current system time to the end of the file url. - this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis()); - } catch (Exception e) { - e.printStackTrace(); - this.failPicture("Error retrieving image."); - } - } - else { - this.callbackContext.success(uri.toString()); - } - } - if (bitmap != null) { - bitmap.recycle(); - bitmap = null; - } - System.gc(); - } - } - } - - /** - * Called when the camera view exits. - * - * @param requestCode The request code originally supplied to startActivityForResult(), - * allowing you to identify who this result came from. - * @param resultCode The integer result code returned by the child activity through its setResult(). - * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras"). - */ - public void onActivityResult(int requestCode, int resultCode, Intent intent) { - - // Get src and dest types from request code - int srcType = (requestCode / 16) - 1; - int destType = (requestCode % 16) - 1; - - // If CAMERA - if (srcType == CAMERA) { - // If image available - if (resultCode == Activity.RESULT_OK) { - try { - this.processResultFromCamera(destType, intent); - } catch (IOException e) { - e.printStackTrace(); - this.failPicture("Error capturing image."); - } - } - - // If cancelled - else if (resultCode == Activity.RESULT_CANCELED) { - this.failPicture("Camera cancelled."); - } - - // If something else - else { - this.failPicture("Did not complete!"); - } - } - - // If retrieving photo from library - else if ((srcType == PHOTOLIBRARY) || (srcType == SAVEDPHOTOALBUM)) { - if (resultCode == Activity.RESULT_OK) { - this.processResultFromGallery(destType, intent); - } - else if (resultCode == Activity.RESULT_CANCELED) { - this.failPicture("Selection cancelled."); - } - else { - this.failPicture("Selection did not complete!"); - } - } - } - - private int getImageOrientation(Uri uri) { - int rotate = 0; - String[] cols = { MediaStore.Images.Media.ORIENTATION }; - try { - Cursor cursor = cordova.getActivity().getContentResolver().query(uri, - cols, null, null, null); - if (cursor != null) { - cursor.moveToPosition(0); - rotate = cursor.getInt(0); - cursor.close(); - } - } catch (Exception e) { - // You can get an IllegalArgumentException if ContentProvider doesn't support querying for orientation. - } - return rotate; - } - - /** - * Figure out if the bitmap should be rotated. For instance if the picture was taken in - * portrait mode - * - * @param rotate - * @param bitmap - * @return rotated bitmap - */ - private Bitmap getRotatedBitmap(int rotate, Bitmap bitmap, ExifHelper exif) { - Matrix matrix = new Matrix(); - if (rotate == 180) { - matrix.setRotate(rotate); - } else { - matrix.setRotate(rotate, (float) bitmap.getWidth() / 2, (float) bitmap.getHeight() / 2); - } - - try - { - bitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); - exif.resetOrientation(); - } - catch (OutOfMemoryError oom) - { - // You can run out of memory if the image is very large: - // http://simonmacdonald.blogspot.ca/2012/07/change-to-camera-code-in-phonegap-190.html - // If this happens, simply do not rotate the image and return it unmodified. - // If you do not catch the OutOfMemoryError, the Android app crashes. - } - - return bitmap; - } - - /** - * In the special case where the default width, height and quality are unchanged - * we just write the file out to disk saving the expensive Bitmap.compress function. - * - * @param uri - * @throws FileNotFoundException - * @throws IOException - */ - private void writeUncompressedImage(Uri uri) throws FileNotFoundException, - IOException { - FileInputStream fis = new FileInputStream(FileHelper.stripFileProtocol(imageUri.toString())); - OutputStream os = this.cordova.getActivity().getContentResolver().openOutputStream(uri); - byte[] buffer = new byte[4096]; - int len; - while ((len = fis.read(buffer)) != -1) { - os.write(buffer, 0, len); - } - os.flush(); - os.close(); - fis.close(); - } - - /** - * Create entry in media store for image - * - * @return uri - */ - private Uri getUriFromMediaStore() { - ContentValues values = new ContentValues(); - values.put(android.provider.MediaStore.Images.Media.MIME_TYPE, "image/jpeg"); - Uri uri; - try { - uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values); - } catch (UnsupportedOperationException e) { - LOG.d(LOG_TAG, "Can't write to external media storage."); - try { - uri = this.cordova.getActivity().getContentResolver().insert(android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI, values); - } catch (UnsupportedOperationException ex) { - LOG.d(LOG_TAG, "Can't write to internal media storage."); - return null; - } - } - return uri; - } - - /** - * Return a scaled bitmap based on the target width and height - * - * @param imagePath - * @return - * @throws IOException - */ - private Bitmap getScaledBitmap(String imageUrl) throws IOException { - // If no new width or height were specified return the original bitmap - if (this.targetWidth <= 0 && this.targetHeight <= 0) { - return BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova)); - } - - // figure out the original width and height of the image - BitmapFactory.Options options = new BitmapFactory.Options(); - options.inJustDecodeBounds = true; - BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options); - - //CB-2292: WTF? Why is the width null? - if(options.outWidth == 0 || options.outHeight == 0) - { - return null; - } - - // determine the correct aspect ratio - int[] widthHeight = calculateAspectRatio(options.outWidth, options.outHeight); - - // Load in the smallest bitmap possible that is closest to the size we want - options.inJustDecodeBounds = false; - options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, this.targetWidth, this.targetHeight); - Bitmap unscaledBitmap = BitmapFactory.decodeStream(FileHelper.getInputStreamFromUriString(imageUrl, cordova), null, options); - if (unscaledBitmap == null) { - return null; - } - - return Bitmap.createScaledBitmap(unscaledBitmap, widthHeight[0], widthHeight[1], true); - } - - /** - * Maintain the aspect ratio so the resulting image does not look smooshed - * - * @param origWidth - * @param origHeight - * @return - */ - public int[] calculateAspectRatio(int origWidth, int origHeight) { - int newWidth = this.targetWidth; - int newHeight = this.targetHeight; - - // If no new width or height were specified return the original bitmap - if (newWidth <= 0 && newHeight <= 0) { - newWidth = origWidth; - newHeight = origHeight; - } - // Only the width was specified - else if (newWidth > 0 && newHeight <= 0) { - newHeight = (newWidth * origHeight) / origWidth; - } - // only the height was specified - else if (newWidth <= 0 && newHeight > 0) { - newWidth = (newHeight * origWidth) / origHeight; - } - // If the user specified both a positive width and height - // (potentially different aspect ratio) then the width or height is - // scaled so that the image fits while maintaining aspect ratio. - // Alternatively, the specified width and height could have been - // kept and Bitmap.SCALE_TO_FIT specified when scaling, but this - // would result in whitespace in the new image. - else { - double newRatio = newWidth / (double) newHeight; - double origRatio = origWidth / (double) origHeight; - - if (origRatio > newRatio) { - newHeight = (newWidth * origHeight) / origWidth; - } else if (origRatio < newRatio) { - newWidth = (newHeight * origWidth) / origHeight; - } - } - - int[] retval = new int[2]; - retval[0] = newWidth; - retval[1] = newHeight; - return retval; - } - - /** - * Figure out what ratio we can load our image into memory at while still being bigger than - * our desired width and height - * - * @param srcWidth - * @param srcHeight - * @param dstWidth - * @param dstHeight - * @return - */ - public static int calculateSampleSize(int srcWidth, int srcHeight, int dstWidth, int dstHeight) { - final float srcAspect = (float)srcWidth / (float)srcHeight; - final float dstAspect = (float)dstWidth / (float)dstHeight; - - if (srcAspect > dstAspect) { - return srcWidth / dstWidth; - } else { - return srcHeight / dstHeight; - } - } - - /** - * Creates a cursor that can be used to determine how many images we have. - * - * @return a cursor - */ - private Cursor queryImgDB(Uri contentStore) { - return this.cordova.getActivity().getContentResolver().query( - contentStore, - new String[] { MediaStore.Images.Media._ID }, - null, - null, - null); - } - - /** - * Cleans up after picture taking. Checking for duplicates and that kind of stuff. - * @param newImage - */ - private void cleanup(int imageType, Uri oldImage, Uri newImage, Bitmap bitmap) { - if (bitmap != null) { - bitmap.recycle(); - } - - // Clean up initial camera-written image file. - (new File(FileHelper.stripFileProtocol(oldImage.toString()))).delete(); - - checkForDuplicateImage(imageType); - // Scan for the gallery to update pic refs in gallery - if (this.saveToPhotoAlbum && newImage != null) { - this.scanForGallery(newImage); - } - - System.gc(); - } - - /** - * Used to find out if we are in a situation where the Camera Intent adds to images - * to the content store. If we are using a FILE_URI and the number of images in the DB - * increases by 2 we have a duplicate, when using a DATA_URL the number is 1. - * - * @param type FILE_URI or DATA_URL - */ - private void checkForDuplicateImage(int type) { - int diff = 1; - Uri contentStore = whichContentStore(); - Cursor cursor = queryImgDB(contentStore); - int currentNumOfImages = cursor.getCount(); - - if (type == FILE_URI && this.saveToPhotoAlbum) { - diff = 2; - } - - // delete the duplicate file if the difference is 2 for file URI or 1 for Data URL - if ((currentNumOfImages - numPics) == diff) { - cursor.moveToLast(); - int id = Integer.valueOf(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media._ID))); - if (diff == 2) { - id--; - } - Uri uri = Uri.parse(contentStore + "/" + id); - this.cordova.getActivity().getContentResolver().delete(uri, null, null); - cursor.close(); - } - } - - /** - * Determine if we are storing the images in internal or external storage - * @return Uri - */ - private Uri whichContentStore() { - if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) { - return android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI; - } else { - return android.provider.MediaStore.Images.Media.INTERNAL_CONTENT_URI; - } - } - - /** - * Compress bitmap using jpeg, convert to Base64 encoded string, and return to JavaScript. - * - * @param bitmap - */ - public void processPicture(Bitmap bitmap) { - ByteArrayOutputStream jpeg_data = new ByteArrayOutputStream(); - try { - if (bitmap.compress(CompressFormat.JPEG, mQuality, jpeg_data)) { - byte[] code = jpeg_data.toByteArray(); - byte[] output = Base64.encode(code, Base64.NO_WRAP); - String js_out = new String(output); - this.callbackContext.success(js_out); - js_out = null; - output = null; - code = null; - } - } catch (Exception e) { - this.failPicture("Error compressing image."); - } - jpeg_data = null; - } - - /** - * Send error message to JavaScript. - * - * @param err - */ - public void failPicture(String err) { - this.callbackContext.error(err); - } - - private void scanForGallery(Uri newImage) { - this.scanMe = newImage; - if(this.conn != null) { - this.conn.disconnect(); - } - this.conn = new MediaScannerConnection(this.cordova.getActivity().getApplicationContext(), this); - conn.connect(); - } - - public void onMediaScannerConnected() { - try{ - this.conn.scanFile(this.scanMe.toString(), "image/*"); - } catch (java.lang.IllegalStateException e){ - LOG.e(LOG_TAG, "Can't scan file in MediaScanner after taking picture"); - } - - } - - public void onScanCompleted(String path, Uri uri) { - this.conn.disconnect(); - } -} diff --git a/src/android/ExifHelper.java b/src/android/ExifHelper.java deleted file mode 100644 index 5160a2f..0000000 --- a/src/android/ExifHelper.java +++ /dev/null @@ -1,185 +0,0 @@ -/* - 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. -*/ -package org.apache.cordova.camera; - -import java.io.IOException; - -import android.media.ExifInterface; - -public class ExifHelper { - private String aperture = null; - private String datetime = null; - private String exposureTime = null; - private String flash = null; - private String focalLength = null; - private String gpsAltitude = null; - private String gpsAltitudeRef = null; - private String gpsDateStamp = null; - private String gpsLatitude = null; - private String gpsLatitudeRef = null; - private String gpsLongitude = null; - private String gpsLongitudeRef = null; - private String gpsProcessingMethod = null; - private String gpsTimestamp = null; - private String iso = null; - private String make = null; - private String model = null; - private String orientation = null; - private String whiteBalance = null; - - private ExifInterface inFile = null; - private ExifInterface outFile = null; - - /** - * The file before it is compressed - * - * @param filePath - * @throws IOException - */ - public void createInFile(String filePath) throws IOException { - this.inFile = new ExifInterface(filePath); - } - - /** - * The file after it has been compressed - * - * @param filePath - * @throws IOException - */ - public void createOutFile(String filePath) throws IOException { - this.outFile = new ExifInterface(filePath); - } - - /** - * Reads all the EXIF data from the input file. - */ - public void readExifData() { - this.aperture = inFile.getAttribute(ExifInterface.TAG_APERTURE); - this.datetime = inFile.getAttribute(ExifInterface.TAG_DATETIME); - this.exposureTime = inFile.getAttribute(ExifInterface.TAG_EXPOSURE_TIME); - this.flash = inFile.getAttribute(ExifInterface.TAG_FLASH); - this.focalLength = inFile.getAttribute(ExifInterface.TAG_FOCAL_LENGTH); - this.gpsAltitude = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE); - this.gpsAltitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF); - this.gpsDateStamp = inFile.getAttribute(ExifInterface.TAG_GPS_DATESTAMP); - this.gpsLatitude = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE); - this.gpsLatitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF); - this.gpsLongitude = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE); - this.gpsLongitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF); - this.gpsProcessingMethod = inFile.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD); - this.gpsTimestamp = inFile.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP); - this.iso = inFile.getAttribute(ExifInterface.TAG_ISO); - this.make = inFile.getAttribute(ExifInterface.TAG_MAKE); - this.model = inFile.getAttribute(ExifInterface.TAG_MODEL); - this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION); - this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE); - } - - /** - * Writes the previously stored EXIF data to the output file. - * - * @throws IOException - */ - public void writeExifData() throws IOException { - // Don't try to write to a null file - if (this.outFile == null) { - return; - } - - if (this.aperture != null) { - this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperture); - } - if (this.datetime != null) { - this.outFile.setAttribute(ExifInterface.TAG_DATETIME, this.datetime); - } - if (this.exposureTime != null) { - this.outFile.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, this.exposureTime); - } - if (this.flash != null) { - this.outFile.setAttribute(ExifInterface.TAG_FLASH, this.flash); - } - if (this.focalLength != null) { - this.outFile.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, this.focalLength); - } - if (this.gpsAltitude != null) { - this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, this.gpsAltitude); - } - if (this.gpsAltitudeRef != null) { - this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, this.gpsAltitudeRef); - } - if (this.gpsDateStamp != null) { - this.outFile.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, this.gpsDateStamp); - } - if (this.gpsLatitude != null) { - this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE, this.gpsLatitude); - } - if (this.gpsLatitudeRef != null) { - this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, this.gpsLatitudeRef); - } - if (this.gpsLongitude != null) { - this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, this.gpsLongitude); - } - if (this.gpsLongitudeRef != null) { - this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, this.gpsLongitudeRef); - } - if (this.gpsProcessingMethod != null) { - this.outFile.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, this.gpsProcessingMethod); - } - if (this.gpsTimestamp != null) { - this.outFile.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, this.gpsTimestamp); - } - if (this.iso != null) { - this.outFile.setAttribute(ExifInterface.TAG_ISO, this.iso); - } - if (this.make != null) { - this.outFile.setAttribute(ExifInterface.TAG_MAKE, this.make); - } - if (this.model != null) { - this.outFile.setAttribute(ExifInterface.TAG_MODEL, this.model); - } - if (this.orientation != null) { - this.outFile.setAttribute(ExifInterface.TAG_ORIENTATION, this.orientation); - } - if (this.whiteBalance != null) { - this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance); - } - - this.outFile.saveAttributes(); - } - - public int getOrientation() { - int o = Integer.parseInt(this.orientation); - - if (o == ExifInterface.ORIENTATION_NORMAL) { - return 0; - } else if (o == ExifInterface.ORIENTATION_ROTATE_90) { - return 90; - } else if (o == ExifInterface.ORIENTATION_ROTATE_180) { - return 180; - } else if (o == ExifInterface.ORIENTATION_ROTATE_270) { - return 270; - } else { - return 0; - } - } - - public void resetOrientation() { - this.orientation = "" + ExifInterface.ORIENTATION_NORMAL; - } -} diff --git a/src/android/FileHelper.java b/src/android/FileHelper.java deleted file mode 100644 index 24ced59..0000000 --- a/src/android/FileHelper.java +++ /dev/null @@ -1,158 +0,0 @@ -/* - 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. - */ -package org.apache.cordova.camera; - -import android.database.Cursor; -import android.net.Uri; -import android.webkit.MimeTypeMap; - -import org.apache.cordova.CordovaInterface; -import org.apache.cordova.LOG; - -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.Locale; - -public class FileHelper { - private static final String LOG_TAG = "FileUtils"; - private static final String _DATA = "_data"; - - /** - * Returns the real path of the given URI string. - * If the given URI string represents a content:// URI, the real path is retrieved from the media store. - * - * @param uriString the URI string of the audio/image/video - * @param cordova the current application context - * @return the full path to the file - */ - @SuppressWarnings("deprecation") - public static String getRealPath(String uriString, CordovaInterface cordova) { - String realPath = null; - - if (uriString.startsWith("content://")) { - String[] proj = { _DATA }; - Cursor cursor = cordova.getActivity().managedQuery(Uri.parse(uriString), proj, null, null, null); - int column_index = cursor.getColumnIndexOrThrow(_DATA); - cursor.moveToFirst(); - realPath = cursor.getString(column_index); - if (realPath == null) { - LOG.e(LOG_TAG, "Could get real path for URI string %s", uriString); - } - } else if (uriString.startsWith("file://")) { - realPath = uriString.substring(7); - if (realPath.startsWith("/android_asset/")) { - LOG.e(LOG_TAG, "Cannot get real path for URI string %s because it is a file:///android_asset/ URI.", uriString); - realPath = null; - } - } else { - realPath = uriString; - } - - return realPath; - } - - /** - * Returns the real path of the given URI. - * If the given URI is a content:// URI, the real path is retrieved from the media store. - * - * @param uri the URI of the audio/image/video - * @param cordova the current application context - * @return the full path to the file - */ - public static String getRealPath(Uri uri, CordovaInterface cordova) { - return FileHelper.getRealPath(uri.toString(), cordova); - } - - /** - * Returns an input stream based on given URI string. - * - * @param uriString the URI string from which to obtain the input stream - * @param cordova the current application context - * @return an input stream into the data at the given URI or null if given an invalid URI string - * @throws IOException - */ - public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) throws IOException { - if (uriString.startsWith("content")) { - Uri uri = Uri.parse(uriString); - return cordova.getActivity().getContentResolver().openInputStream(uri); - } else if (uriString.startsWith("file://")) { - int question = uriString.indexOf("?"); - if (question > -1) { - uriString = uriString.substring(0,question); - } - if (uriString.startsWith("file:///android_asset/")) { - Uri uri = Uri.parse(uriString); - String relativePath = uri.getPath().substring(15); - return cordova.getActivity().getAssets().open(relativePath); - } else { - return new FileInputStream(getRealPath(uriString, cordova)); - } - } else { - return new FileInputStream(getRealPath(uriString, cordova)); - } - } - - /** - * Removes the "file://" prefix from the given URI string, if applicable. - * If the given URI string doesn't have a "file://" prefix, it is returned unchanged. - * - * @param uriString the URI string to operate on - * @return a path without the "file://" prefix - */ - public static String stripFileProtocol(String uriString) { - if (uriString.startsWith("file://")) { - uriString = uriString.substring(7); - } - return uriString; - } - - public static String getMimeTypeForExtension(String path) { - String extension = path; - int lastDot = extension.lastIndexOf('.'); - if (lastDot != -1) { - extension = extension.substring(lastDot + 1); - } - // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185). - extension = extension.toLowerCase(Locale.getDefault()); - if (extension.equals("3ga")) { - return "audio/3gpp"; - } - return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); - } - - /** - * Returns the mime type of the data specified by the given URI string. - * - * @param uriString the URI string of the data - * @return the mime type of the specified data - */ - public static String getMimeType(String uriString, CordovaInterface cordova) { - String mimeType = null; - - Uri uri = Uri.parse(uriString); - if (uriString.startsWith("content://")) { - mimeType = cordova.getActivity().getContentResolver().getType(uri); - } else { - mimeType = getMimeTypeForExtension(uri.getPath()); - } - - return mimeType; - } -} diff --git a/src/blackberry10/index.js b/src/blackberry10/index.js deleted file mode 100644 index 9a5ebf3..0000000 --- a/src/blackberry10/index.js +++ /dev/null @@ -1,129 +0,0 @@ -/* - * - * 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 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) - }, - 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) - }; - -function encodeBase64(filePath, callback) { - var sandbox = window.qnx.webplatform.getController().setFileSystemSandbox, // save original sandbox value - errorHandler = function (err) { - var msg = "An error occured: "; - - switch (err.code) { - case FileError.NOT_FOUND_ERR: - msg += "File or directory not found"; - break; - - case FileError.NOT_READABLE_ERR: - msg += "File or directory not readable"; - break; - - case FileError.PATH_EXISTS_ERR: - msg += "File or directory already exists"; - break; - - case FileError.TYPE_MISMATCH_ERR: - msg += "Invalid file type"; - break; - - default: - msg += "Unknown Error"; - break; - }; - - // set it back to original value - window.qnx.webplatform.getController().setFileSystemSandbox = sandbox; - callback(msg); - }, - gotFile = function (fileEntry) { - fileEntry.file(function (file) { - var reader = new FileReader(); - - reader.onloadend = function (e) { - // set it back to original value - window.qnx.webplatform.getController().setFileSystemSandbox = sandbox; - callback(this.result); - }; - - reader.readAsDataURL(file); - }, errorHandler); - }, - onInitFs = function (fs) { - window.qnx.webplatform.getController().setFileSystemSandbox = false; - fs.root.getFile(filePath, {create: false}, gotFile, errorHandler); - }; - - window.webkitRequestFileSystem(window.TEMPORARY, 10 * 1024 * 1024, onInitFs, errorHandler); // set size to 10MB max -} - -module.exports = { - takePicture: function (success, fail, args, env) { - var destinationType = JSON.parse(decodeURIComponent(args[1])), - sourceType = JSON.parse(decodeURIComponent(args[2])), - result = new PluginResult(args, env), - done = function (data) { - if (destinationType === DestinationType.FILE_URI) { - data = "file://" + data; - result.callbackOk(data, false); - } else { - encodeBase64(data, function (data) { - if (/^data:/.test(data)) { - data = data.slice(data.indexOf(",") + 1); - result.callbackOk(data, false); - } else { - result.callbackError(data, false); - } - }); - } - }, - cancel = function (reason) { - result.callbackError(reason, false); - }, - invoked = function (error) { - if (error) { - result.callbackError(error, false); - } - }; - - switch(sourceType) { - case PictureSourceType.CAMERA: - window.qnx.webplatform.getApplication().cards.camera.open("photo", done, cancel, invoked); - break; - - case PictureSourceType.PHOTOLIBRARY: - case PictureSourceType.SAVEDPHOTOALBUM: - window.qnx.webplatform.getApplication().cards.filePicker.open({ - mode: "Picker", - type: ["picture"] - }, done, cancel, invoked); - break; - } - - result.noResult(true); - } -}; diff --git a/src/firefoxos/CameraProxy.js b/src/firefoxos/CameraProxy.js deleted file mode 100644 index 9afb343..0000000 --- a/src/firefoxos/CameraProxy.js +++ /dev/null @@ -1,51 +0,0 @@ -/* - * - * 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. - * - */ - -function takePicture(success, error, opts) { - var pick = new MozActivity({ - name: "pick", - data: { - type: ["image/*"] - } - }); - - pick.onerror = error || function() {}; - - pick.onsuccess = function() { - // image is returned as Blob in this.result.blob - // we need to call success with url or base64 encoded image - if (opts && opts.destinationType == 0) { - // TODO: base64 - return; - } - if (!opts || !opts.destinationType || opts.destinationType > 0) { - // url - return success(window.URL.createObjectURL(this.result.blob)); - } - }; -} - -module.exports = { - takePicture: takePicture, - cleanup: function(){} -}; - -require("cordova/firefoxos/commandProxy").add("Camera", module.exports); diff --git a/src/ios/CDVCamera.h b/src/ios/CDVCamera.h deleted file mode 100644 index 744ae7f..0000000 --- a/src/ios/CDVCamera.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - 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 -#import -#import -#import - -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 -{} - -@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 diff --git a/src/ios/CDVCamera.m b/src/ios/CDVCamera.m deleted file mode 100644 index 9981747..0000000 --- a/src/ios/CDVCamera.m +++ /dev/null @@ -1,756 +0,0 @@ -/* - 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 -#import -#import -#import -#import -#import -#import -#import -#import - -#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 %lu not available.", (unsigned long)sourceType); - CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no camera available"]; - [self.commandDelegate sendPluginResult:result callbackId:callbackId]; - return; - } - - bool allowEdit = [[arguments objectAtIndex:7] boolValue]; - NSNumber* targetWidth = [arguments objectAtIndex:3]; - NSNumber* targetHeight = [arguments objectAtIndex:4]; - NSNumber* mediaValue = [arguments objectAtIndex:6]; - CDVMediaType mediaType = (mediaValue) ? [mediaValue intValue] : MediaTypePicture; - - CGSize targetSize = CGSizeMake(0, 0); - if ((targetWidth != nil) && (targetHeight != nil)) { - targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]); - } - - // If a popover is already open, close it; we only want one at a time. - if (([[self pickerController] popoverController] != nil) && [[[self pickerController] popoverController] isPopoverVisible]) { - [[[self pickerController] popoverController] dismissPopoverAnimated:YES]; - [[[self pickerController] popoverController] setDelegate:nil]; - [[self pickerController] setPopoverController:nil]; - } - - CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init]; - self.pickerController = cameraPicker; - - cameraPicker.delegate = self; - cameraPicker.sourceType = sourceType; - cameraPicker.allowsEditing = allowEdit; // THIS IS ALL IT TAKES FOR CROPPING - jm - cameraPicker.callbackId = callbackId; - cameraPicker.targetSize = targetSize; - cameraPicker.cropToSize = NO; - // we need to capture this state for memory warnings that dealloc this object - cameraPicker.webView = self.webView; - cameraPicker.popoverSupported = [self popoverSupported]; - - cameraPicker.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 { - SEL selector = NSSelectorFromString(@"presentViewController:animated:completion:"); - if ([self.viewController respondsToSelector:selector]) { - [self.viewController presentViewController:cameraPicker animated:YES completion:nil]; - } else { - // deprecated as of iOS >= 6.0 - [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 -{ - NSInteger x = 0; - NSInteger y = 32; - NSInteger width = 320; - NSInteger 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 numberWithUnsignedInteger: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; - // returnedImage is the image that is returned to caller and (optionally) saved to photo album - UIImage* returnedImage = (scaledImage == nil ? image : scaledImage); - - if (cameraPicker.encodingType == EncodingTypePNG) { - data = UIImagePNGRepresentation(returnedImage); - } else if ((cameraPicker.allowsEditing==false) && (cameraPicker.targetSize.width <= 0) && (cameraPicker.targetSize.height <= 0) && (cameraPicker.correctOrientation==false)){ - // use image unedited as requested , don't resize - data = UIImageJPEGRepresentation(returnedImage, 1.0); - } else { - data = UIImageJPEGRepresentation(returnedImage, cameraPicker.quality / 100.0f); - - NSDictionary *controllerMetadata = [info objectForKey:@"UIImagePickerControllerMediaMetadata"]; - if (controllerMetadata) { - self.data = data; - self.metadata = [[NSMutableDictionary alloc] init]; - - NSMutableDictionary *EXIFDictionary = [[controllerMetadata objectForKey:(NSString *)kCGImagePropertyExifDictionary]mutableCopy]; - if (EXIFDictionary) [self.metadata setObject:EXIFDictionary forKey:(NSString *)kCGImagePropertyExifDictionary]; - - [[self locationManager] startUpdatingLocation]; - return; - } - } - - if (cameraPicker.saveToPhotoAlbum) { - ALAssetsLibrary *library = [ALAssetsLibrary new]; - [library writeImageToSavedPhotosAlbum:returnedImage.CGImage orientation:(ALAssetOrientation)(returnedImage.imageOrientation) completionBlock: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) { - ALAssetsLibrary *library = [ALAssetsLibrary new]; - [library writeImageDataToSavedPhotosAlbum:self.data metadata:self.metadata completionBlock:nil]; - } - - if (self.pickerController.returnType == DestinationTypeFileUri) { - // write to temp directory and return URI - // get the temp directory path - NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath]; - NSError* err = nil; - NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by apple (vs [NSFileManager defaultManager]) to be threadsafe - // generate unique file name - NSString* filePath; - - int i = 1; - do { - filePath = [NSString stringWithFormat:@"%@/%@%03d.%@", docsPath, CDV_PHOTO_PREFIX, i++, self.pickerController.encodingType == EncodingTypePNG ? @"png":@"jpg"]; - } while ([fileMgr fileExistsAtPath:filePath]); - - // save file - if (![self.data writeToFile:filePath options:NSAtomicWrite error:&err]) { - result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]]; - } - 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; - -- (BOOL)prefersStatusBarHidden { - return YES; -} - -- (UIViewController*)childViewControllerForStatusBarHidden { - return nil; -} - -- (void)viewWillAppear:(BOOL)animated { - SEL sel = NSSelectorFromString(@"setNeedsStatusBarAppearanceUpdate"); - if ([self respondsToSelector:sel]) { - [self performSelector:sel withObject:nil afterDelay:0]; - } - - [super viewWillAppear:animated]; -} - -@end diff --git a/src/ios/CDVExif.h b/src/ios/CDVExif.h deleted file mode 100644 index 3e8adbd..0000000 --- a/src/ios/CDVExif.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - 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 diff --git a/src/ios/CDVJpegHeaderWriter.h b/src/ios/CDVJpegHeaderWriter.h deleted file mode 100644 index 3b43ef0..0000000 --- a/src/ios/CDVJpegHeaderWriter.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - Licensed to the Apache Software Foundation (ASF) under one - or more contributor license agreements. See the NOTICE file - distributed with this work for additional information - regarding copyright ownership. The ASF licenses this file - to you under the Apache License, Version 2.0 (the - "License"); you may not use this file except in compliance - with the License. You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, - software distributed under the License is distributed on an - "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - KIND, either express or implied. See the License for the - specific language governing permissions and limitations - under the License. - */ - -#import - -@interface 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 diff --git a/src/ios/CDVJpegHeaderWriter.m b/src/ios/CDVJpegHeaderWriter.m deleted file mode 100644 index 4d3ea24..0000000 --- a/src/ios/CDVJpegHeaderWriter.m +++ /dev/null @@ -1,547 +0,0 @@ -/* - 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 : @""]) { - // 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, - (unsigned int)(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 - unsigned int entrycount = (unsigned int)[ifdblock count]; - if (ifd0flag) { - // 18 accounts for 8769's width + offset to next ifd, 8 accounts for start of header - NSNumber * offset = [NSNumber numberWithUnsignedInteger:[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 numberWithUnsignedInteger:[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", (int)(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 { - NSUInteger 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 diff --git a/src/ubuntu/CaptureWidget.qml b/src/ubuntu/CaptureWidget.qml deleted file mode 100644 index e3fe20e..0000000 --- a/src/ubuntu/CaptureWidget.qml +++ /dev/null @@ -1,119 +0,0 @@ -/* - * - * Copyright 2013 Canonical Ltd. - * - * 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 QtQuick 2.0 -import QtMultimedia 5.0 - -Rectangle { - property string shootImagePath: "shoot.png" - function isSuffix(str, suffix) { - return String(str).substr(String(str).length - suffix.length) == suffix - } - - id: ui - color: "#252423" - anchors.fill: parent - - Camera { - objectName: "camera" - id: camera - onError: { - console.log(errorString); - } - videoRecorder.audioBitRate: 128000 - videoRecorder.mediaContainer: "mp4" - imageCapture { - onImageSaved: { - root.exec("Camera", "onImageSaved", [path]); - ui.destroy(); - } - } - } - VideoOutput { - id: output - source: camera - width: parent.width - height: parent.height - } - - Item { - anchors.bottom: parent.bottom - width: parent.width - height: shootButton.height - BorderImage { - id: leftBackground - anchors.left: parent.left - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.right: middle.left - anchors.topMargin: units.dp(2) - anchors.bottomMargin: units.dp(2) - source: "toolbar-left.png" - Image { - anchors.verticalCenter: parent.verticalCenter - anchors.left: parent.left - anchors.leftMargin: parent.iconSpacing - source: "back.png" - width: units.gu(6) - height: units.gu(5) - MouseArea { - anchors.fill: parent - onClicked: { - root.exec("Camera", "cancel"); - } - } - } - } - BorderImage { - id: middle - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.horizontalCenter: parent.horizontalCenter - height: shootButton.height + units.gu(1) - width: shootButton.width - source: "toolbar-middle.png" - Image { - id: shootButton - width: units.gu(8) - height: width - anchors.horizontalCenter: parent.horizontalCenter - source: shootImagePath - MouseArea { - anchors.fill: parent - onClicked: { - camera.imageCapture.capture(); - } - } - } - } - BorderImage { - id: rightBackground - anchors.right: parent.right - anchors.top: parent.top - anchors.bottom: parent.bottom - anchors.left: middle.right - anchors.topMargin: units.dp(2) - anchors.bottomMargin: units.dp(2) - source: "toolbar-right.png" - } - } -} diff --git a/src/ubuntu/back.png b/src/ubuntu/back.png deleted file mode 100644 index af78faa837ce940e2818f5a8fcd2f88e1de27bda..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 12428 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 C%sA`- diff --git a/src/ubuntu/camera.cpp b/src/ubuntu/camera.cpp deleted file mode 100644 index eada5dc..0000000 --- a/src/ubuntu/camera.cpp +++ /dev/null @@ -1,143 +0,0 @@ -/* - * - * 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. - * -*/ - -#include "camera.h" -#include - -#include -#include -#include -#include -#include - -const char code[] = "\ -var component, object; \ -function createObject() { \ - component = Qt.createComponent(%1); \ - if (component.status == Component.Ready) \ - finishCreation(); \ - else \ - component.statusChanged.connect(finishCreation); \ -} \ -function finishCreation() { \ - CordovaWrapper.object = component.createObject(root, \ - {root: root, cordova: cordova}); \ -} \ -createObject()"; - - -Camera::Camera(Cordova *cordova): - CPlugin(cordova), - _lastScId(0), - _lastEcId(0) { -} - -bool Camera::preprocessImage(QString &path) { - bool convertToPNG = (*_options.find("encodingType")).toInt() == Camera::PNG; - int quality = (*_options.find("quality")).toInt(); - int width = (*_options.find("targetWidth")).toInt(); - int height = (*_options.find("targetHeight")).toInt(); - - QImage image(path); - if (width <= 0) - width = image.width(); - if (height <= 0) - height = image.height(); - image = image.scaled(width, height, Qt::KeepAspectRatio, Qt::SmoothTransformation); - - QFile oldImage(path); - QTemporaryFile newImage; - - const char *type; - if (convertToPNG) { - newImage.setFileTemplate("imgXXXXXX.png"); - type = "png"; - } else { - newImage.setFileTemplate("imgXXXXXX.jpg"); - type = "jpg"; - } - - newImage.open(); - newImage.setAutoRemove(false); - image.save(newImage.fileName(), type, quality); - - path = newImage.fileName(); - oldImage.remove(); - - return true; -} - -void Camera::onImageSaved(QString path) { - bool dataURL = _options.find("destinationType")->toInt() == Camera::DATA_URL; - - QString cbParams; - if (preprocessImage(path)) { - QString absolutePath = QFileInfo(path).absoluteFilePath(); - if (dataURL) { - QFile image(absolutePath); - image.open(QIODevice::ReadOnly); - QByteArray content = image.readAll().toBase64(); - cbParams = QString("\"%1\"").arg(content.data()); - image.remove(); - } else { - cbParams = CordovaInternal::format(QUrl::fromLocalFile(absolutePath).toString()); - } - } - - this->callback(_lastScId, cbParams); - - _lastEcId = _lastScId = 0; -} - -void Camera::takePicture(int scId, int ecId, int quality, int destinationType, int/*sourceType*/, int targetWidth, int targetHeight, int encodingType, - int/*mediaType*/, bool/*allowEdit*/, bool/*correctOrientation*/, bool/*saveToPhotoAlbum*/, const QVariantMap &/*popoverOptions*/, int/*cameraDirection*/) { - if (_camera.isNull()) { - _camera = QSharedPointer(new QCamera()); - } - - if (((_lastScId || _lastEcId) && (_lastScId != scId && _lastEcId != ecId)) || !_camera->isAvailable() || _camera->lockStatus() != QCamera::Unlocked) { - this->cb(_lastEcId, "Device is busy"); - return; - } - - _options.clear(); - _options.insert("quality", quality); - _options.insert("destinationType", destinationType); - _options.insert("targetWidth", targetWidth); - _options.insert("targetHeight", targetHeight); - _options.insert("encodingType", encodingType); - - _lastScId = scId; - _lastEcId = ecId; - - QString path = m_cordova->get_app_dir() + "/../qml/CaptureWidget.qml"; - - // TODO: relative url - QString qml = QString(code).arg(CordovaInternal::format(path)); - m_cordova->execQML(qml); -} - -void Camera::cancel() { - m_cordova->execQML("CordovaWrapper.object.destroy()"); - this->cb(_lastEcId, "canceled"); - - _lastEcId = _lastScId = 0; -} diff --git a/src/ubuntu/camera.h b/src/ubuntu/camera.h deleted file mode 100644 index aa06698..0000000 --- a/src/ubuntu/camera.h +++ /dev/null @@ -1,76 +0,0 @@ -/* - * - * 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 CAMERA_H -#define CAMERA_H - -#include - -#include -#include -#include -#include -#include - -class Camera: public CPlugin { - Q_OBJECT -public: - explicit Camera(Cordova *cordova); - - virtual const QString fullName() override { - return Camera::fullID(); - } - - virtual const QString shortName() override { - return "Camera"; - } - - static const QString fullID() { - return "Camera"; - } - -public slots: - void takePicture(int scId, int ecId, int quality, int destinationType, int/*sourceType*/, int targetWidth, int targetHeight, int encodingType, - int/*mediaType*/, bool/*allowEdit*/, bool/*correctOrientation*/, bool/*saveToPhotoAlbum*/, const QVariantMap &popoverOptions, int cameraDirection); - void cancel(); - - void onImageSaved(QString path); - -private: - bool preprocessImage(QString &path); - - int _lastScId; - int _lastEcId; - QSharedPointer _camera; - - QVariantMap _options; -protected: - enum DestinationType { - DATA_URL = 0, - FILE_URI = 1 - }; - enum EncodingType { - JPEG = 0, - PNG = 1 - }; -}; - -#endif // CAMERA_H diff --git a/src/ubuntu/shoot.png b/src/ubuntu/shoot.png deleted file mode 100644 index c093b633c886b1ebd03925113c66c49ac53f50b0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14430 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 diff --git a/src/ubuntu/toolbar-left.png b/src/ubuntu/toolbar-left.png deleted file mode 100644 index 720d7f601675cb18b2394fedb47dc43805df7adf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1212 zcmeAS@N?(olHy`uVBq!ia0y~yU}OWb=Ws9s$yJG8=K}>g1AIbU|D%HX`ue?l_rk@_ zoH+w$BQx~$^wibWAtE0?esp$r{`Kn@kn8X74$p2$-0F2n4dSGJzyBGY~-m3k$QOqhnfH8j!&P z2CS?sV8jaKv9hwVu>lDdAjt-1K^S3SVL)Sn;_U2fT3VVA1HsDJczC$^`1sV-)xh>L zNlHorodk3M4-XGe1ZXRel$V!>+0P7i53``4pqQ8#P!OmLA_7qWbOW3LbO$FVCr||D z5;m9%K~4k;va_>87;rMvh&={qeRD~WUoZnR3mZEJ2fv_@sEoXdnzoL$hnJVPZ*X)> zLRv{#d1Z5RTU%G}^yxEa%?5%wbLY;TH*fy@`3n{T!JNRWDu3fi&!$u(3v}yC^EnBy4+YSUfcI@1_YuB#byLa!|vv==4c3+`X zU|__1x;TbZ+OE-f7&?D@}I`tyzkfj1A}hA ze{p}`mMey*`;Qzt^gVyRYs%fmr*Y3;|K4f-w(R%P#5j$!X`fe~xNtD;dGPC#SGjxJ zo?kulXxG)OrH?F9J>S05J$G-n#E;VT&sNQ}oU`v_(aMl1zU#%J%?~Yjcy-k;$D10e zp$?}{?>qO#H+12%FqyeWEm~{rrf+_F<#_upr>litRmL_WDd6QSPj? zc{ygYJx@zQ&=DswmJ{49u(#F$dc1aTo3!&nxOj@;e3>@RX5$yD8+lTGOn1CLVcJE> zWo(j0DGJPzCmh&}CIH1LXFeznvGY@7?&c0VAk{5uqFX}8w;MkaH;5B*qJPw=sue+Wii!L>(~orHkuW`Inwhk;g`_W-pA?5cO6>|s+PVx zG4Jz71(yfEc_&|aJ@41^uigqqTTBTiKS!{^-dBiF&&F KxvX*PxS diff --git a/src/ubuntu/toolbar-middle.png b/src/ubuntu/toolbar-middle.png deleted file mode 100644 index 77595bb1332aee9326f86e496a6cf8dca6724327..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4416 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 M8k!o^>bXAn7gDq;O#lD@ diff --git a/src/ubuntu/toolbar-right.png b/src/ubuntu/toolbar-right.png deleted file mode 100644 index e4e6aa6026a3bc336abf5c46223c4f0152ecd2da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1161 zcmeAS@N?(olHy`uVBq!ia0y~yU}OQZ=Ws9s$#qjy7Xbwd1AIbU|099Ay1Ko4_re9v zo;?d^!x`%8>Uw&55bpc;@132UfBpIe-}+aZ9Fk%5tsao)UnKoSU;n1Bcbva&LPBr`J*K>-U3v!kP9YHBKw!2$-X ztSn%}3IuFytUz@@E|9^-#>U6T2VsPTg#oPqinFt`X=!P}&4kGE@NffFs;jF3tp?f! zbR^JKV21#?%u-TP5WB&;m<0p`#KgpaA`mV+J3B-cNCKS$AvriWfVKmu1L4Lsu%q(mi9Q=YpVlwh7YT7!Uo?hO5!7(ujX(eUlmCenqZQavn%$zkF z23T_2sUlr zym`ykZQHhQ-@aq#&Yin zZ+-VWOhL%umWmV;=d4>R3h#@GUJ1LiYHQNLx+-<&^B?Ej`+n$i{d{k|`;yP}>{+1^ z3ZgdLtm9{Ew!an7v$fRQ{M@_St9stsPoG{dSsNG@zFDsS`|~N+^0wd4$WMJ)wp(6o z|DPB9*ZcA>3(6cXwLSm+^&%F>&6RJjoj$ky--jbJg0|i|v&Q(*sfRzmE)aCPK3{JQ z5C78;)8NaRDkuH!tY$x}vG00h<#z9zWjkY5dM)O^Tlja^x`O(J^&wM@wrQjmzcD@j zaTAyRzPJ$A)0@0L-I$t{d+lSh!Myi-!hbdeiX1-mf+w|B{7#i}SG?}ZJvOXor9wY^ z3ElBK@@cA;i1$*j(qmWGAA0Mb^-Dfdbj_r->zm|VKHHk=28B7sw_g13=sw|OOlwi7 zeQ)9(4eO>#kq!kLr?~w+E*k6HGXxtsTojlDI~-V)1Sn>HDAbtGDctz7;eU}!ljX#W zb;mdOO!+cHqHFTJH5)aPAKwW175L{(gtlkAvBPw`9ZGdw2A=chPP6lxx#Z>N=0(pv zeVf~#t3Tzt+7_stJt1!1t(7+Rzcn*VW;L}WiX63SEc^PQ!tbS;RoBHyis#O#svVrm z?f$JtGj-OHPK}ixUz|MatM*|Tm;48FA_Lb$p-|30t~frA?{^^95F Vdv8wr^Q;LZ=;`X`vd$@?2>|~T#2)|v diff --git a/src/windows8/CameraProxy.js b/src/windows8/CameraProxy.js deleted file mode 100644 index d46553b..0000000 --- a/src/windows8/CameraProxy.js +++ /dev/null @@ -1,354 +0,0 @@ -/* - * - * 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. - * -*/ - -/*global Windows:true, URL:true */ - - - -var cordova = require('cordova'), - Camera = require('./Camera'), - FileEntry = require('org.apache.cordova.file.FileEntry'), - FileError = require('org.apache.cordova.file.FileError'), - FileReader = require('org.apache.cordova.file.FileReader'); - -module.exports = { - - // args will contain : - // ... it is an array, so be careful - // 0 quality:50, - // 1 destinationType:Camera.DestinationType.FILE_URI, - // 2 sourceType:Camera.PictureSourceType.CAMERA, - // 3 targetWidth:-1, - // 4 targetHeight:-1, - // 5 encodingType:Camera.EncodingType.JPEG, - // 6 mediaType:Camera.MediaType.PICTURE, - // 7 allowEdit:false, - // 8 correctOrientation:false, - // 9 saveToPhotoAlbum:false, - // 10 popoverOptions:null - - takePicture: function (successCallback, errorCallback, args) { - var encodingType = args[5]; - var targetWidth = args[3]; - var targetHeight = args[4]; - var sourceType = args[2]; - var destinationType = args[1]; - var mediaType = args[6]; - var saveToPhotoAlbum = args[9]; - - var pkg = Windows.ApplicationModel.Package.current; - var packageId = pkg.installedLocation; - - var fail = function (fileError) { - errorCallback("FileError, code:" + fileError.code); - }; - - // resize method :) - var resizeImage = function (file) { - var tempPhotoFileName = ""; - if (encodingType == Camera.EncodingType.PNG) { - tempPhotoFileName = "camera_cordova_temp_return.png"; - } else { - tempPhotoFileName = "camera_cordova_temp_return.jpg"; - } - var imgObj = new Image(); - var success = function (fileEntry) { - var successCB = function (filePhoto) { - var fileType = file.contentType, - reader = new FileReader(); - reader.onloadend = function () { - var image = new Image(); - image.src = reader.result; - image.onload = function () { - var imageWidth = targetWidth, - imageHeight = targetHeight; - var canvas = document.createElement('canvas'); - - canvas.width = imageWidth; - canvas.height = imageHeight; - - var ctx = canvas.getContext("2d"); - ctx.drawImage(this, 0, 0, imageWidth, imageHeight); - - // The resized file ready for upload - var _blob = canvas.msToBlob(); - var _stream = _blob.msDetachStream(); - - var storageFolder = Windows.Storage.ApplicationData.current.localFolder; - storageFolder.createFileAsync(tempPhotoFileName, Windows.Storage.CreationCollisionOption.generateUniqueName).done(function (file) { - file.openAsync(Windows.Storage.FileAccessMode.readWrite).done(function (fileStream) { - Windows.Storage.Streams.RandomAccessStream.copyAndCloseAsync(_stream, fileStream).done(function () { - var _imageUrl = URL.createObjectURL(file); - successCallback(_imageUrl); - }, function () { - errorCallback("Resize picture error."); - }); - }, function () { - errorCallback("Resize picture error."); - }); - }, function () { - errorCallback("Resize picture error."); - }); - - }; - }; - - reader.readAsDataURL(filePhoto); - }; - - var failCB = function () { - errorCallback("File not found."); - }; - fileEntry.file(successCB, failCB); - }; - - var storageFolder = Windows.Storage.ApplicationData.current.localFolder; - file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function (storageFile) { - success(new FileEntry(storageFile.name, storageFile.path)); - }, function () { - fail(FileError.INVALID_MODIFICATION_ERR); - }, function () { - errorCallback("Folder not access."); - }); - - }; - - // because of asynchronous method, so let the successCallback be called in it. - var resizeImageBase64 = function (file) { - var imgObj = new Image(); - var success = function (fileEntry) { - var successCB = function (filePhoto) { - var fileType = file.contentType, - reader = new FileReader(); - reader.onloadend = function () { - var image = new Image(); - image.src = reader.result; - - image.onload = function () { - var imageWidth = targetWidth, - imageHeight = targetHeight; - var canvas = document.createElement('canvas'); - - canvas.width = imageWidth; - canvas.height = imageHeight; - - var ctx = canvas.getContext("2d"); - ctx.drawImage(this, 0, 0, imageWidth, imageHeight); - - // The resized file ready for upload - var finalFile = canvas.toDataURL(fileType); - - // Remove the prefix such as "data:" + contentType + ";base64," , in order to meet the Cordova API. - var arr = finalFile.split(","); - var newStr = finalFile.substr(arr[0].length + 1); - successCallback(newStr); - }; - }; - - reader.readAsDataURL(filePhoto); - - }; - var failCB = function () { - errorCallback("File not found."); - }; - fileEntry.file(successCB, failCB); - }; - - var storageFolder = Windows.Storage.ApplicationData.current.localFolder; - file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function (storageFile) { - success(new FileEntry(storageFile.name, "ms-appdata:///local/" + storageFile.name)); - }, function () { - fail(FileError.INVALID_MODIFICATION_ERR); - }, function () { - errorCallback("Folder not access."); - }); - - - }; - - if (sourceType != Camera.PictureSourceType.CAMERA) { - var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker(); - fileOpenPicker.suggestedStartLocation = Windows.Storage.Pickers.PickerLocationId.picturesLibrary; - if (mediaType == Camera.MediaType.PICTURE) { - fileOpenPicker.fileTypeFilter.replaceAll([".png", ".jpg", ".jpeg"]); - } - else if (mediaType == Camera.MediaType.VIDEO) { - fileOpenPicker.fileTypeFilter.replaceAll([".avi", ".flv", ".asx", ".asf", ".mov", ".mp4", ".mpg", ".rm", ".srt", ".swf", ".wmv", ".vob"]); - } - else { - fileOpenPicker.fileTypeFilter.replaceAll(["*"]); - } - - fileOpenPicker.pickSingleFileAsync().then(function (file) { - if (file) { - if (destinationType == Camera.DestinationType.FILE_URI) { - if (targetHeight > 0 && targetWidth > 0) { - resizeImage(file); - } - else { - - var storageFolder = Windows.Storage.ApplicationData.current.localFolder; - file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function (storageFile) { - successCallback(URL.createObjectURL(storageFile)); - }, function () { - fail(FileError.INVALID_MODIFICATION_ERR); - }, function () { - errorCallback("Folder not access."); - }); - - } - } - else { - if (targetHeight > 0 && targetWidth > 0) { - resizeImageBase64(file); - } else { - Windows.Storage.FileIO.readBufferAsync(file).done(function (buffer) { - var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer); - successCallback(strBase64); - }); - } - - } - - } else { - errorCallback("User didn't choose a file."); - } - }, function () { - errorCallback("User didn't choose a file."); - }); - } - else { - - var cameraCaptureUI = new Windows.Media.Capture.CameraCaptureUI(); - cameraCaptureUI.photoSettings.allowCropping = true; - var allowCrop = !!args[7]; - if (!allowCrop) { - cameraCaptureUI.photoSettings.allowCropping = false; - } - - if (encodingType == Camera.EncodingType.PNG) { - cameraCaptureUI.photoSettings.format = Windows.Media.Capture.CameraCaptureUIPhotoFormat.png; - } else { - cameraCaptureUI.photoSettings.format = Windows.Media.Capture.CameraCaptureUIPhotoFormat.jpeg; - } - - // decide which max pixels should be supported by targetWidth or targetHeight. - if (targetWidth >= 1280 || targetHeight >= 960) { - cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.large3M; - } - else if (targetWidth >= 1024 || targetHeight >= 768) { - cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.mediumXga; - } - else if (targetWidth >= 800 || targetHeight >= 600) { - cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.mediumXga; - } - else if (targetWidth >= 640 || targetHeight >= 480) { - cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.smallVga; - } - else if (targetWidth >= 320 || targetHeight >= 240) { - cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.verySmallQvga; - } - else { - cameraCaptureUI.photoSettings.maxResolution = Windows.Media.Capture.CameraCaptureUIMaxPhotoResolution.highestAvailable; - } - - cameraCaptureUI.captureFileAsync(Windows.Media.Capture.CameraCaptureUIMode.photo).then(function (picture) { - if (picture) { - // save to photo album successCallback - var success = function (fileEntry) { - if (destinationType == Camera.DestinationType.FILE_URI) { - if (targetHeight > 0 && targetWidth > 0) { - resizeImage(picture); - } else { - - var storageFolder = Windows.Storage.ApplicationData.current.localFolder; - picture.copyAsync(storageFolder, picture.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function (storageFile) { - successCallback("ms-appdata:///local/" + storageFile.name); - }, function () { - fail(FileError.INVALID_MODIFICATION_ERR); - }, function () { - errorCallback("Folder not access."); - }); - } - } else { - if (targetHeight > 0 && targetWidth > 0) { - resizeImageBase64(picture); - } else { - Windows.Storage.FileIO.readBufferAsync(picture).done(function (buffer) { - var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer); - successCallback(strBase64); - }); - } - } - }; - // save to photo album errorCallback - var fail = function () { - //errorCallback("FileError, code:" + fileError.code); - errorCallback("Save fail."); - }; - - if (saveToPhotoAlbum) { - Windows.Storage.StorageFile.getFileFromPathAsync(picture.path).then(function (storageFile) { - storageFile.copyAsync(Windows.Storage.KnownFolders.picturesLibrary, picture.name, Windows.Storage.NameCollisionOption.generateUniqueName).then(function (storageFile) { - success(storageFile); - }, function () { - fail(); - }); - }); - //var directory = new DirectoryEntry("Pictures", parentPath); - //new FileEntry(picture.name, picture.path).copyTo(directory, null, success, fail); - } else { - if (destinationType == Camera.DestinationType.FILE_URI) { - if (targetHeight > 0 && targetWidth > 0) { - resizeImage(picture); - } else { - - var storageFolder = Windows.Storage.ApplicationData.current.localFolder; - picture.copyAsync(storageFolder, picture.name, Windows.Storage.NameCollisionOption.replaceExisting).then(function (storageFile) { - successCallback("ms-appdata:///local/" + storageFile.name); - }, function () { - fail(FileError.INVALID_MODIFICATION_ERR); - }, function () { - errorCallback("Folder not access."); - }); - } - } else { - if (targetHeight > 0 && targetWidth > 0) { - resizeImageBase64(picture); - } else { - Windows.Storage.FileIO.readBufferAsync(picture).done(function (buffer) { - var strBase64 = Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer); - successCallback(strBase64); - }); - } - } - } - } else { - errorCallback("User didn't capture a photo."); - } - }, function () { - errorCallback("Fail to capture a photo."); - }); - } - } -}; - -require("cordova/exec/proxy").add("Camera",module.exports); diff --git a/src/wp/Camera.cs b/src/wp/Camera.cs deleted file mode 100644 index b76929b..0000000 --- a/src/wp/Camera.cs +++ /dev/null @@ -1,515 +0,0 @@ -/* - Licensed 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. -*/ - -using System; -using System.Net; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Documents; -using System.Windows.Ink; -using System.Windows.Input; -using System.Windows.Media; -using System.Windows.Media.Animation; -using System.Collections.Generic; -using Microsoft.Phone.Tasks; -using System.Runtime.Serialization; -using System.IO; -using System.IO.IsolatedStorage; -using System.Windows.Media.Imaging; -using Microsoft.Phone; -using Microsoft.Xna.Framework.Media; -using System.Diagnostics; - -namespace WPCordovaClassLib.Cordova.Commands -{ - public class Camera : BaseCommand - { - - /// - /// Return base64 encoded string - /// - private const int DATA_URL = 0; - - /// - /// Return file uri - /// - private const int FILE_URI = 1; - - /// - /// Choose image from picture library - /// - private const int PHOTOLIBRARY = 0; - - /// - /// Take picture from camera - /// - - private const int CAMERA = 1; - - /// - /// Choose image from picture library - /// - private const int SAVEDPHOTOALBUM = 2; - - /// - /// Take a picture of type JPEG - /// - private const int JPEG = 0; - - /// - /// Take a picture of type PNG - /// - private const int PNG = 1; - - /// - /// Folder to store captured images - /// - private const string isoFolder = "CapturedImagesCache"; - - /// - /// Represents captureImage action options. - /// - [DataContract] - public class CameraOptions - { - /// - /// Source to getPicture from. - /// - [DataMember(IsRequired = false, Name = "sourceType")] - public int PictureSourceType { get; set; } - - /// - /// Format of image that returned from getPicture. - /// - [DataMember(IsRequired = false, Name = "destinationType")] - public int DestinationType { get; set; } - - /// - /// Quality of saved image - /// - [DataMember(IsRequired = false, Name = "quality")] - public int Quality { get; set; } - - /// - /// Controls whether or not the image is also added to the device photo album. - /// - [DataMember(IsRequired = false, Name = "saveToPhotoAlbum")] - public bool SaveToPhotoAlbum { get; set; } - - /// - /// Ignored - /// - [DataMember(IsRequired = false, Name = "correctOrientation")] - public bool CorrectOrientation { get; set; } - - /// - /// Ignored - /// - [DataMember(IsRequired = false, Name = "allowEdit")] - public bool AllowEdit { get; set; } - - /// - /// Height in pixels to scale image - /// - [DataMember(IsRequired = false, Name = "encodingType")] - public int EncodingType { get; set; } - - /// - /// Height in pixels to scale image - /// - [DataMember(IsRequired = false, Name = "mediaType")] - public int MediaType { get; set; } - - - /// - /// Height in pixels to scale image - /// - [DataMember(IsRequired = false, Name = "targetHeight")] - public int TargetHeight { get; set; } - - - /// - /// Width in pixels to scale image - /// - [DataMember(IsRequired = false, Name = "targetWidth")] - public int TargetWidth { get; set; } - - /// - /// Creates options object with default parameters - /// - public CameraOptions() - { - this.SetDefaultValues(new StreamingContext()); - } - - /// - /// Initializes default values for class fields. - /// Implemented in separate method because default constructor is not invoked during deserialization. - /// - /// - [OnDeserializing()] - public void SetDefaultValues(StreamingContext context) - { - PictureSourceType = CAMERA; - DestinationType = FILE_URI; - Quality = 80; - TargetHeight = -1; - TargetWidth = -1; - SaveToPhotoAlbum = false; - CorrectOrientation = true; - AllowEdit = false; - MediaType = -1; - EncodingType = -1; - } - } - - /// - /// Camera options - /// - CameraOptions cameraOptions; - - public void takePicture(string options) - { - try - { - string[] args = JSON.JsonHelper.Deserialize(options); - // ["quality", "destinationType", "sourceType", "targetWidth", "targetHeight", "encodingType", - // "mediaType", "allowEdit", "correctOrientation", "saveToPhotoAlbum" ] - cameraOptions = new CameraOptions(); - cameraOptions.Quality = int.Parse(args[0]); - cameraOptions.DestinationType = int.Parse(args[1]); - cameraOptions.PictureSourceType = int.Parse(args[2]); - cameraOptions.TargetWidth = int.Parse(args[3]); - cameraOptions.TargetHeight = int.Parse(args[4]); - cameraOptions.EncodingType = int.Parse(args[5]); - cameraOptions.MediaType = int.Parse(args[6]); - cameraOptions.AllowEdit = bool.Parse(args[7]); - cameraOptions.CorrectOrientation = bool.Parse(args[8]); - cameraOptions.SaveToPhotoAlbum = bool.Parse(args[9]); - - // a very large number will force the other value to be the bound - if (cameraOptions.TargetWidth > -1 && cameraOptions.TargetHeight == -1) - { - cameraOptions.TargetHeight = 100000; - } - else if (cameraOptions.TargetHeight > -1 && cameraOptions.TargetWidth == -1) - { - cameraOptions.TargetWidth = 100000; - } - } - catch (Exception ex) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message)); - return; - } - - if(cameraOptions.DestinationType != Camera.FILE_URI && cameraOptions.DestinationType != Camera.DATA_URL ) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType")); - return; - } - - ChooserBase chooserTask = null; - if (cameraOptions.PictureSourceType == CAMERA) - { - chooserTask = new CameraCaptureTask(); - } - else if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) || (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM)) - { - chooserTask = new PhotoChooserTask(); - } - // if chooserTask is still null, then PictureSourceType was invalid - if (chooserTask != null) - { - chooserTask.Completed += onTaskCompleted; - chooserTask.Show(); - } - else - { - Debug.WriteLine("Unrecognized PictureSourceType :: " + cameraOptions.PictureSourceType.ToString()); - DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT)); - } - } - - public void onTaskCompleted(object sender, PhotoResult e) - { - var task = sender as ChooserBase; - if (task != null) - { - task.Completed -= onTaskCompleted; - } - - if (e.Error != null) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR)); - return; - } - - switch (e.TaskResult) - { - case TaskResult.OK: - try - { - string imagePathOrContent = string.Empty; - - // Save image back to media library - // only save to photoalbum if it didn't come from there ... - if (cameraOptions.PictureSourceType == CAMERA && cameraOptions.SaveToPhotoAlbum) - { - MediaLibrary library = new MediaLibrary(); - Picture pict = library.SavePicture(e.OriginalFileName, e.ChosenPhoto); // to save to photo-roll ... - } - - int orient = ImageExifHelper.getImageOrientationFromStream(e.ChosenPhoto); - int newAngle = 0; - switch (orient) - { - case ImageExifOrientation.LandscapeLeft: - newAngle = 90; - break; - case ImageExifOrientation.PortraitUpsideDown: - newAngle = 180; - break; - case ImageExifOrientation.LandscapeRight: - newAngle = 270; - break; - case ImageExifOrientation.Portrait: - default: break; // 0 default already set - } - - if (newAngle != 0) - { - using (Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle)) - { - // we should reset stream position after saving stream to media library - rotImageStream.Seek(0, SeekOrigin.Begin); - if (cameraOptions.DestinationType == DATA_URL) - { - imagePathOrContent = GetImageContent(rotImageStream); - } - else // FILE_URL - { - imagePathOrContent = SaveImageToLocalStorage(rotImageStream, Path.GetFileName(e.OriginalFileName)); - } - } - } - else // no need to reorient - { - if (cameraOptions.DestinationType == DATA_URL) - { - imagePathOrContent = GetImageContent(e.ChosenPhoto); - } - else // FILE_URL - { - imagePathOrContent = SaveImageToLocalStorage(e.ChosenPhoto, Path.GetFileName(e.OriginalFileName)); - } - } - - DispatchCommandResult(new PluginResult(PluginResult.Status.OK, imagePathOrContent)); - } - catch (Exception) - { - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Error retrieving image.")); - } - break; - case TaskResult.Cancel: - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection cancelled.")); - break; - default: - DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Selection did not complete!")); - break; - } - } - - /// - /// Returns image content in a form of base64 string - /// - /// Image stream - /// Base64 representation of the image - private string GetImageContent(Stream stream) - { - byte[] imageContent = null; - - try - { - //use photo's actual width & height if user doesn't provide width & height - if (cameraOptions.TargetWidth < 0 && cameraOptions.TargetHeight < 0) - { - int streamLength = (int)stream.Length; - imageContent = new byte[streamLength + 1]; - stream.Read(imageContent, 0, streamLength); - } - else - { - // resize photo - imageContent = ResizePhoto(stream); - } - } - finally - { - stream.Dispose(); - } - - return Convert.ToBase64String(imageContent); - } - - /// - /// Resize image - /// - /// Image stream - /// File data - /// resized image - private byte[] ResizePhoto(Stream stream) - { - //output - byte[] resizedFile; - - BitmapImage objBitmap = new BitmapImage(); - objBitmap.SetSource(stream); - objBitmap.CreateOptions = BitmapCreateOptions.None; - - WriteableBitmap objWB = new WriteableBitmap(objBitmap); - objBitmap.UriSource = null; - - //Keep proportionally - double ratio = Math.Min((double)cameraOptions.TargetWidth / objWB.PixelWidth, (double)cameraOptions.TargetHeight / objWB.PixelHeight); - int width = Convert.ToInt32(ratio * objWB.PixelWidth); - int height = Convert.ToInt32(ratio * objWB.PixelHeight); - - //Hold the result stream - using (MemoryStream objBitmapStreamResized = new MemoryStream()) - { - - try - { - // resize the photo with user defined TargetWidth & TargetHeight - Extensions.SaveJpeg(objWB, objBitmapStreamResized, width, height, 0, cameraOptions.Quality); - } - finally - { - //Dispose bitmaps immediately, they are memory expensive - DisposeImage(objBitmap); - DisposeImage(objWB); - GC.Collect(); - } - - //Convert the resized stream to a byte array. - int streamLength = (int)objBitmapStreamResized.Length; - resizedFile = new Byte[streamLength]; //-1 - objBitmapStreamResized.Position = 0; - - //for some reason we have to set Position to zero, but we don't have to earlier when we get the bytes from the chosen photo... - objBitmapStreamResized.Read(resizedFile, 0, streamLength); - } - - return resizedFile; - } - - /// - /// Util: Dispose a bitmap resource - /// - /// BitmapSource subclass to dispose - private void DisposeImage(BitmapSource image) - { - if (image != null) - { - try - { - using (var ms = new MemoryStream(new byte[] { 0x0 })) - { - image.SetSource(ms); - } - } - catch (Exception) - { - } - } - } - - /// - /// Saves captured image in isolated storage - /// - /// image file name - /// Image path - private string SaveImageToLocalStorage(Stream stream, string imageFileName) - { - - if (stream == null) - { - throw new ArgumentNullException("imageBytes"); - } - try - { - var isoFile = IsolatedStorageFile.GetUserStoreForApplication(); - - if (!isoFile.DirectoryExists(isoFolder)) - { - isoFile.CreateDirectory(isoFolder); - } - - string filePath = System.IO.Path.Combine("///" + isoFolder + "/", imageFileName); - - using (IsolatedStorageFileStream outputStream = isoFile.CreateFile(filePath)) - { - BitmapImage objBitmap = new BitmapImage(); - objBitmap.SetSource(stream); - objBitmap.CreateOptions = BitmapCreateOptions.None; - - WriteableBitmap objWB = new WriteableBitmap(objBitmap); - objBitmap.UriSource = null; - - try - { - - //use photo's actual width & height if user doesn't provide width & height - if (cameraOptions.TargetWidth < 0 && cameraOptions.TargetHeight < 0) - { - objWB.SaveJpeg(outputStream, objWB.PixelWidth, objWB.PixelHeight, 0, cameraOptions.Quality); - } - else - { - //Resize - //Keep proportionally - double ratio = Math.Min((double)cameraOptions.TargetWidth / objWB.PixelWidth, (double)cameraOptions.TargetHeight / objWB.PixelHeight); - int width = Convert.ToInt32(ratio * objWB.PixelWidth); - int height = Convert.ToInt32(ratio * objWB.PixelHeight); - - // resize the photo with user defined TargetWidth & TargetHeight - objWB.SaveJpeg(outputStream, width, height, 0, cameraOptions.Quality); - } - } - finally - { - //Dispose bitmaps immediately, they are memory expensive - DisposeImage(objBitmap); - DisposeImage(objWB); - GC.Collect(); - } - } - - return new Uri(filePath, UriKind.Relative).ToString(); - } - catch (Exception) - { - //TODO: log or do something else - throw; - } - finally - { - stream.Dispose(); - } - } - - } -} diff --git a/www/Camera.js b/www/Camera.js deleted file mode 100644 index 555bb5e..0000000 --- a/www/Camera.js +++ /dev/null @@ -1,75 +0,0 @@ -/* - * - * 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('./Camera'); - // XXX: commented out - //CameraPopoverHandle = require('./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); - // XXX: commented out - //return new CameraPopoverHandle(); -}; - -cameraExport.cleanup = function(successCallback, errorCallback) { - exec(successCallback, errorCallback, "Camera", "cleanup", []); -}; - -module.exports = cameraExport; diff --git a/www/CameraConstants.js b/www/CameraConstants.js deleted file mode 100644 index ae4e534..0000000 --- a/www/CameraConstants.js +++ /dev/null @@ -1,53 +0,0 @@ -/* - * - * 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 - } -}; diff --git a/www/CameraPopoverHandle.js b/www/CameraPopoverHandle.js deleted file mode 100644 index 7a4c32d..0000000 --- a/www/CameraPopoverHandle.js +++ /dev/null @@ -1,33 +0,0 @@ -/* - * - * 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; diff --git a/www/CameraPopoverOptions.js b/www/CameraPopoverOptions.js deleted file mode 100644 index c024984..0000000 --- a/www/CameraPopoverOptions.js +++ /dev/null @@ -1,37 +0,0 @@ -/* - * - * 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('./Camera'); - -/** - * 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; diff --git a/www/ios/CameraPopoverHandle.js b/www/ios/CameraPopoverHandle.js deleted file mode 100644 index fc48c11..0000000 --- a/www/ios/CameraPopoverHandle.js +++ /dev/null @@ -1,34 +0,0 @@ -/* - * - * 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) { - var args = [ popoverOptions ]; - exec(null, null, "Camera", "repositionPopover", args); - }; -}; - -module.exports = CameraPopoverHandle;