Compare commits

...

529 Commits

Author SHA1 Message Date
4afa471fb6 修改压缩比例quality为100 2024-03-30 23:45:02 +08:00
a19ba493b3 修改压缩比例 2024-03-30 23:18:10 +08:00
c95f4f7501 修改ios选择,删除拍照按钮的位置 2024-03-30 20:51:49 +08:00
6c38d126ec 修改ios选择,删除拍照按钮的位置 2024-03-30 20:20:33 +08:00
ffaef73016 修改ios选择,删除拍照按钮的位置 2024-03-30 20:02:52 +08:00
4d59795df1 修改ios选择,删除拍照按钮的位置 2024-03-30 20:02:02 +08:00
6e82b526a2 修改ios选择,删除拍照按钮的位置 2024-03-30 19:46:27 +08:00
f13d7c7aa4 压缩比例改为100 2024-03-30 19:02:26 +08:00
2c804cea55 修改“拍照按钮”的高度y="513" 改为 y="463"
修改“自拍按钮”的位置 x="180" 改为 x="230"
2024-03-28 10:01:53 +08:00
976623696@qq.com
6d76d1defe 照片增加裁剪 2020-12-30 19:04:53 +08:00
zher52
47da7a7c29 修复iso13相机未全屏的问题 2020-12-30 14:27:57 +08:00
zher52
739cb20679 ios合并cordova camera 的取相册照片的方法 2020-06-01 16:00:56 +08:00
zher52
9782d52be4 fix 修复Failed to find configured root that contains错误 2020-05-13 13:24:29 +08:00
zher52
852531344a fix provider冲突造成的无法获取路径的问题 2020-05-13 12:00:50 +08:00
zher52
07e7444ee1 调整readme 2020-05-12 12:28:33 +08:00
zher52
ad603fcdaa 修改Readme 2020-05-12 12:23:25 +08:00
zher52
0a2c778c5f 调整ios端代码为custom项目代码 避免疯狂调用导致的webview崩溃 2020-05-12 12:10:19 +08:00
Jesse MacFadyen
ba4f77468f chore(release): 4.2.0-dev 2020-05-07 01:34:03 -07:00
Jesse MacFadyen
adf15799d9 Updated version and RELEASENOTES.md for release (Camera-4.2.0) 2020-05-07 00:45:53 -07:00
Jesse MacFadyen
e9aba07926 Merge pull request #588 from purplecabbage/AndroidCacheLocal
[Android] Cache images in device storage, devices have enough space now.
2020-04-30 10:46:21 -07:00
Jesse MacFadyen
df14414203 Cache images in device storage, devices have enough space now. 2020-04-28 13:57:00 -07:00
Norman Breau
2a750f0fa1 Merge pull request #508 from rtpHarry/patch-1
docs(readme): app renamed to Google Photos
2020-04-24 23:09:49 -03:00
Erisu
06ac9b3dc9 chore(asf): update git notification settings 2020-04-22 13:39:50 +09:00
jcesarmobile
bfa38fed2c fix(ios): return copy of video when picking from gallery on iOS 13 (#580) 2020-04-15 11:41:21 +02:00
Niklas Merz
7611960ef2 Update CONTRIBUTING.md 2020-04-13 14:27:10 +02:00
exxbrain
f4067e22d9 Fix UI API called on a background thread (#550, #530, #447) (#551)
Co-authored-by: Denis Zakharov <d.zakharov@bssys.com>
2020-04-09 13:54:26 +00:00
Tim Brust
f33ade83e4 ci: updates Node.js versions (#576) 2020-03-28 12:11:08 +00:00
Tim Brust
6f25420ce7 chore(npm): adds ignore list (#575) 2020-03-28 12:10:44 +00:00
jcesarmobile
6feaa95559 docs(README): remove confusing comment (#513) 2019-10-20 01:05:19 +02:00
jcesarmobile
c887c229f0 docs(README): remove orphan windows phone 7 note (#512) 2019-10-19 17:07:21 +02:00
Matthew Harris
6900fbaefa docs(readme): app renamed to Google Photos 2019-09-25 22:04:31 +07:00
klodha
a9436b1a18 ImagePicker returning same image (#306)
ImagePicker returning same image

Co-authored-by: Jan Piotrowski <piotrowski+github@gmail.com>
Co-authored-by: Tim Brust <github@timbrust.de>
2019-09-16 11:40:54 +02:00
Jan Piotrowski
db4b4b947d chore(release): 4.1.1-dev 2019-06-27 21:04:04 +02:00
Jan Piotrowski
ae3531acfa chore(release): 4.1.0 (version string) 2019-06-27 21:01:58 +02:00
Jan Piotrowski
5b4d9ba5c7 chore(release): release notes for 4.1.0 2019-06-27 21:01:58 +02:00
Jan Piotrowski
06dc38f9ab docs: remove outdated test docs translations 2019-06-27 18:46:33 +02:00
Jan Piotrowski
5dc952724f build: remove .ratignore file that is not needed any more 2019-06-27 18:46:13 +02:00
Jan Piotrowski
cad8bd1442 chore: fix repo and issue urls and license in package.json and plugin.xml 2019-06-27 18:45:52 +02:00
Jan Piotrowski
19d8e2f6ff fix: temporarily remove Appium tests (#468) 2019-06-20 13:30:25 +02:00
Jan Piotrowski
cffd0ac825 ci(travis): Update Travis CI configuration for new paramedic (#455)
* Update .travis.yml

* ADDITIONAL_TESTS

* npm install github:apache/cordova-paramedic\#plugin-test-fixes

* undo

* fix

* ADDITIONAL_TESTS_DIR

* Update .travis.yml

* update to npm 8 for `npm install appium`
2019-06-20 13:25:28 +02:00
Hazem Saleh
295e928784 (Android) Fix NullPointerException error on some Android phones (#429) 2019-05-05 19:16:20 +02:00
Gedas Gardauskas
fae190ead2 Update CI Environment Setup for Node.js 6 (#438) 2019-04-08 23:14:38 +09:00
Hazem Saleh
a13665d530 AAR-232: (android) Enhancement: Camera plugin code cleanup (#425) 2019-03-01 14:00:39 -05:00
Álvaro Herrero
81b878da59 GH-329: (android) Fixes issue: Exif data lost on many cases (#331)
* GH-329 android: Fix Exif data lost when correctOrientation is true

* Changed variable name
2019-02-21 16:51:54 +01:00
Jan Piotrowski
b261d3174f Add or update GitHub pull request and issue template 2019-02-11 18:38:15 +01:00
pz
24c8b6c43d GH-376 (ios) fixes UIImagePickerController cancel handling for iOS11+ (#377) 2018-12-16 12:20:01 +01:00
jcesarmobile
7ddb3dfbbe Remove deprecated platforms from docs (#394) 2018-12-10 00:52:39 +01:00
jcesarmobile
60e779559e Android: return DATA_URL for ALLMEDIA if it's an image (#382) 2018-12-09 12:39:06 +01:00
jcesarmobile
ce77aab010 CB-13813: (iOS) Remove old iOS code (#381) 2018-12-04 12:21:39 +01:00
Ams
cd72047dfc CB-13865: (IOS-Ipad) Making popover Window Size configurable using popoverOptions - imagePicker (#314) 2018-11-25 13:59:51 +01:00
Jan Piotrowski
bfbe4a1e52 fix quirk 2018-11-23 20:18:31 +01:00
jcesarmobile
86b0bf2534 CB-13837: fix TypeScript Definition for CameraPopoverOptions (#379) 2018-11-23 18:44:46 +01:00
Jan Piotrowski
a5a3d88152 clarify android quirk of cameraDirection 2018-11-20 23:40:08 +01:00
jcesarmobile
eed44330a4 Bump minor version (#370) 2018-11-13 23:02:58 +01:00
jcesarmobile
07e85742aa Remove automatic README generation (#365) 2018-11-01 16:13:52 +01:00
jcesarmobile
c0d78ad644 Revert "Bump minor version to 4.1.0-dev (#357)" (#363)
This reverts commit 7ee91a927d.
2018-10-30 16:44:58 +01:00
jcesarmobile
7ee91a927d Bump minor version to 4.1.0-dev (#357) 2018-10-24 13:26:07 +02:00
Jan Piotrowski
bcb26fbbd2 remove JIRA link 2018-10-04 01:15:01 +02:00
Chris Brody
dc73954108 Merge pull request #242 from DisruptiveMind/master
CB-11714: (windows) added check for encoding in savePhoto() without height/width
2018-10-03 18:42:51 -04:00
Jan Piotrowski
c1b9772dca replace double quotes with single quotes 2018-10-03 20:54:06 +02:00
Jan Piotrowski
a346212e90 also accept terms for android sdk android-27 2018-10-01 12:36:47 +02:00
Tyler Pham
eb57b02ba8 CB-11714: reuse picture.name instead of pictureName 2018-09-16 19:22:16 -04:00
Tyler Pham
dca4b9c82b simplify picture.copyAsync 2018-09-16 19:19:13 -04:00
Jan Piotrowski
403682b9d4 remove outdated docs translations that haven't been touched for 3 years 2018-08-18 22:57:23 +02:00
bvmensvoort
5c23b65af9 CB-14097: (android) Fix crash when selecting some files with getPicture (#322)
* CB-14097: (android) Fix crash when selecting some files with getPicture of urls with raw://

Handles both urls:
content://com.android.providers.downloads.documents/document/1111
content://com.android.providers.downloads.documents/document/raw%3A%2Fstorage%2Femulated%2F0%2FDownload%2Ffilename.pdf

* Optimization: Remove TextUtils dependency, return null when no id could be extracted
2018-07-06 00:16:25 +02:00
jcesarmobile
6899c5ece9 Update engines to use variables (#323) 2018-06-10 23:14:08 +02:00
Matthew Vander Vliet
5163d38465 CB-13384: (browser) Added deprecation of video.src compatibility (#288)
* CB-13384: (browser) Added deprecation of video.src compatibility

* CB-13384: Updated to reflect property detection rather than deprecation exception.
2018-05-25 12:44:23 +08:00
Andrew Decker
36343a8e07 Update CameraProxy.js (#284)
Remove audio flag from getUserMedia on the browser.  Including audio resulted in some nasty audio feedback, and audio isn't really needed for taking pictures anyway.
2018-05-24 13:42:39 +08:00
Nicco Kunzmann
ead7d5e6c2 replace warning emoji with warning unicode (#317)
Due to the use of the emoji, the documentation page shows
⚠️ instead of ⚠.
https://cordova.apache.org/docs/en/latest/reference/cordova-plugin-camera/index.html
2018-05-19 12:04:58 +02:00
jcesarmobile
e334656933 CB-14017 (android): Make com.android.support:support-v4 version configurable (#318) 2018-05-19 01:59:48 -04:00
Hazem Saleh
5ec121bf98 CB-14047: (android) CameraLauncher: Replacing Repeated String literals with final variables (#319) 2018-04-22 14:33:52 -04:00
Steve Gill
d9d80e40c1 Set VERSION to 4.0.4-dev (via coho) 2018-04-12 18:06:58 -07:00
Steve Gill
6ce1443622 fixed issue with version, 4.0.3 2018-04-12 18:04:49 -07:00
Steve Gill
37e12e85fb Set VERSION to 4.0.4-dev (via coho) 2018-04-12 17:16:12 -07:00
Steve Gill
9d05a1e58f CB-14030 Updated version and RELEASENOTES.md for release 4.0.3 (via coho) 2018-04-12 17:06:17 -07:00
Joe Bowser
c8581ba2c9 Merge pull request #275 from cjpearson/CB12953
CB-12593: (android) Fix potential FileProvider conflicts
2018-03-14 12:44:35 -07:00
jcesarmobile
e36482c7ba Fix a mistake in the examples of usage descriptions (#313) 2018-02-12 10:36:58 +01:00
Julio César
7c90555bd4 CB-13854(ios): fix Camera opens in portrait orientation on iphones 2018-02-11 21:44:56 -05:00
Tsuruda
e25aed97c5 modified init value (#264) 2018-02-11 18:22:34 +01:00
Alpesh Patel
bf935dfbd2 CB-13415 (android) Importing corrupt images using the Camera plugin c… (#309)
* CB-13415 (android) Importing corrupt images using the Camera plugin crashes the app
2018-02-08 13:12:16 +01:00
Suraj Pindoria
ad8788a5e6 CB-13826 Incremented plugin version. 2018-01-25 11:47:20 -08:00
Suraj Pindoria
4b276ee534 CB-13826 Updated version and RELEASENOTES.md for release 4.0.2 2018-01-25 11:40:16 -08:00
Joe Bowser
4b99623eda Merge pull request #308 from okode/android8_permission_request_fix
CB-13781: (android) Fixed permissions request on Android 8 to save a …
2018-01-15 14:13:07 -08:00
rpanadero
36ea63a60f CB-13781: (android) Fixed permissions request on Android 8 to save a photo into the photo album 2018-01-15 13:05:10 +01:00
jcesarmobile
e6a4738031 Merge pull request #307 from jcesarmobile/CB-13747
CB-13747: Add build-tools-26.0.2 to travis
2018-01-10 23:46:04 +01:00
Julio César
c46fe3b31d CB-13747: Add build-tools-26.0.2 to travis 2018-01-09 20:32:55 +01:00
jcesarmobile
67718544a8 Fix release notes (#304) 2017-12-30 00:59:38 -05:00
Simon MacDonald
b00cf97a04 Set VERSION to 4.0.2-dev (via coho) 2017-12-27 19:13:49 -05:00
Simon MacDonald
fb02f48745 CB-13714 Updated version and RELEASENOTES.md for release 4.0.1 (via coho) 2017-12-27 19:13:36 -05:00
jcesarmobile
6bf45f005a Merge pull request #303 from jcesarmobile/CB-13701
CB-13701 Fix to allow 4.0.0 version install
2017-12-27 10:55:32 +01:00
Julio César
96b7f55ec2 CB-13701Fix to allow 4.0.0 version install 2017-12-27 00:00:45 +01:00
Steve Gill
82f1c83a76 Set VERSION to 4.0.1-dev (via coho) 2017-12-15 17:26:41 -08:00
Steve Gill
4ae0de1c5e CB-13681 Updated version and RELEASENOTES.md for release 4.0.0 (via coho) 2017-12-15 17:25:06 -08:00
Steve Gill
b79c659c92 Merge pull request #301 from surajpindoria/removePlatforms
CB-13661: Remove deprecated platforms
2017-12-13 17:35:44 -08:00
Suraj Pindoria
7fad5d5786 CB-13661: Remove deprecated platforms 2017-12-12 11:09:29 -08:00
Steve Gill
1f86358156 Set VERSION to 3.0.1-dev (via coho) 2017-11-06 14:38:37 -08:00
Steve Gill
d456eeb711 CB-13542 Updated version and RELEASENOTES.md for release 3.0.0 (via coho) 2017-11-06 14:37:41 -08:00
Steve Gill
f761934814 Merge pull request #290 from JoseExposito/master
CB-13421: (osx) Added macOS support
2017-11-03 22:21:09 -07:00
Steve Gill
43b3a911c2 Merge pull request #297 from jcesarmobile/CB-13515
CB-13515 (all): Add 'protective' entry to cordovaDependencies
2017-11-01 13:39:41 -07:00
Julio César
8f033f53db CB-13515 (all): Add 'protective' entry to cordovaDependencies 2017-11-01 12:04:34 +01:00
Julio César
51d665a7a1 CB-13332 (iOS): document NSPhotoLibraryAddUsageDescription
This closes #296
2017-10-21 17:27:52 +02:00
Julio César
9f480b10cb CB-13264 (iOS): Remove ios usage descriptions
This closes #295
2017-10-21 16:45:13 +02:00
Alexander Sorokin
a6706aef5f CB-13473: (CI) Removed browser builds from AppVeyor 2017-10-20 10:11:26 +03:00
Alexander Sorokin
fb213b2b38 CB-13472: (CI) Fixed Travis Android builds again 2017-10-20 08:58:12 +03:00
Julio César
3e24b15934 CB-13446: Sync template with previous doc changes
This closes #291
2017-10-19 18:38:08 -07:00
Kelvin Dart
2acda2d2f9 CB-13294 Remove cordova-plugin-compat
This closes #293
2017-10-19 18:28:14 -07:00
José Expósito
97d2014d62 Adds macOS support 2017-10-10 17:11:10 +02:00
Alexander Sorokin
b2107e0818 CB-13299 (CI) Fix Android builds 2017-09-19 08:58:14 +03:00
Audrey So
16c4325fef CB-12895 : updated src files to use eslint format 2017-07-31 13:29:36 -07:00
Audrey So
80342b0ddd CB-12985 : setup eslint and removed jshint 2017-07-31 11:28:15 -07:00
Alexander Sorokin
55d419a36e CB-13028 (CI) Browser builds on Travis and AppVeyor 2017-07-25 14:50:55 +03:00
Alexander Sorokin
5574490bc3 CB-13002: (Android, iOS) Fix occasional Appium tests failures 2017-07-10 14:51:10 +03:00
Alexander Sorokin
f1b0ccec56 CB-13000: (CI) Speed up android builds 2017-07-10 10:02:24 +03:00
Alexander Sorokin
e69240f251 CB-12991: (CI) Updated CI badges 2017-07-06 13:58:47 +03:00
Alexander Sorokin
5b3a99a6db CB-12990 (iOS) Optimized Appium tests 2017-07-06 12:04:19 +03:00
José Luis Ballesteros del Val
3b8f64e330 CB-12964: (android) Fix of bug when Pictures folder did not exist.
If someone had removed Pictures folder in android, plugin failed trying to move there the new photo. This happened because plugin did not check the existence of this folder, and if not, it did not complete the folder tree.

This closes #273
2017-07-04 14:03:10 +03:00
Alexander Sorokin
f667ba6179 CB-12982: (Android, iOS) Appium tests: try to create a session harder 2017-07-03 18:01:34 +03:00
Connor Pearson
cfefa53272 CB-12593: (android) Fix potential FileProvider conflicts 2017-06-30 10:15:43 -04:00
Alexander Sorokin
77539558e6 CB-12935: (windows) Enable paramedic builds on AppVeyor 2017-06-30 09:30:25 +03:00
Alexander Sorokin
cba99940a7 CB-12935: (android, ios) Run paramedic tests on Travis 2017-06-23 09:56:20 +03:00
Jacques de Villiers
7155b636d5 Incorrect "JIRA issue tracker" link in Readme 2017-06-19 14:37:15 +01:00
Shazron Abdullah
160ed2d03f CB-12912 - Incorrect 'Report Bugs' link in README
This closes #270
2017-06-14 01:59:09 -07:00
Sergii Stotskyi
c3d7e55ad4 CB-12682: (ios, android): changes cancel error message to be consistent for ios android 2017-06-07 07:36:30 +03:00
Alexander Sorokin
1b218cd8a0 CB-12764: (android) Adapt Appium tests for Android 7 2017-06-02 15:02:10 +03:00
filmaj
51e5c02dcb CB-12847: fixed bugs entry in package.json. 2017-05-25 12:35:40 +02:00
filmaj
26d13b0245 CB-12847: added bugs entry to package.json. 2017-05-24 21:11:53 +02:00
filmaj
ef617cc943 Close #265 2017-05-10 09:15:40 -07:00
filmaj
1422b0a4f2 Set VERSION to 2.4.2-dev (via coho) 2017-04-27 10:27:41 -07:00
filmaj
ba9a803b69 CB-12736 Updated version and RELEASENOTES.md for release 2.4.1 2017-04-27 10:26:08 -07:00
Alexander Sorokin
9615620843 CB-12622: Updated build badges in README 2017-04-26 14:29:16 +03:00
Nikita Matrosov
a33c35152e CB-12650: Fix manual test for uploading image 2017-04-25 15:25:20 +03:00
filmaj
eb98015e8a Close #256 2017-04-24 16:40:08 -07:00
filmaj
3c48ea9c9c Close #258 2017-04-24 16:30:53 -07:00
Steve Gill
2286bb3bb2 CB-12685: added package.json to tests folder 2017-04-21 18:15:33 -07:00
Alexander Sorokin
9badea4c95 CB-12622: (android) Appium tests: Bust Android 6 and 7 permission dialogs 2017-04-20 14:58:03 +03:00
Alexander Sorokin
180f7b5510 CB-12618: (android) Appium tests: Handle native cling 2017-03-30 17:52:15 +03:00
Steve Gill
d0b381aad8 CB-12519 updated incorrect version in RELEASENOTES 2017-03-02 16:06:15 -08:00
Steve Gill
926fbf0e8c Set VERSION to 2.4.1-dev (via coho) 2017-03-02 15:44:42 -08:00
Steve Gill
e4ff41c07c CB-12519 Updated version and RELEASENOTES.md for release 2.4.0 2017-02-28 17:41:23 -08:00
Alexander Sorokin
4fc25154f3 CB-12501 (Android) Appium tests don't use XPath selectors anymore 2017-02-23 20:01:59 +03:00
Alexander Sorokin
7f616d16f1 CB-12469 (ios) Appium tests can now run on iOS 10 2017-02-20 13:16:53 +03:00
Joe Bowser
dfbca19a7a Close #170 2017-02-02 12:48:05 -08:00
Joe Bowser
86e546f868 Close #169 2017-02-02 12:45:57 -08:00
Joe Bowser
f2ca5ed79f Close #143 2017-02-02 12:43:42 -08:00
Joe Bowser
ab7e02f0b8 Close #158 2017-02-02 12:42:27 -08:00
Joe Bowser
899f6d8059 Close #192 2017-02-02 12:40:21 -08:00
Joe Bowser
aa8a5945dd Close #220 2017-02-02 12:38:10 -08:00
Joe Bowser
c06480f4e3 Close #239 2017-02-02 12:37:01 -08:00
Joe Bowser
5ca4d8b082 Close #248 2017-02-02 12:34:57 -08:00
Joe Bowser
bba8283d98 CB-12005: Changing the getOrientation method to return the defined enumerated EXIF instead of orientation in degrees for Consistency
This closes #252
2017-02-02 12:10:42 -08:00
Joe Bowser
c27725ce66 Close #243 2017-01-31 15:34:39 -08:00
Julio César
415412cfef Closing merged pull request: close #251 2017-01-31 01:15:37 +01:00
Julio César
5ebda25164 Closing invalid pull request: close #247 2017-01-31 01:12:01 +01:00
Sergey Zolotarev
d29c767f07 CB-12368: Fix permission check on Android
The plugin was checking whether camera permission was granted but then
actually requested permission for external storage.

Surprisingly enough this fixed CB-12368.
2017-01-30 23:52:54 +01:00
daserge
0ad5bdd9ff CB-12353 Corrected merges usage in plugin.xml 2017-01-20 15:35:30 +03:00
Nikita Matrosov
d6bd9ae3b3 CB-12369: Add plugin typings from DefinitelyTyped
This closes #250
2017-01-20 10:58:49 +03:00
Alexander Sorokin
81f9433606 CB-12363 Added build badges for iOS 9.3 and 10.0 2017-01-18 13:27:26 +03:00
filmaj
05594c4646 CB-12312: [Appium] [Android] A few changes to the tests:
- updated comments on how to run the tests. extra comments around functionality at certain points in the automation.
 - stub of a resolution checker on test startup - still need to figure out acceptable values.
 - moved session shutdown to an afterAll clause.
 - changed resolution determiner from using webview-based values to using the native windows dimensions - this helps as the webview values may be scaled down intentionally by manufacturers (via changing devicePixelRatio). furthermore, since the screen dimension automation is used purely for native UI automation, better to use the dimensions reported by the native context rather than the web context.
 - when finding elements by XPath, use multiple calls to avoid a Windows emulator + Android bug. Made this pattern consistent in the entire test.
2017-01-03 06:36:36 -08:00
Shazron Abdullah
a364e79482 CB-12236 - Fixed RELEASENOTES for cordova-plugin-camera 2016-12-11 12:41:08 -08:00
Alexander Sorokin
42fc8e0bcd CB-12230 Removed Windows 8.1 build badges 2016-12-09 14:22:12 +03:00
Shazron Abdullah
ee5537694a CB-12224 Incremented plugin version. 2016-12-07 16:55:06 -08:00
Shazron Abdullah
9eba35e2f6 CB-12224 Updated version and RELEASENOTES.md for release 2.3.1 2016-12-07 16:39:43 -08:00
Shazron Abdullah
8b83171ee2 Fix missing license headers. 2016-12-07 16:19:39 -08:00
Tyler Pham
a201722f6d CB-11714: (windows) added extra check for content-type in savePhoto() without options.targetWidth/Height 2016-12-01 14:12:01 -05:00
Vladimir Kotikov
c9e6a9a38a CB-12086 Regenerate README.md from template 2016-11-14 10:01:22 +03:00
Chris Rae
cc48945f37 Added NSPhotoLibraryUsageDescription parameter to example install command
Fixing some usages of NSPhotoLibraryUsageDescriptionentry

 This closes #240
2016-11-13 23:36:38 +01:00
Joe Bowser
8b3410bcc6 Close #124: I can crop fine with Photos. We should not have adopted Crop, since it makes no sense on Android. 2016-11-09 10:05:33 -08:00
Simon MacDonald
485a11e0f4 Updating compat dependency to 1.1.0 or better 2016-11-07 21:40:38 -05:00
Joe Bowser
2d47a26271 Close #199. We save photos to a shared Pictures directory, similar to the behaviour of the Twitter application 2016-11-07 16:23:16 -08:00
Joe Bowser
2d2352f695 Close #201. Running out of memory shouldn't be graceful. 2016-11-07 16:21:17 -08:00
Joe Bowser
2f003d2b49 Close #228. We don't require these permissions on Camera, since we use intents. 2016-11-07 16:19:00 -08:00
Joe Bowser
3a90bb7d55 Close #241 2016-11-07 16:11:45 -08:00
Joe Bowser
b13cbdeb16 Merge branch 'nougat_camera'
This closes #235
2016-11-07 15:59:20 -08:00
Joe Bowser
ee192d94b4 Bumping the CI 2016-11-07 15:49:52 -08:00
Joe Bowser
d9eb83bcb9 CB-11625: Forgot to add CordovaUri.java to plugin.xml 2016-10-27 13:38:46 -07:00
Joe Bowser
84f96c1067 CB-11625: Files Provider does not work with Android 4.4.4 or lower, and I have no idea why. Working around with CordovaUri 2016-10-27 13:37:03 -07:00
Joe Bowser
61064ae3ed CB-11625 (Android) : Make this work with previous versions of Cordova via cordova-plugin-compat 2016-10-21 15:12:34 -07:00
Shazron Abdullah
9ec8aea073 CB-11917 - Remove pull request template checklist item: "iCLA has been submitted…"
This closes #237
2016-10-04 21:39:29 -07:00
Julio César
9db952e161 Closing invalid pull request: close #98 2016-09-24 00:47:37 +02:00
Steve Gill
06d609cfa4 CB-11832 Incremented plugin version. 2016-09-09 16:08:02 -07:00
Steve Gill
cc1076d3cb CB-11832 Updated version and RELEASENOTES.md for release 2.3.0 2016-09-08 23:38:52 -07:00
Vladimir Kotikov
48d4213b2d CB-11795 Add 'protective' entry to cordovaDependencies
The entry is required to protect end-users from fetching edge versions of the plugin by incompatible version of cordova. This also assumes that we will not introduce any regressions in compatibility w/ cordova in minor and patch releases. On every major release we will need to add similar entry with _next_ major version.

 This closes #234
2016-09-08 11:40:37 +03:00
Jacques de Villiers
9b566d3f0b CB-11661: (ios) Add mandatory iOS 10 privacy description
Add support for photoalbum description

 This closes #236
2016-09-06 23:22:58 +02:00
Joe Bowser
b63a0d83e0 Merging API 24 code with master including large refactor 2016-09-01 15:11:33 -07:00
Vladimir Kotikov
9fe94479e2 CB-11661: (ios) Add mandatory iOS 10 privacy description
This commit adds corresponding change to README template so changes from a3af38a won't be lost
2016-09-01 16:08:20 +03:00
Steve Gill
2f89666db7 Revert "close #229"
This reverts commit fa58e83fca.
2016-08-30 11:51:59 -07:00
swbradshaw
f8682b9162 Removed unneeded file
This closes #197
2016-08-29 10:46:14 -07:00
swbradshaw
0ed6406864 Merge remote-tracking branch 'refs/remotes/apache/master'
Rebase from Master
2016-08-26 20:30:35 -04:00
Steve Gill
fa58e83fca close #229 2016-08-25 16:20:16 -07:00
mhartington
a3af38ad5b CB-11661: (ios) Add mandatory iOS 10 privacy description 2016-08-25 16:17:28 -07:00
Tyler Pham
c98607c613 CB-11714: (windows) added more explicit content-type when converting to target data on canvas
This closes #232
2016-08-25 10:00:41 +03:00
Vladimir Kotikov
b89645c749 CB-11295 Add WP8.1 quirk when choosing image from photoalbum 2016-08-23 16:18:13 +03:00
Vladimir Kotikov
1beeafb6e8 CB-10067 Update PictureSourceType JSDoc to reflect README update 2016-08-23 16:18:00 +03:00
Vladimir Kotikov
7813ad9bef CB-9070 Update CameraPopoverHandle docs to reflect README update 2016-08-23 16:16:41 +03:00
Simon MacDonald
6e19147b09 Plugin uses Android Log class and not Cordova LOG class 2016-08-22 15:52:52 -04:00
Alexander Sorokin
9f159d757a CB-11631 Appium tests: A working fix for a flaky "selection canceled" failure 2016-08-17 17:35:23 +03:00
Alexander Sorokin
62d1b01e81 CB-11709 Tests should use resolveLocalFileSystemURL() instead of deprecated resolveFileSystemURI() 2016-08-16 19:19:22 +03:00
Alexander Sorokin
92d67d990d Closing invalid PR
This closes #219
2016-08-16 14:29:26 +03:00
Alexander Sorokin
0accbf560b CB-11695 Increased session creation timeout for Appium tests 2016-08-16 14:03:09 +03:00
Alexander Sorokin
e588907ac7 CB-11631 Appium tests: A fix for a flaky "selection cancelled" failure 2016-08-13 16:58:33 +03:00
Joe Bowser
3ed3d887ca BuildConfig from test project crept in source code thanks to Android Studio, removing 2016-08-04 11:35:39 -07:00
Joe Bowser
f010394af8 WTF. Directory, not file. Not sure why I did that 2016-08-04 11:16:29 -07:00
Joe Bowser
00e0a7dc46 CB-11625: Managed to get Content Providers to work with a weird mix of Content Providers and non-Content Providers 2016-08-03 14:43:11 -07:00
Alexander Sorokin
fee72c7c04 CB-11656 (Android) Appium tests: Fixed side menu opening on some more resolutions 2016-08-02 18:11:19 +03:00
Alexander Sorokin
5807458a1d CB-11656 (Android) Appium tests: Fixed side menu opening on certain resolutions 2016-08-02 13:05:12 +03:00
Julio César
c13e9f327b CB-11376: (ios): fix CameraUsesGeolocation error
If it's not a camera picture don't use geolocation

 This closes #226
2016-08-02 00:16:38 +02:00
Julio César
7e8fe0bae9 CB-10067: (ios) clarifications on PictureSourceType
This closes #227
2016-08-01 00:27:07 +02:00
Julio César
3f8c53f7f3 CB-11410: (ios) fix cameraPopoverHandle.setPosition
This closes #224
2016-07-31 18:25:03 +02:00
Julio César
4e439d85c3 CB-9070. (ios) Fixed CameraPopoverHandle documentation
This closes #225
2016-07-31 18:20:50 +02:00
Joe Bowser
b62fdf50f7 Adding provider_paths.xml so this works 2016-07-29 13:33:51 -07:00
Joe Bowser
744d72a33b Partially modified plugin.xml 2016-07-29 09:07:03 -07:00
Joe Bowser
3d26986bfd CB-11625: Working on fix to API 24 no longer allowing File URIs to be passed across intents 2016-07-27 14:06:07 -07:00
Vladimir Kotikov
fed798e6c7 CB-11447 Respect output format when retrieving images from gallery 2016-07-26 15:59:52 +03:00
Vladimir Kotikov
2027d69606 CB-11447 Resolve iOS tests failures due to iOS quirks
* Skip image type verification if source is gallery
  and destination is native uri
* Update docs t oclarify how camera works on iOS in
  some edge cases
2016-07-26 15:59:49 +03:00
Alexander Sorokin
7129fb2c12 CB-11553 Pend failing Appium tests on Sauce Labs for the time being (reverted from commit b695717240) 2016-07-12 12:28:58 +03:00
Alexander Sorokin
b695717240 CB-11553 Pend failing Appium tests on Sauce Labs for the time being 2016-07-11 16:16:52 +03:00
Alexander Sorokin
acff98058f CB-11498 [Android] Appium tests should not fail when there is no camera 2016-06-28 18:49:59 +03:00
Vladimir Kotikov
8a7326969f Add badges for paramedic builds on Jenkins 2016-06-10 11:15:20 +03:00
Alexander Sorokin
a05f169984 CB-11296: Appium: Better element clicking and session error handling 2016-05-19 19:05:28 +03:00
Alexander Sorokin
dcc81bfbe1 CB-11232 Appium tests: fixed element tapping on iOS 9 2016-05-18 12:02:44 +03:00
Alexander Sorokin
278b527702 CB-11183 Appium tests: Added image verification 2016-05-18 11:48:52 +03:00
Raghav Katyal
d7ca7edf88 Closing stale PRs. This closes #114, closes #104 2016-05-17 14:10:36 -07:00
Raghav Katyal
f283502545 Closing stale PRs. This closes #85, closes #93 2016-05-17 11:38:59 -07:00
Mikejo5001
a831e15a91 fixed some bad formatting that hid HTML tags and added link to sample
This closes #207
2016-05-17 10:58:26 -07:00
Nikhil Khandelwal
3586ea58a2 Closing stale PRs. Close #167 2016-05-16 12:51:33 -07:00
Nikhil Khandelwal
cc840b6cef Closing stale PRs. Close #147 2016-05-16 12:48:57 -07:00
Julio César
0115458ce8 Set android quality default value to 50 on the java code
Default value is set to 80 on the java code, but doc says that default
value is 50.

I’m changing it just for making code clearer, but default value is set
to 50 to all platforms in Camera.js if no value is passed
2016-05-16 19:43:01 +02:00
Richard Knoll
2eef096861 Moving message in PR template to a comment 2016-05-13 12:15:11 -07:00
Nikhil Khandelwal
cf35b1bb2a Add pull request template. This closes #213 2016-05-13 12:00:06 -07:00
Keith M
39bff2f41d CB-11228 browser: Add classes for styling purposes
This closes #212
2016-05-13 11:58:11 -07:00
Keith M
7551778e13 CB-10139 browser: Respect target width and height
This closes #210
2016-05-13 11:56:43 -07:00
swbradshaw
e3a431cbeb Reverted indenting done by Android Studio 2016-05-12 21:25:36 -04:00
swbradshaw
832d6e3bea Adding missing function 2016-05-12 13:19:35 -04:00
Nikhil Khandelwal
2a7469e065 Stale PRs: closes #149, closes #148, closes #155, closes #107, closes #71, closes #55, closes #14 2016-05-09 17:00:51 -07:00
Keith M
af98d57417 CB-11227 browser: Fix incorrect mime type
This closes #211
2016-05-09 14:09:30 -07:00
Alexander Sorokin
57b177f3fb CB-11162 Appium tests: retry spec on failure 2016-04-28 10:45:49 +03:00
swbradshaw
f2b4eeded0 CB-4078: Fix for orientation/scaling on Android 4.4+ devices
The only way to get rotation for photos in library (Gallery, File
System, Google Drive,etc) is to first create a temporary file from the
provider. Only then can we determine the orientation and scale the
bitmap correctly. By doing it in a central place, it eliminates reading
the inputstream repetitively in the plugin.
2016-04-27 22:27:37 -04:00
Steve Gill
d4a55f20ec CB-11165 removed peer dependency 2016-04-27 16:22:18 -07:00
Alexander Sorokin
68e18a97d1 CB-11147 Appium tests: generate descriptive spec names 2016-04-26 10:32:08 +03:00
Dmitry Blotsky
bfaef0ff25 CB-10996 Adding front matter to README.md 2016-04-22 19:43:08 -07:00
Alexander Sorokin
0ba547cd3c CB-11128 Appum tests: Fixed some of the flaky failures 2016-04-21 16:14:58 +03:00
Mikejo5001
6d058fe9e7 CB-11003: Added Sample section to the Camera plugin README
This closes #203
2016-04-15 15:44:38 -07:00
Steve Gill
daf5fa48dd CB-11091 Incremented plugin version. 2016-04-15 13:45:27 -07:00
Steve Gill
d124e03cb9 Updated version and RELEASENOTES.md for release 2.2.0 2016-04-15 13:08:26 -07:00
Omar Mefire
4202fff7ac CB-10873
- Avoid crash due to usage of uninitialized variable when writing geolocation data to image destination
    - Properly handle 'CameraUsesGeolocation' option by properly setting geolocation data in EXIF header in all cases

 This closes #205
2016-04-13 15:49:51 -07:00
Omar Mefire
def399fe51 CB-10873 Avoid crash due to usage of uninitialized variable when writing geolocation data to image destination 2016-04-13 15:49:50 -07:00
Alexander Sorokin
82c9f4524a CB-11073 Appium tests stability improvements 2016-04-13 12:42:51 +03:00
Simon MacDonald
a9c18710f2 Replace PermissionHelper.java with cordova-plugin-compat 2016-04-05 12:17:18 -04:00
Raghav Katyal
624ddd5ced Making focus handler work only for windows 10 phone 2016-03-23 18:33:09 -07:00
daserge
fb871d40e2 CB-10865 Run ios native tests on Travis
Updated cordova-ios tests dependency version to latest published
Changed the tests to reflect the current scaling behavior
Fixed a typo in manual test img.onloadend -> img.onload
2016-03-21 12:54:07 +03:00
riknoll
0cd962466d CB-10120 android: Fixing use of constants and PermissionHelper
This closes #179
2016-03-14 17:56:52 -07:00
ochakov
c12206ebc8 CB-10120 android: Fix missing CAMERA permission for Android M
According to the PR conversation, when android.permission.CAMERA
is not set in the package, there is no need to ask for the
camera permission. Also, checking now camera and storage
permissions separately, so if only one of them is missing, the
other one will be requested and not both.

Rebased by MatthewBooth and riknoll

This closes #142, closes #174
2016-03-14 17:03:26 -07:00
Richard Knoll
826aca3524 CB-10756: Adding sterner warnings about DATA_URL
This closes #193
2016-03-14 10:39:20 -07:00
Julio César
76c129c95e CB-10460 getRealPath return null in some cases
Now there is only a function to get the real path on API 11 and above.
2016-03-11 20:43:08 +01:00
Carlos Santana
fac7a53383 clean RELEASENOTES for bold font 2016-03-10 13:49:49 -05:00
Alexander Sorokin
1348d2e138 Appium tests: tweaking some timeouts and default screenshot path 2016-03-10 13:27:34 +03:00
Carlos Santana
c5f5a46e3e CB-10820 Incremented plugin version. 2016-03-09 22:34:17 -05:00
Carlos Santana
37dd471d0e CB-10820 Updated version and RELEASENOTES.md for release 2.1.1 2016-03-09 22:11:36 -05:00
Richard Knoll
a19c75253a CB-10825 android: Always request READ permission for gallery source
This closes #191
2016-03-09 17:56:20 -08:00
Carlos Santana
c20e031d42 added apache license header to appium files 2016-03-08 22:21:47 -05:00
Dmitry Blotsky
68a1150939 CB-10720 Fixed spelling, capitalization, and other small issues. 2016-03-03 15:21:40 -08:00
Raghav Katyal
9c906b2ab7 CB-10414: Adding focus handler to resume video when user comes back on leaving the app while preview was running 2016-03-02 14:15:01 -08:00
Alexander Sorokin
56b9469313 Appium tests: adjust swipe distance on Android 2016-03-02 17:39:59 +03:00
Alexander Sorokin
d51e23ad7b CB-10750 Appium tests: fail fast if session is irrecoverable 2016-03-02 13:23:51 +03:00
Raghav Katyal
2cd2528d1c Adding missing semi colon 2016-02-29 10:30:40 -08:00
Raghav Katyal
5f7f4f3e55 Adding focus handler to make sure filepicker gets launched when app is active 2016-02-26 14:15:27 -08:00
Miguel Revetria
20dcaf2cb3 CB-10128: [iOS] Fixed how checks access authorization to camera & library. This closes #146 2016-02-24 16:10:20 -08:00
daserge
b16c5234d5 CB-10636 Add JSHint for plugins 2016-02-24 17:14:58 +03:00
Alexander Sorokin
c1948fc0d4 CB-10639 Appium tests: Added some timeouts,
Taking a screenshot on failure,
Retry taking a picture up to 3 times,
Try to restart the Appium session if it's lost
2016-02-24 16:44:29 +03:00
Dmitry Blotsky
f792aaacc3 CB-10552 Replacing images in README.md. 2016-02-22 12:06:29 -08:00
Julio César
16636d18f2 Added a lot of more cases to get the real path
Added a lot of more cases to get the real path

This closes #175
2016-02-22 11:54:22 -08:00
Julio César
019346d188 Fix for CB-10625
getDocumentId was crashing in some cases.
Now, in case it crashes, it will use the original uri to query.
2016-02-22 11:23:53 -08:00
Alexander Sorokin
61b77951e1 CB-10619 Appium tests: Properly switch to webview 2016-02-16 16:28:43 +03:00
Alexander Sorokin
a060fb36f3 CB-10397 Added Appium tests 2016-02-12 14:13:46 +03:00
Sarangan Rajamanickam
77653183dd CB-10576: MobileSpec can't get results for Windows-Store 8.1 Builds
Fixing a minor syntax issue
2016-02-09 16:17:17 -08:00
t1st3
df734a522c chore: edit package.json license to match SPDX id
See [NPM package.json spec for licenses](https://docs.npmjs.com/files/package.json#license) and [SPDX license IDs](https://spdx.org/licenses/)

X-ref: https://github.com/apache/cordova-plugin-device/pull/48
2016-02-06 11:16:08 +01:00
Raghav Katyal
654286d373 CB-10539: Commenting out the verySmallQvga maxResolution option 2016-02-05 15:03:19 -08:00
Raghav Katyal
76ad059c9c CB-10541: Changing default maxResoltion to be highestAvailable for CameraCaptureUI 2016-02-04 12:14:16 -08:00
Laurent Deketelaere
5b38453262 CB-10113 Browser - Layer camera UI on top of all!
Adds CSS style {position: 'relative', z-index: 2147483647} (2147483647 is the highest possible z-index) on DOM appended elements.

This closes #134
2016-02-02 17:02:15 +10:00
Tim Barham
e48a7e5c5c CB-10502 Fix camera plugin exception in Chrome when click capture.
The MediaStream.stop() method has been deprecated as of Chrome 47. We were using it, and it was generating an exception.

If stop() method is not found, instead stop each individual track (the new way of doing it).
2016-02-02 16:31:39 +10:00
Raghav Katyal
06fcbf05a2 Adding comments 2016-01-21 14:11:59 -08:00
PerfectionCSGO
9a9081b0d4 Camera tapping fix 2016-01-21 14:07:51 -08:00
Steve Gill
6f7ce333cc CB-10368 Incremented plugin version. 2016-01-15 16:58:32 -08:00
Steve Gill
0f32b78c82 CB-10368 Updated version and RELEASENOTES.md for release 2.1.0 2016-01-15 16:35:05 -08:00
Steve Gill
eb009471ab added .ratignore 2016-01-15 15:09:14 -08:00
riknoll
1d32ea46f0 CB-10319 android: Adding reflective helper methods for permission requests 2016-01-12 17:42:29 -08:00
riknoll
e2193631d5 CB-9189 android: Implementing save/restore API to handle Activity destruction 2016-01-05 14:18:43 -08:00
Shazron Abdullah
e8fa1695c4 CB-10241 - App Crash cause by Camera Plugin ios 7 2015-12-22 17:54:07 -08:00
Steve Gill
e1911a3c78 CB-10035 Incremented plugin version. 2015-11-30 17:57:07 -08:00
Raghav Katyal
ef5484a2aa CB-8940 Setting z-index values to maximum for UI buttons. This closes #140. 2015-11-19 17:36:06 -08:00
Steve Gill
b3376e2389 CB-10035 linked issues in RELEASENOTES.md 2015-11-18 22:11:41 -08:00
Steve Gill
ee9884e97b CB-10035 Updated version and RELEASENOTES.md for release 2.0.0 2015-11-18 19:45:05 -08:00
Steve Gill
1cf4feee60 removed r prefix from tags 2015-11-18 14:53:10 -08:00
Steve Gill
847add6870 CB-10035 Updated RELEASENOTES to be newest to oldest 2015-11-18 13:54:08 -08:00
Jesse MacFadyen
63ac782b32 remove unneeded weakness 2015-11-17 16:56:35 -08:00
Jesse MacFadyen
7f3a0a5483 CB-8863 correct block usage for async calls 2015-11-17 16:37:45 -08:00
riknoll
036cdfdeb8 CB-5479 android: changed saveToPhotoAlbum to save uncompressed images 2015-11-17 12:03:30 -08:00
riknoll
2bb134bf6b CB-9169 android: Fixed filetype for uncompressed images and added quirk 2015-11-10 17:26:07 -08:00
Joe Bowser
88592575fe CB-9446 related: Removing CordovaResource library code in favour of the code we're supposed to be deprecating because that at least works. 2015-11-09 14:28:58 -08:00
daserge
f5217bf02b CB-9942 Normalize line endings in Camera plugin docs
Adds .gitattributes to ensure LF line endings in the repo
2015-11-04 12:01:21 +03:00
riknoll
9b444c39ba CB-9910 android: Add permission request for some gallery requests 2015-11-02 15:25:33 -08:00
Richard Knoll
5ff225d8df CB-7668 android: Adding a sterner warning for allowedit on Android 2015-10-29 14:35:58 -07:00
Dmitry Blotsky
3a8880d0c3 Actually fixing the contribute link. 2015-10-23 12:11:49 -07:00
Dmitry Blotsky
d0ad2f5065 Fixing contribute link. 2015-10-23 12:03:42 -07:00
Joe Bowser
44475d9df9 Using the CordovaResourceApi to fine paths of files in the background thread. If the file doesn't exist, return the content URI
We also do a refactor to bring this in line.  This code got bike-shedded
a bit.
2015-10-22 16:19:13 -07:00
Joe Bowser
2714060b09 Add engine tag for Cordova-Android 5.0.x 2015-10-22 16:19:13 -07:00
Joe Bowser
cbe17eec21 Fix permission handling 2015-10-22 16:19:12 -07:00
Joe Bowser
8024c5de49 CB-9583: Permissions for Marshmallow 2015-10-22 16:19:12 -07:00
Vladimir Kotikov
933b35b0d2 Closes stale pull requests. Close #91, close #82, close #59, close #20 2015-10-19 13:10:04 +03:00
Nelson Antunes
dbe3e3d2ca Try to use realpath filename instead of default modified.jpg 2015-10-15 01:21:05 +01:00
Jesse MacFadyen
a030c52f7f change 'case' to else-if. This closes #113 2015-10-14 18:08:01 +03:00
Julio César
b8a68af63f CB-6190 - iOS camera plugin ignores quality parameter
CB-6190 - iOS camera plugin ignores quality parameter in some
circunstances
Added a check to not downscale if quality is 100 or sourceType !=
UIImagePickerControllerSourceTypeCamera (according to the docs, images
from gallery aren’t downscaled). This closes #108
2015-10-14 17:09:44 +03:00
sgrebnov
837d6721f2 CB-9633 iOS Taking a Picture With Option destinationType:NATIVE_URI Doesn't Show Image
This closes #122
2015-10-14 16:19:48 +03:00
daserge
f20dfae735 CB-9745 Camera plugin docs should be generated from the source
Moved docs to jsdocs comments in the code, removed redundancy.
Moved Quirks and extra examples to errata sections of the docs TEMPLATE.md, linked the jsdoc comments to these sections.
Added dependencies to common plugin docs template and husky (precommit hook to regen the docs automatically).
Added gen-docs command to re-generate the docs.
Extended TOC manually [to include classes containing only one member](https://github.com/jsdoc2md/jsdoc-to-markdown/issues/34) (CameraPopoverHandle and CameraPopoverOptions).
Extended the docs via DMD template to include "Installation", "How to contribute" and "Docs are generated" warning.

github: close #129
2015-10-12 12:42:47 +03:00
sgrebnov
454a6f518c CB-9622 Windows Phone 8 Camera Option destinationType:NATIVE_URI is a NO-OP
•	WP8 proxy now supports NATIVE_URI param
•	Treat NATIVE_URI same way as FILE_URI (similar to Android).

This closes #119
2015-09-09 13:01:48 +03:00
Vladimir Kotikov
dca8bd1943 CB-9623 Fixes various issues when encodingType set to png 2015-09-08 17:18:57 +03:00
Jakub Navrátil
cad9ab0419 CB-9591 Retaining aspect ratio when resizing 2015-09-01 10:49:12 -07:00
Murat Sutunc
ee5cfe89a5 CB-9443 Pick correct maxResolution
This closes #111, closes #56
2015-08-03 15:45:55 -07:00
Murat Sutunc
813d143667 CB-9151 Trigger captureAction only once 2015-08-03 10:09:15 -07:00
Murat Sutunc
110b3b3388 CB-9413 Close RandomAccessStream once copied 2015-07-27 11:39:38 -07:00
Andrey Kurdyumov
eeb5880580 CB-5661 Remove outdated iOS quirks about memory 2015-07-27 15:53:13 +06:00
Murat Sutunc
9dfd37cd66 Closing stale pull request: close #106 2015-07-13 16:02:12 -07:00
Gillardo
c50757c245 CB-9349 Focus control and nice UI
Removed old comment, move style text. close #106
2015-07-10 10:03:36 -07:00
Murat Sutunc
0264e56162 Closing stale pull request: close #73 2015-07-09 15:22:02 -07:00
Murat Sutunc
8ebaaa62bd Closing stale pull request: close #77 2015-07-09 15:19:19 -07:00
Jesse MacFadyen
11eaaa8b9f remove travis-ci integration 2015-07-07 17:36:10 -07:00
Joe Bowser
899802a202 CB-9259: Forgot to add another check on which URI we're using when fixing this thing the first time 2015-07-07 14:27:44 -07:00
Shazron Abdullah
1e607ddcc8 CB-9247 - typo 2015-06-25 06:22:24 -07:00
Shazron Abdullah
63110ea54c CB-9247 - Added macro to conditionally add NSData+Base64.h 2015-06-25 06:20:25 -07:00
Shazron Abdullah
b683315be6 CB-9247 - Fixes compilation errors with cordova-ios 4.x 2015-06-25 06:09:59 -07:00
Jesse MacFadyen
2e147ba9ca Merge branch 'CB-8498-take2' of https://github.com/vldmrrr/cordova-plugin-camera 2015-06-17 17:38:01 -07:00
Steve Gill
11498404fc CB-9192 Incremented plugin version. 2015-06-17 17:35:34 -07:00
vladimir
363dd02584 Fix returning native url on windows. 2015-06-17 16:14:58 -05:00
Steve Gill
437cf3d93a CB-9202 updated repo url to github mirror in package.json 2015-06-17 14:14:41 -07:00
Steve Gill
e8d52ef256 CB-9192 Updated version and RELEASENOTES.md for release 1.2.0 2015-06-17 12:36:01 -07:00
Murat Sutunc
647dac284b Closing stale pull request: close #84 2015-06-15 16:52:32 -07:00
Murat Sutunc
92c039e465 Closing stale pull request: close #66 2015-06-15 16:51:08 -07:00
Victor Sosa
b6a8a24b88 CB-9128 cordova-plugin-camera documentation translation: cordova-plugin-camera 2015-06-12 09:38:52 -05:00
Murat Sutunc
0d37267eb4 Update docs. This closes #100 2015-06-09 17:46:49 -07:00
Raymond Camden
88ee99011c attempt to fix npm markdown issue 2015-06-02 10:42:32 -05:00
Murat Sutunc
a6cc9271a0 CB-8883 fix picture rotation issue 2015-05-26 12:32:53 -07:00
Jesse MacFadyen
b3430e6f80 one more alias 2015-05-20 16:31:59 -07:00
Jesse MacFadyen
888a9661fb Fixed some nit white-space issues, aliased a little more 2015-05-20 16:17:57 -07:00
Jesse MacFadyen
15f66bf5cd major refactor : readability 2015-05-18 21:38:34 -07:00
Jesse MacFadyen
33ffb17c97 Patch for CB-8498, this closes #64 2015-05-18 17:32:14 -07:00
Murat Sutunc
a830b3e08b CB-8879 fix stripe issue with correct aspect ratio 2015-05-13 11:50:03 -07:00
Shazron Abdullah
706a3aa73e CB-8601 - iOS camera unit tests broken 2015-05-11 17:39:40 -07:00
Dan Polivy
9f9e5ef4a9 CB-7667 iOS8: Handle case where camera is not authorized (closes #49)
In iOS 7+, when the app does not have access to the camera, show a
prompt notifying the user so they're not puzzled by looking at a black
screen.

In iOS 8+, include a link on the dialog to open the Setting app to allow
the user to change their Camera privacy setting.

Signed-off-by: Shazron Abdullah <shazron@apache.org>
2015-05-11 17:26:00 -07:00
Jesse MacFadyen
b8b53c6254 add missing license header 2015-05-07 16:04:19 -07:00
Steve Gill
0436928275 CB-8959 Incremented plugin version. 2015-05-06 17:37:22 -07:00
Steve Gill
19feee9cb0 CB-8959 Updated version and RELEASENOTES.md for release 1.1.0 2015-05-06 17:07:39 -07:00
Murat Sutunc
69c687e0cf CB-8943 fix PickAndContinue issue on Win10Phone 2015-05-06 12:05:36 -07:00
Alan Kinzie
b0ee9dd905 CB-8253 Fix potential unreleased resources
There was a place (~line 701) in CameraLauncher.java where there was the
potential for input and output streams to never be closed if an exception
occurs at the wrong time.   There were some other places where an
InputStream was used anonymously, and so would never be closed.

This change introduces try/finally blocks to ensure that the streams will
always end up closed.

Change-Id: I479bceddcd631bfec45c3f5ee7e88ddb04c59073

Signed-off-by: Joe Bowser <bowserj@apache.org>

(Closes #90)
2015-05-06 10:17:43 -07:00
Joe Bowser
c2e0db2b86 CB-8909: Remove unused import from File 2015-04-24 14:24:47 -07:00
Murat Sutunc
8f07f562a2 CB-8404 typo fix cameraproxy.js
There was a missing comma on cameraproxy

github close #89
2015-04-22 14:39:40 -07:00
Murat Sutunc
1e8c836844 CB-8404 Rotate camera feed with device orientation
CR-1

CR-2
2015-04-21 10:56:04 -07:00
Vladimir Kotikov
b131021303 CB-8054 Support taking pictures from file for WP8 2015-04-21 15:22:40 +03:00
Murat Sutunc
0dabe94416 CB-8054 Support taking pictures from file for WP8
codereview

codereview 2
2015-04-16 14:19:01 -07:00
Murat Sutunc
fb8ce21711 CB-8405 Use z-index instead of z-order 2015-04-16 12:44:29 -07:00
Steve Gill
b67e4a09ed CB-8858 Incremented plugin version. 2015-04-15 16:00:21 -07:00
Steve Gill
d10bf50c61 CB-8858 Updated version in package.json for release 1.0.0 2015-04-15 15:50:47 -07:00
Steve Gill
b7af490a3e Revert "CB-8858 Incremented plugin version."
This reverts commit c2e4d1f36d.
2015-04-15 14:30:57 -07:00
Steve Gill
c2e4d1f36d CB-8858 Incremented plugin version. 2015-04-15 13:55:46 -07:00
Steve Gill
d0fe66e1d5 CB-8858 Updated version and RELEASENOTES.md for release 1.0.0 2015-04-15 11:06:37 -07:00
Connor Pearson
af36e74d05 CB-8780 - Display popover using main thread. Fixes popover slowness (closes #81) 2015-04-10 17:30:28 -07:00
Steve Gill
629dbcb712 CB-8746 bumped version of file dependency in package.json too 2015-04-09 17:08:52 -07:00
Steve Gill
bc7c4278ef CB-8746 bumped version of file dependency 2015-04-09 17:06:28 -07:00
Steve Gill
302aacb214 CB-8746 gave plugin major version bump 2015-04-09 16:51:58 -07:00
Vladimir Kotikov
3927735d09 CB-8706, CB-8707 saveToPhotoAlbum improvements and some refactoring
- On Windows we should use filePicker instead of programmatically
accessing user libs. This way the app doesnt have to depend on extra
capabilities.

- Some refactoring to help on navigating code easier

This closes #78
2015-04-07 21:48:00 +03:00
Murat Sutunc
9e11ab4dfb CR fixes 2015-04-03 11:08:00 -07:00
Steve Gill
d1dfc1e8ee CB-8747 updated dependency, added peer dependency 2015-04-01 23:01:47 -07:00
Steve Gill
ee4ac0d7b2 CB-8683 updated blackberry specific references of org.apache.cordova.camera to cordova-plugin-camera 2015-04-01 11:40:30 -07:00
Joe Bowser
d52b936bd8 CB-8782: Updated the docs to talk about the allowEdit quirks, it's not 100% working, but better than it was 2015-04-01 11:22:56 -07:00
Joe Bowser
9fe5b430aa CB-8782: Fixed the flow so that we save the cropped image and use it, not the original non-cropped. Crop only supports G+ Photos Crop, other crops may not work, depending on the OEM 2015-04-01 11:04:06 -07:00
Joe Bowser
23dbb8889a CB-8740: Removing FileHelper call that was failing on Samsung Galaxy S3, now that we have a real path, we only need to update the MediaStore, not pull from it in this case 2015-04-01 11:04:06 -07:00
Joe Bowser
ac4af88f55 CB-8740: Partial fix for Save Image to Gallery error found in MobileSpec 2015-04-01 11:04:06 -07:00
Steve Gill
f1ae0e9ccf CB-8683 changed plugin-id to pacakge-name 2015-03-31 16:39:18 -07:00
Steve Gill
563f0038fd CB-8653 properly updated translated docs to use new id 2015-03-31 16:05:59 -07:00
Steve Gill
ccbbdccc4c CB-8653 updated translated docs to use new id 2015-03-31 10:53:30 -07:00
Gene Connolly
04ed502d92 CB-8351 Fix custom implementation of integerValueForKey (close #79)
2ead6335c9 (diff-3cfd0e1f93894bd4e501e8e0e4634850)
2015-03-30 20:10:24 -04:00
Jesse MacFadyen
7209d38fa2 Fix cordova-paramedic path change, build with TRAVIS_BUILD_DIR, use npm to install paramedic 2015-03-24 23:16:57 -07:00
sgrebnov
8062a006c0 docs: added 'Windows' to supported platforms
Untill Windows8 is depracted we should have both Windows and Windows8
2015-03-19 17:47:46 +03:00
Murat Sutunc
29c9ea387d CB-8707 refactoring windows code to improve readability 2015-03-18 11:03:01 -07:00
Murat Sutunc
5ef04e552c CB-8706 use filePicker if saveToPhotoAlbum is true 2015-03-18 10:59:18 -07:00
Murat Sutunc
b8a700215a CB-8706 remove unnecessary capabilities from xml 2015-03-18 10:58:37 -07:00
Steve Gill
081aec5602 CB-8653 Updated Readme 2015-03-13 18:53:04 -07:00
Ian Clelland
9e4174caff CB-8659: ios: 4.0.x Compatibility: Remove use of deprecated headers 2015-03-13 10:46:47 -04:00
Steve Gill
7b2f453c25 CB-8646 Incremented plugin version. 2015-03-10 17:16:07 -07:00
Steve Gill
00cd249dd7 CB-8646 Updated version and RELEASENOTES.md for release 0.3.6 2015-03-10 17:12:32 -07:00
Steve Gill
b698e10386 added missing apache header 2015-03-10 17:01:00 -07:00
Jesse MacFadyen
2a93a48956 Fix localize key for Videos. This closes #58 2015-03-09 17:34:36 -07:00
Serge Huijben
929733b891 CB-8235 android: Fix crash when selecting images from DropBox with spaces in path (close #65) 2015-03-04 20:33:21 -05:00
Jesse MacFadyen
f39a08ba29 Merge branch 'patch-1' of https://github.com/vilic/cordova-plugin-camera 2015-03-03 14:43:07 -08:00
Murat Sutunc
bca73e6ee9 CB-8599 fix threading issue with cameraPicker (fixes #72)
Signed-off-by: Shazron Abdullah <shazron@apache.org>
2015-03-03 14:09:29 -08:00
Jesse MacFadyen
2c597a389b CB-8559 Integrate TravisCI 2015-03-02 11:47:04 -08:00
Victor Sosa
b780331389 CB-8438 cordova-plugin-camera documentation translation: cordova-plugin-camera 2015-02-27 12:47:23 -06:00
Steve Gill
57aa707c6a CB-8538 Added package.json file 2015-02-24 23:02:44 -08:00
Andrew Grieve
97514fb01e CB-8429 Incremented plugin version. 2015-02-04 20:54:02 -05:00
Andrew Grieve
799ed580d3 CB-8429 Updated version and RELEASENOTES.md for release 0.3.5 2015-02-04 20:12:45 -05:00
VILIC VANE
d7e708db09 add try ... catch for getting image orientation
There's bug in Windows Phone 8.1 causing Seek on a DssPhotoStream not working properly.
https://connect.microsoft.com/VisualStudio/feedback/details/783252
But a mis-oriented file is better than nothing, so try and catch.
2015-01-29 01:31:21 +08:00
Andrew Grieve
80b0048384 CB-8351 ios: Stop using now-deprecated [NSData base64EncodedString] 2015-01-27 10:56:19 -05:00
Andrew Grieve
2ead6335c9 CB-8351 ios: Stop using now-deprecated integerValueForKey: class extension 2015-01-27 10:47:04 -05:00
Andrew Grieve
2a0735d551 CB-8351 Unbreak build from previous commit 2015-01-27 10:19:46 -05:00
Andrew Grieve
4f056f0a73 CB-8351 Use argumentForIndex rather than NSArray extension 2015-01-23 09:49:20 -05:00
Shazron Abdullah
376bec2b96 CB-8032 - Camera Plugin - Add nativeURL external method support for CDVFileSystem->makeEntryForPath:isDirectory: (closes #57) 2015-01-09 16:24:31 -08:00
Shazron Abdullah
482f2ac2cc CB-7938 - Added XCTest unit tests project, with stubs (adapted from SplashScreen unit test setup) (closes #60) 2015-01-09 16:04:28 -08:00
Shazron Abdullah
35c653d24d CB-7937 - Re-factor iOS Camera plugin so that it is testable (closes #52)
Signed-off-by: Shazron Abdullah <shazron@apache.org>
2015-01-09 15:39:29 -08:00
Steve Gill
3ab650bdc9 CB-8110 Incremented plugin version. 2014-12-02 16:08:49 -08:00
Steve Gill
2045e0a644 CB-8110 Updated version and RELEASENOTES.md for release 0.3.4 2014-12-02 16:07:01 -08:00
Josh Soref
032531ae77 CB-7977 Mention deviceready in plugin docs 2014-11-06 17:34:12 -05:00
Josh Soref
fb4cff9cc0 CB-7979 Each plugin doc should have a ## Installation section 2014-11-06 17:34:09 -05:00
Kris Selden
0d389857cf Fix memory leak of image data in imagePickerControllerReturnImageResult
A __bridge_retained cast increments the count and requires a CFRelease, this should just be __bridge a cast since it isn’t being held onto by this method.

close #51
2014-10-09 20:26:45 -04:00
Brian Bolton
8b8db828f6 Pass uri to crop instead of pulling the low resolution image out of the intent return (close #43) 2014-10-07 15:47:04 -04:00
yoshifp
03fade661e Add orientation support for PNG to Android (closes #45) 2014-10-07 15:44:27 -04:00
Ian Clelland
c06ae46485 Merge branch 'master' of https://github.com/sosahvictor/cordova-plugin-camera 2014-10-06 14:24:33 -04:00
Steven Gill
dbe33a44ff Incremented plugin version. 2014-10-03 17:09:46 -07:00
Steven Gill
021743f20e Updated version and RELEASENOTES.md for release 0.3.3 2014-10-03 16:10:12 -07:00
Victor Sosa
53e42fc97b CB-7700 cordova-plugin-camera documentation translation: cordova-plugin-camera 2014-10-02 18:10:17 -05:00
Vladimir Kotikov
7413c1bcb2 CB-7600 Adds informative message to error callback in manual test. 2014-09-19 13:21:22 +04:00
Marcel Kinard
860fedece4 CB-7571 Bump version of nested plugin to match parent plugin 2014-09-17 16:27:13 -04:00
Marcel Kinard
9adc39ca2c CB-7571 Incremented plugin version. 2014-09-17 15:35:01 -04:00
Marcel Kinard
af18483d69 CB-7571 Updated version and RELEASENOTES.md for release 0.3.2 2014-09-17 15:27:39 -04:00
ktsour
3581c595d7 CB-7551 - [Camera][iOS 8] Scaled images show a white line
Signed-off-by: Shazron Abdullah <shazron@apache.org>
2014-09-15 23:13:34 -07:00
Wang Jinggang
513bfde49e CB-7558 - hasPendingOperation flag in Camera plugin's takePicture should be reversed to fix memory errors
Signed-off-by: Shazron Abdullah <shazron@apache.org>
2014-09-15 15:34:18 -07:00
Shazron Abdullah
43cb385f0e CB-7557 - Camera plugin tests is missing a File dependency 2014-09-15 15:31:04 -07:00
Edna Morales
45da410662 CB-7423 do cleanup after copyImage manual test
Signed-off-by: Shazron Abdullah <shazron@apache.org>
2014-09-15 15:27:46 -07:00
Lisa Seacat DeLuca
fcfe642147 CB-7471 cordova-plugin-camera documentation translation: cordova-plugin-camera 2014-09-15 17:24:53 -04:00
Vladimir Kotikov
05da230c2a CB-7413 Resolve 'ms-appdata' URIs with File plugin
+ typo fix in data URI check
2014-09-11 13:55:53 +04:00
Suraj Pindoria
986bf6fd3c Fixed minor bugs with the browser 2014-09-10 15:38:09 -07:00
Vladimir Kotikov
d84b875c44 CB-7433 Adds missing window reference to prevent manual tests failure on Android and iOS 2014-09-10 18:53:09 +04:00
Anis Kadri
1ffb14d764 Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera
Conflicts:
	plugin.xml
2014-09-05 11:08:40 -07:00
Lisa Seacat DeLuca
e851960910 CB-7249 cordova-plugin-camera documentation translation: cordova-plugin-camera 2014-09-05 11:08:15 -07:00
Shazron Abdullah
ae22820046 CB-4003 - Add config option to not use location information in Camera plugin (and default to not use it) 2014-09-05 11:08:15 -07:00
Shazron Abdullah
fa30a56760 CB-7461 - Geolocation fails in Camera plugin in iOS 8 2014-09-05 11:08:15 -07:00
Vladimir Kotikov
5c1394058c CB-7433 Fixes manual tests failure on windows 2014-09-05 11:08:15 -07:00
Vladimir Kotikov
6dcfa9cf9b CB-7378 Use single Proxy for both windows8 and windows. 2014-09-05 11:08:15 -07:00
Vladimir Kotikov
f3cfadb19e CB-7378 Adds support for windows platform 2014-09-05 11:07:49 -07:00
Marcel Kinard
e9a834955c CB-6958 Get the correct default for "quality" in the test 2014-09-05 11:07:49 -07:00
Edna Morales
5b84c38a43 add documentation for manual tests 2014-09-05 11:07:49 -07:00
Lisa Seacat DeLuca
af566264ef CB-7249 cordova-plugin-camera documentation translation: cordova-plugin-camera 2014-09-04 22:30:08 -04:00
Suraj Pindoria
a423e57c8a Updated docs for browser 2014-09-04 14:51:24 -07:00
Shazron Abdullah
481ff27727 CB-4003 - Add config option to not use location information in Camera plugin (and default to not use it) 2014-09-03 17:40:20 -07:00
Shazron Abdullah
599ab31090 CB-7461 - Geolocation fails in Camera plugin in iOS 8 2014-09-03 16:48:42 -07:00
Jesse MacFadyen
b3b43b1f3c Merge branch 'CB-7378' of https://github.com/MSOpenTech/cordova-plugin-camera 2014-09-02 18:45:37 -07:00
Suraj Pindoria
b2403c6076 Added support for the browser 2014-08-29 15:14:41 -07:00
Vladimir Kotikov
c8c3bf0782 CB-7433 Fixes manual tests failure on windows 2014-08-30 01:20:57 +04:00
Vladimir Kotikov
f3bc296da8 CB-7378 Use single Proxy for both windows8 and windows. 2014-08-27 17:18:22 +04:00
Vladimir Kotikov
938543c203 CB-7378 Adds support for windows platform 2014-08-27 17:15:47 +04:00
Marcel Kinard
e316e32808 CB-6958 Get the correct default for "quality" in the test 2014-08-25 15:28:44 -04:00
Edna Morales
8e1e5c8550 Merge new tests directory 2014-08-13 12:35:28 -04:00
Bryan Higgins
d53a7770d9 CB-7286 [BlackBerry10] Use getUserMedia if camera card is unavailable 2014-08-12 11:42:18 -04:00
Shazron Abdullah
42bf5d2983 CB-7180 - Update Camera plugin to support generic plugin webView UIView (which can be either a UIWebView or WKWebView) 2014-08-11 23:13:15 -07:00
Jesse MacFadyen
9064130fce Merge branch 'CB-6958' of https://github.com/stacic/cordova-plugin-camera 2014-08-07 11:58:07 -07:00
Steven Gill
6366aeba47 CB-7244 Incremented plugin version. 2014-08-06 19:24:26 -07:00
Steven Gill
823eb5d27a CB-7244 Updated version and RELEASENOTES.md for release 0.3.1 2014-08-06 18:58:20 -07:00
Lisa Seacat DeLuca
0d63ac27ca CB-7249cordova-plugin-camera documentation translation: cordova-plugin-camera 2014-08-01 16:22:53 -04:00
Staci Cooper
dbaa458b7f Renamed test dir, added nested plugin.xml 2014-07-31 12:45:05 -04:00
Edna Morales
f2eebeed0a add documentation for manual tests 2014-07-30 13:54:58 -04:00
Willy Aguirre
c696f6e0b3 update CameraProxy.js 2014-07-28 20:42:43 -05:00
Edna Morales
45a50c448e merging to work on top of test framework changes 2014-07-23 16:24:18 -04:00
Andrew Grieve
e8cbb106ae CB-7187 ios: Add explicit dependency on CoreLocation.framework 2014-07-21 23:01:10 -04:00
Staci Cooper
10e0efc503 CB-6958 added manual tests 2014-07-21 15:20:59 -04:00
Staci Cooper
cb7e19311a Merge branch 'master' of https://github.com/javierbb31/cordova-plugin-camera into CB-6958 2014-07-16 15:49:20 -04:00
Lisa Seacat DeLuca
9a26e97ac8 CB-7110cordova-plugin-camera documentation translation: cordova-plugin-camera 2014-07-09 14:42:25 -04:00
Bryan Higgins
f8d5ef643e [BlackBerry10] Doc correction - sourceType is supported 2014-07-08 09:33:38 -04:00
Lisa Seacat DeLuca
98749a611b CB-6127lisa7cordova-plugin-consolecordova-plugin-camera documentation translation: cordova-plugin-camera 2014-07-07 15:26:23 -04:00
ldeluca
08acf7bc49 Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera 2014-07-07 11:07:15 -04:00
Andrew Grieve
e4ab155fd0 CB-7071 android: Fix callback firing before CROP intent is sent when allowEdit=true 2014-07-03 13:21:52 -04:00
javierbb31
7305c64db0 CB-6958. Port camera tests to plugin-test-framework
Ported camera test from mobilespec to the new test-framework in jasmine
2.0
Added test folder.
Added tes.js file inside the test folder.
2014-06-30 15:37:18 -05:00
kieferhagin
f20703de20 Tweak docs to not use []'s for optional arg since that's JS array notation
close #21
2014-06-27 13:56:27 -04:00
Dominik Pesch
543c4198d8 CB-6875 android: Handle exception when SDCard is not mounted
close #29
2014-06-27 13:55:18 -04:00
Andrew Grieve
1650dce693 ios: Delete postImage (dead code) 2014-06-27 13:49:56 -04:00
Manu Garcia Urreta
5b8324e984 Prevent NPE on processResiultFromGallery when intent comes null
close #22
2014-06-27 13:33:03 -04:00
ldeluca
4aa85de064 Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera 2014-06-27 12:51:52 -04:00
Eirik Hoem
fa93b534d1 Remove iOS doc reference to non-existing navigator.fileMgr API
close #13
2014-06-27 12:10:35 -04:00
Raymond Camden
c1683000d2 Docs updated with some default values
close #35
2014-06-27 12:09:01 -04:00
ldeluca
1a495492c6 Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera 2014-06-23 12:23:29 -04:00
ldeluca
a07c85e8b4 Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera 2014-06-16 11:07:40 -04:00
Vladimir Kotikov
06ecc91fd1 Removes File plugin dependency from windows8 code. 2014-06-16 10:51:45 +04:00
ldeluca
05e3eed60e Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera 2014-06-11 09:55:29 -04:00
Vladimir Kotikov
ffd46c4ef5 Use WinJS functionality to resize image instead of File plugin functionality 2014-06-11 12:49:58 +04:00
Steven Gill
1cf38cd775 CB-6877 Incremented plugin version. 2014-06-05 13:40:49 -07:00
Steven Gill
4fa934e06f CB-6877 Updated version and RELEASENOTES.md for release 0.3.0 2014-06-05 13:39:42 -07:00
Jesse MacFadyen
1f51a3b61d Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera 2014-06-04 13:38:52 -07:00
Jesse MacFadyen
4bdb990b77 CB-5895 documented saveToPhotoAlbum quirk on WP8 2014-06-04 13:38:15 -07:00
Jesse MacFadyen
d00464e9d3 CB-2083 documented saveToPhotoAlbum quirk on WP8 2014-06-04 13:34:17 -07:00
Andrew Grieve
7b60a0b6d1 Remove deprecated symbols for iOS < 6 2014-06-04 14:22:41 -04:00
ldeluca
4c901d56be documentation translation: cordova-plugin-camera 2014-06-03 14:29:42 -07:00
ldeluca
5af2653f18 Lisa testing pulling in plugins for plugin: cordova-plugin-camera 2014-06-03 14:29:42 -07:00
ldeluca
9de98fcc0d Lisa testing pulling in plugins for plugin: cordova-plugin-camera 2014-06-03 14:29:41 -07:00
ldeluca
68453f2492 Lisa testing pulling in plugins for plugin: cordova-plugin-camera 2014-06-03 14:29:41 -07:00
ldeluca
61325f4620 Lisa testing pulling in plugins for plugin: cordova-plugin-camera 2014-06-03 14:29:41 -07:00
Maxim Ermilov
8ff4d3f16e ubuntu: use application directory for images 2014-06-03 14:25:01 -07:00
Marcel Kinard
6e93ebbf90 CB-6795 Add license 2014-05-30 11:21:48 -04:00
ldeluca
8719cb7342 documentation translation: cordova-plugin-camera 2014-05-27 21:35:58 -04:00
ldeluca
d5405ba2e0 Lisa testing pulling in plugins for plugin: cordova-plugin-camera 2014-05-27 21:21:31 -04:00
ldeluca
8760c99b31 Lisa testing pulling in plugins for plugin: cordova-plugin-camera 2014-05-27 17:49:11 -04:00
ldeluca
2eb71f648f Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera 2014-05-20 13:54:43 -04:00
Shashwat
199732845e Little fix in code formatting
github: close #28
2014-05-13 11:01:06 -04:00
Jesse MacFadyen
707426ece2 Merge branch 'CB-6613' of https://github.com/MSOpenTech/cordova-plugin-camera 2014-05-08 15:31:46 -07:00
Jesse MacFadyen
10e5455356 Merge branch 'CB-6612' of https://github.com/MSOpenTech/cordova-plugin-camera 2014-05-08 15:06:17 -07:00
mbillau
30a75e3fa7 Removed invalid note from CB-5398 2014-05-08 09:00:37 -04:00
ldeluca
7e9f099301 Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera 2014-05-05 09:59:51 -04:00
Vladimir Kotikov
9e0d943971 CB-6612 camera.getPicture now always returns encoded JPEG image 2014-05-05 09:27:45 +04:00
Vladimir Kotikov
87a5030771 CB-6613 Use WinJS functionality to get base64-encoded content of image instead of File plugin functionality 2014-05-02 12:46:45 +04:00
RemeR
0c9de56da5 CB-6576 - Returns a specific error message when app has no access to library.
Signed-off-by: Shazron Abdullah <shazron@apache.org>
2014-04-30 16:03:37 -07:00
Marcel Kinard
e8596fbc8e CB-6491 add CONTRIBUTING.md 2014-04-30 09:20:09 -04:00
Andrew Grieve
d899d7a4b8 CB-6546 android: Fix a couple bugs with allowEdit pull request
- Don't set width/height when they are not specified
- photolibrary returns null from getData when image is cropped
2014-04-29 00:51:09 -04:00
Andrew Grieve
c7d88e8b34 CB-6546 android: Add support for allowEdit Camera option
GitHub: Close #12
2014-04-29 00:49:29 -04:00
Ian Clelland
d6af2098c1 CB-6452 Incremented plugin version on dev branch. 2014-04-17 11:16:03 -04:00
Ian Clelland
b76b5ae670 CB-6452 Updated version and RELEASENOTES.md for release 0.2.9 2014-04-17 10:53:20 -04:00
Ian Clelland
f2a41e4b5e CB-6460: Update license headers 2014-04-16 16:15:25 -04:00
Jesse MacFadyen
85a986f589 CB-6422 [windows8] use cordova/exec/proxy 2014-04-08 15:53:51 -07:00
Jesse MacFadyen
4c2c567fd8 WP8 When only targetWidth or targetHeight is provided, use it as the only bound 2014-04-08 12:19:44 -07:00
Jesse MacFadyen
fe6dc72a75 Remove rotation test value 2014-04-08 12:03:22 -07:00
Jesse MacFadyen
ae2acd9ab2 cleanup, finalize implementations/consolidations 2014-04-07 18:13:57 -07:00
Jesse MacFadyen
f6e8548381 combining callbacks, removing lots of dupe code 2014-04-07 16:32:21 -07:00
Jesse MacFadyen
e7a3d70fe9 Fix camera issues, cropping, memory leaks CB-4027, CB-5102, CB-2737, CB-2387 2014-04-07 15:00:12 -07:00
James Jong
91d6e10b29 CB-6212 iOS: fix warnings compiled under arm64 64-bit
-one update to CDVCamera.m
2014-03-13 10:16:30 -04:00
Long Nguyen
6fb63fede5 Fix typo error in docs
from libarary to library

github: close #18
2014-03-13 09:59:53 -04:00
James Jong
c9bab1f94c CB-6212 iOS: fix warnings compiled under arm64 64-bit 2014-03-13 09:51:47 -04:00
Ryan Willoughby
5393a28191 Add rim xml namespaces declaration 2014-03-12 12:47:24 -04:00
ldeluca
2d3f10ea3f Merge branch 'master' of https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera 2014-03-04 12:42:16 -05:00
Andrew Grieve
2a7520112e Merge branch 'master' into dev
Conflicts:
	plugin.xml
2014-02-27 16:03:32 -05:00
Andrew Grieve
61a963d6fb Add NOTICE file 2014-02-27 15:36:55 -05:00
Andrew Grieve
3be1802c9e CB-6114 Incremented plugin version on dev branch. 2014-02-27 15:36:55 -05:00
Andrew Grieve
19a44608b8 CB-6114 Updated version and RELEASENOTES.md for release 0.2.8 2014-02-27 15:36:55 -05:00
ldeluca
80205f41e3 Lisa testing pulling in plugins for plugin: cordova-plugin-camera 2014-02-27 11:14:21 -05:00
ldeluca
92dd3eeee3 Lisa testing pulling in plugins for plugin: cordova-plugin-camera 2014-02-26 09:35:34 -05:00
88 changed files with 8972 additions and 2907 deletions

32
.appveyor.yml Normal file
View File

@@ -0,0 +1,32 @@
# appveyor file
# http://www.appveyor.com/docs/appveyor-yml
max_jobs: 1
shallow_clone: true
init:
- git config --global core.autocrlf true
image:
- Visual Studio 2017
environment:
matrix:
- nodejs_version: "10"
- nodejs_version: "12"
platform:
- x86
- x64
install:
- ps: Install-Product node $env:nodejs_version
- node --version
- npm install -g github:apache/cordova-paramedic
- npm install -g cordova
build: off
test_script:
- cordova-paramedic --config pr\windows-10-store --plugin . --justBuild

22
.asf.yaml Normal file
View File

@@ -0,0 +1,22 @@
# 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.
notifications:
commits: commits@cordova.apache.org
issues: issues@cordova.apache.org
pullrequests_status: issues@cordova.apache.org
pullrequests_comment: issues@cordova.apache.org

10
.eslintrc.yml Normal file
View File

@@ -0,0 +1,10 @@
root: true
extends: semistandard
rules:
indent:
- error
- 4
camelcase: off
padded-blocks: off
operator-linebreak: off
no-throw-literal: off

94
.gitattributes vendored Normal file
View File

@@ -0,0 +1,94 @@
* text eol=lf
# source code
*.php text
*.css text
*.sass text
*.scss text
*.less text
*.styl text
*.js text
*.coffee text
*.json text
*.htm text
*.html text
*.xml text
*.svg text
*.txt text
*.ini text
*.inc text
*.pl text
*.rb text
*.py text
*.scm text
*.sql text
*.sh text
*.bat text
# templates
*.ejs text
*.hbt text
*.jade text
*.haml text
*.hbs text
*.dot text
*.tmpl text
*.phtml text
# server config
.htaccess text
# git config
.gitattributes text
.gitignore text
.gitconfig text
# code analysis config
.jshintrc text
.jscsrc text
.jshintignore text
.csslintrc text
# misc config
*.yaml text
*.yml text
.editorconfig text
# build config
*.npmignore text
*.bowerrc text
# Heroku
Procfile text
.slugignore text
# Documentation
*.md text
LICENSE text
AUTHORS text
#
## These files are binary and should be left untouched
#
# (binary is a macro for -text -diff)
*.png binary
*.jpg binary
*.jpeg binary
*.gif binary
*.ico binary
*.mov binary
*.mp4 binary
*.mp3 binary
*.flv binary
*.fla binary
*.swf binary
*.gz binary
*.zip binary
*.7z binary
*.ttf binary
*.eot binary
*.woff binary
*.pyc binary
*.pdf binary

42
.github/ISSUE_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,42 @@
<!--
Please have a look at the issue templates you get when you click "New issue" in the GitHub UI.
We very much prefer issues created by using one of these templates.
-->
### Issue Type
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->
- [ ] Bug Report
- [ ] Feature Request
- [ ] Support Question
## Description
## Information
<!-- Include all relevant information that might help understand and reproduce the problem -->
### Command or Code
<!-- What command or code is needed to reproduce the problem? -->
### Environment, Platform, Device
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->
### Version information
<!--
What are relevant versions you are using?
For example:
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins
Other Frameworks: Ionic Framework and CLI version
Operating System, Android Studio, Xcode etc.
-->
## Checklist
<!-- Please check the boxes by putting an `x` in the `[ ]` like so: `[x]` -->
- [ ] I searched for already existing GitHub issues about this
- [ ] I updated all Cordova tooling to their most recent version
- [ ] I included all the necessary information above

50
.github/ISSUE_TEMPLATE/BUG_REPORT.md vendored Normal file
View File

@@ -0,0 +1,50 @@
---
name: 🐛 Bug Report
about: If something isn't working as expected.
---
# Bug Report
## Problem
### What is expected to happen?
### What does actually happen?
## Information
<!-- Include all relevant information that might help understand and reproduce the problem -->
### Command or Code
<!-- What command or code is needed to reproduce the problem? -->
### Environment, Platform, Device
<!-- In what environment, on what platform or on which device are you experiencing the issue? -->
### Version information
<!--
What are relevant versions you are using?
For example:
Cordova: Cordova CLI, Cordova Platforms, Cordova Plugins
Other Frameworks: Ionic Framework and CLI version
Operating System, Android Studio, Xcode etc.
-->
## Checklist
<!-- Please check the boxes by putting an x in the [ ] like so: [x] -->
- [ ] I searched for existing GitHub issues
- [ ] I updated all Cordova tooling to most recent version
- [ ] I included all the necessary information above

View File

@@ -0,0 +1,29 @@
---
name: 🚀 Feature Request
about: A suggestion for a new functionality
---
# Feature Request
## Motivation Behind Feature
<!-- Why should this feature be implemented? What problem does it solve? -->
## Feature Description
<!--
Describe your feature request in detail
Please provide any code examples or screenshots of what this feature would look like
Are there any drawbacks? Will this break anything for existing users?
-->
## Alternatives or Workarounds
<!--
Describe alternatives or workarounds you are currently using
Are there ways to do this with existing functionality?
-->

View File

@@ -0,0 +1,27 @@
---
name: 💬 Support Question
about: If you have a question, please check out our Slack or StackOverflow!
---
<!------------^ Click "Preview" for a nicer view! -->
Apache Cordova uses GitHub Issues as a feature request and bug tracker _only_.
For usage and support questions, please check out the resources below. Thanks!
---
You can get answers to your usage and support questions about **Apache Cordova** on:
* Slack Community Chat: https://cordova.slack.com (you can sign-up at http://slack.cordova.io/)
* StackOverflow: https://stackoverflow.com/questions/tagged/cordova using the tag `cordova`
---
If you are using a tool that uses Cordova internally, like e.g. Ionic, check their support channels:
* **Ionic Framework**
* [Ionic Community Forum](https://forum.ionicframework.com/)
* [Ionic Worldwide Slack](https://ionicworldwide.herokuapp.com/)
* **PhoneGap**
* [PhoneGap Developer Community](https://forums.adobe.com/community/phonegap)

35
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,35 @@
<!--
Please make sure the checklist boxes are all checked before submitting the PR. The checklist is intended as a quick reference, for complete details please see our Contributor Guidelines:
http://cordova.apache.org/contribute/contribute_guidelines.html
Thanks!
-->
### Platforms affected
### Motivation and Context
<!-- Why is this change required? What problem does it solve? -->
<!-- If it fixes an open issue, please link to the issue here. -->
### Description
<!-- Describe your changes in detail -->
### Testing
<!-- Please describe in detail how you tested your changes. -->
### Checklist
- [ ] I've run the tests to see all new and existing tests pass
- [ ] I added automated test coverage as appropriate for this change
- [ ] Commit is prefixed with `(platform)` if this change only applies to one platform (e.g. `(android)`)
- [ ] If this Pull Request resolves an issue, I linked to the issue in the text above (and used the correct [keyword to close issues using keywords](https://help.github.com/articles/closing-issues-using-keywords/))
- [ ] I've updated the documentation if necessary

10
.gitignore vendored
View File

@@ -12,12 +12,4 @@ Thumbs.db
*.swp
*.user
/node_modules/**

3
.npmignore Normal file
View File

@@ -0,0 +1,3 @@
.*
appveyor.yml
tests

117
.travis.yml Normal file
View File

@@ -0,0 +1,117 @@
# This Travis configuration file is built after a Cordova Paramedic
# specific template with minimal modifications and adaptations:
# https://github.com/apache/cordova-paramedic/blob/master/.travis.yml
sudo: false
addons:
jwt:
# SAUCE_ACCESS_KEY
secure: QivPLlqTVvOo3TJeHxuBOfxU6lho1I0IxQ3b68yntkEQQJko6kzleXHfgjf0a8aw8m38E3+fxaBWF1bGyucGwOLDWY8Ddt2P2xg44zdXH5EXHd9oIqAgngIdzLvUtH3Db2TbQEtIGOkrnNR2STovjqB7vHGLASQrgs4oL7r32/s=
env:
global:
- SAUCE_USERNAME=snay
- TRAVIS_NODE_VERSION=12
- ANDROID_API_LEVEL=28
- ANDROID_BUILD_TOOLS_VERSION=28.0.3
language: node_js
node_js: 12
# yaml anchor/alias: https://medium.com/@tommyvn/travis-yml-dry-with-anchors-8b6a3ac1b027
_ios: &_ios
os: osx
osx_image: xcode10.3
_android: &_android
language: android
os: linux
jdk: oraclejdk8
android:
components:
- tools
- build-tools-$ANDROID_BUILD_TOOLS_VERSION
- android-$ANDROID_API_LEVEL
licenses:
- "android-sdk-preview-license-.+"
- "android-sdk-license-.+"
- "google-gdk-license-.+"
matrix:
include:
# additional tests
- env: ADDITIONAL_TESTS_DIR=./tests/ios
language: objective-c
# local tests, without saucelabs
- env: PLATFORM=local/browser
<<: *_ios
- env: PLATFORM=local/ios-10.0
<<: *_ios
# many tests with saucelabs
- env: PLATFORM=browser-chrome
- env: PLATFORM=browser-firefox
- env: PLATFORM=browser-safari
- env: PLATFORM=browser-edge
- env: PLATFORM=ios-11.3
<<: *_ios
- env: PLATFORM=ios-12.0
<<: *_ios
- env: PLATFORM=ios-12.2
<<: *_ios
- env: PLATFORM=android-5.1
<<: *_android
- env: PLATFORM=android-6.0
<<: *_android
- env: PLATFORM=android-7.0
<<: *_android
- env: PLATFORM=android-7.1
<<: *_android
- env: PLATFORM=android-8.0
<<: *_android
- env: PLATFORM=android-8.1
<<: *_android
- env: PLATFORM=android-9.0
<<: *_android
before_install:
# manually install Node for `language: android`
- if [[ "$PLATFORM" =~ android ]]; then nvm install $TRAVIS_NODE_VERSION; fi
- node --version
- if [[ "$PLATFORM" =~ android ]]; then gradle --version; fi
- if [[ "$PLATFORM" =~ ios ]]; then npm install -g ios-deploy; fi
- npm install -g cordova
# install paramedic if not running on paramedic repo
- if ! [[ "$TRAVIS_REPO_SLUG" =~ cordova-paramedic ]]; then npm install -g github:apache/cordova-paramedic; fi
install:
- npm install
before_script:
- |
if [[ "$TRAVIS_REPO_SLUG" =~ cordova-paramedic ]]; then
# when used in the cordova-paramedic repo
TEST_COMMAND="npm run eslint"
PARAMEDIC_PLUGIN_TO_TEST="./spec/testable-plugin/"
PARAMEDIC_COMMAND="node main.js"
else
# when used in any other (plugin) repo
TEST_COMMAND="npm test"
PARAMEDIC_PLUGIN_TO_TEST=$(pwd)
PARAMEDIC_COMMAND="cordova-paramedic"
fi
- PARAMEDIC_BUILDNAME=travis-$TRAVIS_REPO_SLUG-$TRAVIS_JOB_NUMBER
script:
- $TEST_COMMAND
- |
if [[ "$ADDITIONAL_TESTS_DIR" != "" ]];
then cd $ADDITIONAL_TESTS_DIR && npm install && npm test;
else
$PARAMEDIC_COMMAND --config ./pr/$PLATFORM --plugin $PARAMEDIC_PLUGIN_TO_TEST --buildName $PARAMEDIC_BUILDNAME;
fi

37
CONTRIBUTING.md Normal file
View File

@@ -0,0 +1,37 @@
<!--
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
#
-->
# Contributing to Apache Cordova
Anyone can contribute to Cordova. And we need your contributions.
There are multiple ways to contribute: report bugs, improve the docs, and
contribute code.
For instructions on this, start with the
[contribution overview](http://cordova.apache.org/contribute/).
The details are explained there, but the important items are:
- Check for Github issues that corresponds to your contribution and link or create them if necessary.
- Run the tests so your patch doesn't break existing functionality.
We look forward to your contributions!

View File

@@ -1,22 +1,25 @@
<!---
license: 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
---
title: Camera
description: Take pictures with the device camera.
---
# cordova-plugin-splashscreen
http://www.apache.org/licenses/LICENSE-2.0
在 [cordova-plugin-camera](https://github.com/apache/cordova-plugin-camera.git) 的基础上修改了ios端的代码为[customCamera](https://github.com/geneanet/customCamera.git)的ios的代码,防止ios疯狂调用造成的webview卡死的问题
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.
-->
- [Installation](#installation)
- [Preferences](#preferences)
- [Other](#other)
# org.apache.cordova.camera
## Installation
Plugin documentation: [doc/index.md](doc/index.md)
```bash
# 安装前请先卸载 `cordova-plugin-camera` 和 `org.geneanet.customCamera` 插件
cordova plugin rm cordova-plugin-camera
cordova plugin rm org.geneanet.customCamera
# 安装插件
cordova plugin add https://gitee.com/shuto/cordova-plugin-camera.git
```
## Preferences
- iOS端由于代码调整,导致原插件仅支持 `quality` `saveToPhotoAlbum` 参数,返回数据格式为 **base64**;
## Other
- 其他配置及插件使用方法请移步[cordova-plugin-camera](https://github.com/apache/cordova-plugin-camera.git)

View File

@@ -7,9 +7,9 @@
# 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
@@ -20,33 +20,398 @@
-->
# 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
### 4.2.0 (May 07, 2020)
* Cache images in device storage, devices have enough space now.
* docs(readme): app renamed to Google Photos
* chore(asf): update git notification settings
* fix(ios): return copy of video when picking from gallery on **iOS** 13 (#580)
* Update CONTRIBUTING.md
* Fix UI API called on a background thread (#550, #530, #447) (#551)
* ci: updates Node.js versions (#576)
* chore(npm): adds ignore list (#575)
* docs(README): remove confusing comment (#513)
* docs(README): remove orphan **Windows** phone 7 note (#512)
* ImagePicker returning same image (#306)
### 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
### 4.1.0 (Jun 27, 2019)
### 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.
- docs: remove outdated test docs translations ([`06dc38f`](https://github.com/apache/cordova-plugin-camera/commit/06dc38f))
- build: remove `.ratignore` file that is not needed any more ([`5dc9527`](https://github.com/apache/cordova-plugin-camera/commit/5dc9527))
- chore: fix repo and issue urls and license in package.json and plugin.xml ([`cad8bd1`](https://github.com/apache/cordova-plugin-camera/commit/cad8bd1))
- fix: temporarily remove Appium tests to unbreak CI ([#468](https://github.com/apache/cordova-plugin-camera/issues/468)) ([`19d8e2f`](https://github.com/apache/cordova-plugin-camera/commit/19d8e2f))
- ci(travis): Update Travis CI configuration for new paramedic ([#455](https://github.com/apache/cordova-plugin-camera/issues/455)) ([`cffd0ac`](https://github.com/apache/cordova-plugin-camera/commit/cffd0ac))
- fix(android): Fix NullPointerException error on some Android phones ([#429](https://github.com/apache/cordova-plugin-camera/issues/429)) ([`295e928`](https://github.com/apache/cordova-plugin-camera/commit/295e928))
- ci: Update CI Environment Setup for Node.js 6 ([#438](https://github.com/apache/cordova-plugin-camera/issues/438)) ([`fae190e`](https://github.com/apache/cordova-plugin-camera/commit/fae190e))
- refactor(android): Enhancement: Camera plugin code cleanup ([#425](https://github.com/apache/cordova-plugin-camera/issues/425)) ([`a13665d`](https://github.com/apache/cordova-plugin-camera/commit/a13665d))
- fix(android): Exif data lost on many cases ([#331](https://github.com/apache/cordova-plugin-camera/issues/331)) ([`81b878d`](https://github.com/apache/cordova-plugin-camera/commit/81b878d))
- chore(github): Add or update GitHub pull request and issue template ([`b261d31`](https://github.com/apache/cordova-plugin-camera/commit/b261d31))
- fix(ios): fixes UIImagePickerController cancel handling for iOS11+ ([#377](https://github.com/apache/cordova-plugin-camera/issues/377)) ([`24c8b6c`](https://github.com/apache/cordova-plugin-camera/commit/24c8b6c))
- docs: Remove deprecated platforms from docs ([#394](https://github.com/apache/cordova-plugin-camera/issues/394)) ([`7ddb3df`](https://github.com/apache/cordova-plugin-camera/commit/7ddb3df))
- fix(android): return DATA_URL for ALLMEDIA if it's an image ([#382](https://github.com/apache/cordova-plugin-camera/issues/382)) ([`60e7795`](https://github.com/apache/cordova-plugin-camera/commit/60e7795))
- refactor(ios): [CB-13813](https://issues.apache.org/jira/browse/13813): Remove old iOS code ([#381](https://github.com/apache/cordova-plugin-camera/issues/381)) ([`ce77aab`](https://github.com/apache/cordova-plugin-camera/commit/ce77aab))
- feat(ios): [CB-13865](https://issues.apache.org/jira/browse/13865): (Ipad) Making popover Window Size configurable using popoverOptions - imagePicker ([#314](https://github.com/apache/cordova-plugin-camera/issues/314)) ([`cd72047`](https://github.com/apache/cordova-plugin-camera/commit/cd72047))
- chore(types): [CB-13837](https://issues.apache.org/jira/browse/13837): fix TypeScript Definition for CameraPopoverOptions ([#379](https://github.com/apache/cordova-plugin-camera/issues/379)) ([`86b0bf2`](https://github.com/apache/cordova-plugin-camera/commit/86b0bf2))
- docs(android): clarify android quirk of cameraDirection ([`a5a3d88`](https://github.com/apache/cordova-plugin-camera/commit/a5a3d88), [`bfbe4a1`](https://github.com/apache/cordova-plugin-camera/commit/bfbe4a1))
- chore(release): Bump minor version ([#370](https://github.com/apache/cordova-plugin-camera/issues/370)) ([`eed4433`](https://github.com/apache/cordova-plugin-camera/commit/eed4433))
- build: Remove automatic README generation ([#365](https://github.com/apache/cordova-plugin-camera/issues/365)) ([`07e8574`](https://github.com/apache/cordova-plugin-camera/commit/07e8574))
- docs: remove JIRA link ([`bcb26fb`](https://github.com/apache/cordova-plugin-camera/commit/bcb26fb))
- ci(travis): also accept terms for android sdk `android-27` ([`a346212`](https://github.com/apache/cordova-plugin-camera/commit/a346212))
- docs: remove outdated docs translations that haven't been touched for 3 years ([`403682b`](https://github.com/apache/cordova-plugin-camera/commit/403682b))
- fix(android): [CB-14097](https://issues.apache.org/jira/browse/14097): Fix crash when selecting some files with getPicture ([#322](https://github.com/apache/cordova-plugin-camera/issues/322)) ([`5c23b65`](https://github.com/apache/cordova-plugin-camera/commit/5c23b65))
- fix(browser): [CB-13384](https://issues.apache.org/jira/browse/13384): Added deprecation of video.src compatibility ([#288](https://github.com/apache/cordova-plugin-camera/issues/288)) ([`5163d38`](https://github.com/apache/cordova-plugin-camera/commit/5163d38))
- fix(browser): Remove audio flag from getUserMedia ([#284](https://github.com/apache/cordova-plugin-camera/issues/284)) ([`36343a8`](https://github.com/apache/cordova-plugin-camera/commit/36343a8))
- docs: replace warning emoji with warning unicode ([#317](https://github.com/apache/cordova-plugin-camera/issues/317)) ([`ead7d5e`](https://github.com/apache/cordova-plugin-camera/commit/ead7d5e))
- feat(android): Update engines to use variables ([#323](https://github.com/apache/cordova-plugin-camera/issues/323)) ([`6899c5e`](https://github.com/apache/cordova-plugin-camera/commit/6899c5e))
- feat(android): [CB-14017](https://issues.apache.org/jira/browse/14017): Make com.android.support:support-v4 version configurable ([#318](https://github.com/apache/cordova-plugin-camera/issues/318)) ([`e334656`](https://github.com/apache/cordova-plugin-camera/commit/e334656))
- refactor(android): [CB-14047](https://issues.apache.org/jira/browse/14047): CameraLauncher: Replacing Repeated String literals with final variables ([#319](https://github.com/apache/cordova-plugin-camera/issues/319)) ([`5ec121b`](https://github.com/apache/cordova-plugin-camera/commit/5ec121b))
- fix(windows): [CB-11714](https://issues.apache.org/jira/browse/11714): added extra check for content-type in savePhoto() without options.targetWidth/Height ([#242](https://github.com/apache/cordova-plugin-camera/issues/242)) ([`a201722`](https://github.com/apache/cordova-plugin-camera/commit/a201722), [`dc73954`](https://github.com/apache/cordova-plugin-camera/commit/dc73954), [`dca4b9c`](https://github.com/apache/cordova-plugin-camera/commit/dca4b9c), [`c1b9772`](https://github.com/apache/cordova-plugin-camera/commit/c1b9772), [`eb57b02`](https://github.com/apache/cordova-plugin-camera/commit/eb57b02))
### 4.0.3 (Apr 12, 2018)
* [CB-12593](https://issues.apache.org/jira/browse/CB-12593) **Android** Fix potential `FileProvider` conflicts
* Fix a mistake in the examples of usage descriptions (#313)
* CB-13854(ios): fix Camera opens in portrait orientation on iphones
* [CB-13415](https://issues.apache.org/jira/browse/CB-13415) **Android** Importing corrupt images using the Camera plugin crashes the app
### 4.0.2 (Jan 24, 2018)
* [CB-13781](https://issues.apache.org/jira/browse/CB-13781) (android) Fixed permissions request on **Android** 8 to save a photo into the photo album
* [CB-13747](https://issues.apache.org/jira/browse/CB-13747) Add build-tools-26.0.2 to travis
### 4.0.1 (Dec 27, 2017)
* CB-13701Fix to allow 4.0.0 version install
### 4.0.0 (Dec 15, 2017)
* [CB-13661](https://issues.apache.org/jira/browse/CB-13661) Remove deprecated platforms
### 3.0.0 (Nov 06, 2017)
* Added `cordova-OSX` support
* [CB-13515](https://issues.apache.org/jira/browse/CB-13515) (all): Add 'protective' entry to `cordovaDependencies`
* [CB-13332](https://issues.apache.org/jira/browse/CB-13332) (iOS): document `NSPhotoLibraryAddUsageDescription`
* [CB-13264](https://issues.apache.org/jira/browse/CB-13264) (iOS): Remove **iOS** usage descriptions
* [CB-13473](https://issues.apache.org/jira/browse/CB-13473) (CI) Removed **Browser** builds from AppVeyor
* [CB-13446](https://issues.apache.org/jira/browse/CB-13446) Sync template with previous doc changes
* [CB-13294](https://issues.apache.org/jira/browse/CB-13294) Removed `cordova-plugin-compat`
* [CB-13299](https://issues.apache.org/jira/browse/CB-13299) (CI) Fix **Android** builds
* [CB-12985](https://issues.apache.org/jira/browse/CB-12985) setup `eslint` and removed `jshint`
* [CB-13028](https://issues.apache.org/jira/browse/CB-13028) (CI) **Browser** builds on Travis and AppVeyor
* [CB-13002](https://issues.apache.org/jira/browse/CB-13002) (Android, **iOS**) Fix occasional Appium tests failures
* [CB-13000](https://issues.apache.org/jira/browse/CB-13000) (CI) Speed up **Android** builds
* [CB-12991](https://issues.apache.org/jira/browse/CB-12991) (CI) Updated CI badges
* [CB-12964](https://issues.apache.org/jira/browse/CB-12964) (android) Fix of bug when Pictures folder did not exist.
* [CB-12982](https://issues.apache.org/jira/browse/CB-12982) (Android, **iOS**) Appium tests: try to create a session harder
* [CB-12682](https://issues.apache.org/jira/browse/CB-12682) (ios, **Android**): changes cancel error message to be consistent for **iOS** **Android**
* [CB-12764](https://issues.apache.org/jira/browse/CB-12764) (android) Adapt Appium tests for **Android** 7
* [CB-12847](https://issues.apache.org/jira/browse/CB-12847) added `bugs` entry to `package.json`.
### 2.4.1 (Apr 27, 2017)
* [CB-12622](https://issues.apache.org/jira/browse/CB-12622) Updated build badges in `README`
* [CB-12650](https://issues.apache.org/jira/browse/CB-12650) Fix manual test for uploading image
* [CB-12685](https://issues.apache.org/jira/browse/CB-12685) added `package.json` to tests folder
* [CB-12622](https://issues.apache.org/jira/browse/CB-12622) (android) Appium tests: Bust **Android** 6 and 7 permission dialogs
* [CB-12618](https://issues.apache.org/jira/browse/CB-12618) (android) Appium tests: Handle native cling
### 2.4.0 (Feb 28, 2017)
* [CB-12501](https://issues.apache.org/jira/browse/CB-12501) **Android**: Appium tests don't use `XPath` selectors anymore
* [CB-12469](https://issues.apache.org/jira/browse/CB-12469) Appium tests can now run on **iOS 10**
* [CB-12005](https://issues.apache.org/jira/browse/CB-12005) Changing the `getOrientation` method to return the defined enumerated `EXIF` instead of orientation in degrees for Consistency
* [CB-12368](https://issues.apache.org/jira/browse/CB-12368) Fix permission check on **Android**
* [CB-12353](https://issues.apache.org/jira/browse/CB-12353) Corrected merges usage in `plugin.xml`
* [CB-12369](https://issues.apache.org/jira/browse/CB-12369) Add plugin typings from `DefinitelyTyped`
* [CB-12363](https://issues.apache.org/jira/browse/CB-12363) Added build badges for **iOS 9.3** and **iOS 10.0**
* [CB-12312](https://issues.apache.org/jira/browse/CB-12312) [Appium] [Android] A few changes to the tests: - updated comments on how to run the tests. extra comments around functionality at certain points in the automation. - stub of a resolution checker on test startup - still need to figure out acceptable values. - moved session shutdown to an afterAll clause. - changed resolution determiner from using webview-based values to using the native windows dimensions - this helps as the webview values may be scaled down intentionally by manufacturers (via changing devicePixelRatio). furthermore, since the screen dimension automation is used purely for native UI automation, better to use the dimensions reported by the native context rather than the web context. - when finding elements by XPath, use multiple calls to avoid a Windows emulator + Android bug. Made this pattern consistent in the entire test.
* [CB-12236](https://issues.apache.org/jira/browse/CB-12236) - Fixed RELEASENOTES for cordova-plugin-camera
* [CB-12230](https://issues.apache.org/jira/browse/CB-12230) Removed Windows 8.1 build badges
### 2.3.1 (Dec 07, 2016)
* [CB-12224](https://issues.apache.org/jira/browse/CB-12224) Updated version and RELEASENOTES.md for release 2.3.1
* Fix missing license headers.
* [CB-12086](https://issues.apache.org/jira/browse/CB-12086) Regenerate README.md from template
* Added NSPhotoLibraryUsageDescription parameter to example install command Fixing some usages of NSPhotoLibraryUsageDescriptionentry
* Updating compat dependency to 1.1.0 or better
* [CB-11625](https://issues.apache.org/jira/browse/CB-11625) Forgot to add CordovaUri.java to plugin.xml
* [CB-11625](https://issues.apache.org/jira/browse/CB-11625) Files Provider does not work with Android 4.4.4 or lower, and I have no idea why. Working around with CordovaUri
* [CB-11625](https://issues.apache.org/jira/browse/CB-11625) (Android) : Make this work with previous versions of Cordova via cordova-plugin-compat
* BuildConfig from test project crept in source code thanks to Android Studio, removing
* [CB-11625](https://issues.apache.org/jira/browse/CB-11625) Managed to get Content Providers to work with a weird mix of Content Providers and non-Content Providers
* [CB-11625](https://issues.apache.org/jira/browse/CB-11625) Working on fix to API 24 no longer allowing File URIs to be passed across intents
* [CB-11917](https://issues.apache.org/jira/browse/CB-11917) - Remove pull request template checklist item: "iCLA has been submitted…"
* [CB-11832](https://issues.apache.org/jira/browse/CB-11832) Incremented plugin version.
### 2.3.0 (Sep 08, 2016)
* [CB-11795](https://issues.apache.org/jira/browse/CB-11795) Add 'protective' entry to cordovaDependencies
* [CB-11661](https://issues.apache.org/jira/browse/CB-11661) Add mandatory **iOS 10** privacy description
* [CB-11714](https://issues.apache.org/jira/browse/CB-11714) **windows** added more explicit content-type when converting to target data on canvas
* [CB-11295](https://issues.apache.org/jira/browse/CB-11295) Add **WP8.1** quirk when choosing image from `photoalbum`
* [CB-10067](https://issues.apache.org/jira/browse/CB-10067) Update `PictureSourceType` JSDoc to reflect `README` update
* [CB-9070](https://issues.apache.org/jira/browse/CB-9070) Update `CameraPopoverHandle` docs to reflect `README` update
* Plugin uses `Android Log class` and not `Cordova LOG class`
* [CB-11631](https://issues.apache.org/jira/browse/CB-11631) Appium tests: A working fix for a flaky `selection canceled` failure
* [CB-11709](https://issues.apache.org/jira/browse/CB-11709) Tests should use `resolveLocalFileSystemURL()` instead of deprecated `resolveFileSystemURI()`
* [CB-11695](https://issues.apache.org/jira/browse/CB-11695) Increased session creation timeout for Appium tests
* [CB-11656](https://issues.apache.org/jira/browse/CB-11656) (**Android**) Appium tests: Fixed side menu opening on some more resolutions
* [CB-11376](https://issues.apache.org/jira/browse/CB-11376) (**ios**): fix `CameraUsesGeolocation` error
* [CB-10067](https://issues.apache.org/jira/browse/CB-10067) (**ios**) clarifications on `PictureSourceType`
* [CB-11410](https://issues.apache.org/jira/browse/CB-11410) (**ios**) fix `cameraPopoverHandle.setPosition`
* [CB-9070](https://issues.apache.org/jira/browse/CB-9070) (**ios**) Fixed `CameraPopoverHandle` documentation
* [CB-11447](https://issues.apache.org/jira/browse/CB-11447) Respect output format when retrieving images from gallery
* [CB-11447](https://issues.apache.org/jira/browse/CB-11447) Resolve **iOS** tests failures due to **iOS** quirks
* [CB-11553](https://issues.apache.org/jira/browse/CB-11553) Pend failing Appium tests on Sauce Labs for the time being (reverted from commit b69571724035f41642f3ee612c5b66e1f0c4386c)
* [CB-11553](https://issues.apache.org/jira/browse/CB-11553) Pend failing Appium tests on Sauce Labs for the time being
* [CB-11498](https://issues.apache.org/jira/browse/CB-11498) [**Android**] Appium tests should not fail when there is no camera
* Add badges for paramedic builds on Jenkins
* [CB-11296](https://issues.apache.org/jira/browse/CB-11296) Appium: Better element clicking and session error handling
* [CB-11232](https://issues.apache.org/jira/browse/CB-11232) Appium tests: fixed element tapping on **iOS 9**
* [CB-11183](https://issues.apache.org/jira/browse/CB-11183) Appium tests: Added image verification
* fixed some bad formatting that hid `HTML` tags and added link to sample
* Set **android** quality default value to 50 on the java code
* Moving message in PR template to a comment
* Add pull request template. This closes #213
* [CB-11228](https://issues.apache.org/jira/browse/CB-11228) **browser**: Add classes for styling purposes
* [CB-10139](https://issues.apache.org/jira/browse/CB-10139) **browser**: Respect target width and height
* [CB-11227](https://issues.apache.org/jira/browse/CB-11227) **browser**: Fix incorrect `mime type`
* [CB-11162](https://issues.apache.org/jira/browse/CB-11162) Appium tests: retry spec on failure
* [CB-4078](https://issues.apache.org/jira/browse/CB-4078) Fix for `orientation/scaling` on **Android 4.4+** devices
* [CB-11165](https://issues.apache.org/jira/browse/CB-11165) removed peer dependency
* [CB-11147](https://issues.apache.org/jira/browse/CB-11147) Appium tests: generate descriptive spec names
* [CB-10996](https://issues.apache.org/jira/browse/CB-10996) Adding front matter to `README.md`
* [CB-11128](https://issues.apache.org/jira/browse/CB-11128) Appum tests: Fixed some of the flaky failures
* [CB-11003](https://issues.apache.org/jira/browse/CB-11003) Added Sample section to the Camera plugin README
### 2.2.0 (Apr 15, 2016)
* [CB-10873](https://issues.apache.org/jira/browse/CB-10873) Avoid crash due to usage of uninitialized variable when writing geolocation data to image destination. Properly handle 'CameraUsesGeolocation' option by properly setting geolocation data in EXIF header in all cases
* [CB-11073](https://issues.apache.org/jira/browse/CB-11073) Appium tests stability improvements
* Replace `PermissionHelper.java` with `cordova-plugin-compat`
* Making focus handler work only for **windows 10** phone
* [CB-10865](https://issues.apache.org/jira/browse/CB-10865) Run **ios** native tests on **Travis**
* [CB-10120](https://issues.apache.org/jira/browse/CB-10120) Fixing use of constants and `PermissionHelper`
* [CB-10120](https://issues.apache.org/jira/browse/CB-10120) Fix missing CAMERA permission for **Android M**
* [CB-10756](https://issues.apache.org/jira/browse/CB-10756) Adding sterner warnings about `DATA_URL`
* [CB-10460](https://issues.apache.org/jira/browse/CB-10460) `getRealPath` return null in some cases
### 2.1.1 (Mar 09, 2016)
* [CB-10825](https://issues.apache.org/jira/browse/CB-10825) **Android** should request READ permission for gallery source
* added apache license header to appium files
* [CB-10720](https://issues.apache.org/jira/browse/CB-10720) Fixed spelling, capitalization, and other small issues.
* [CB-10414](https://issues.apache.org/jira/browse/CB-10414) Adding focus handler to resume video when user comes back on leaving the app while preview was running
* Appium tests: adjust swipe distance on **Android**
* [CB-10750](https://issues.apache.org/jira/browse/CB-10750) Appium tests: fail fast if session is irrecoverable
* Adding missing semi colon
* Adding focus handler to make sure filepicker gets launched when app is active on **Windows**
* [CB-10128](https://issues.apache.org/jira/browse/CB-10128) **iOS** Fixed how checks access authorization to camera & library. This closes #146
* [CB-10636](https://issues.apache.org/jira/browse/CB-10636) Add JSHint for plugins
* [CB-10639](https://issues.apache.org/jira/browse/CB-10639) Appium tests: Added some timeouts, Taking a screenshot on failure, Retry taking a picture up to 3 times, Try to restart the Appium session if it's lost
* [CB-10552](https://issues.apache.org/jira/browse/CB-10552) Replacing images in README.md.
* Added a lot of more cases to get the real path on **Android**
* [CB-10625](https://issues.apache.org/jira/browse/CB-10625) **Android** getPicture fails when getting a photo from the Photo Library - Google Photos
* [CB-10619](https://issues.apache.org/jira/browse/CB-10619) Appium tests: Properly switch to webview on **Android**
* [CB-10397](https://issues.apache.org/jira/browse/CB-10397) Added Appium tests
* [CB-10576](https://issues.apache.org/jira/browse/CB-10576) MobileSpec can't get results for **Windows**-Store 8.1 Builds
* chore: edit package.json license to match SPDX id
* [CB-10539](https://issues.apache.org/jira/browse/CB-10539) Commenting out the verySmallQvga maxResolution option on **Windows**
* [CB-10541](https://issues.apache.org/jira/browse/CB-10541) Changing default maxResoltion to be highestAvailable for CameraCaptureUI on **Windows**
* [CB-10113](https://issues.apache.org/jira/browse/CB-10113) **Browse** - Layer camera UI on top of all!
* [CB-10502](https://issues.apache.org/jira/browse/CB-10502) **Browser** - Fix camera plugin exception in Chrome when click capture.
* Adding comments
* Camera tapping fix on **Windows**
### 2.1.0 (Jan 15, 2016)
* added `.ratignore`
* [CB-10319](https://issues.apache.org/jira/browse/CB-10319) **Android** Adding reflective helper methods for permission requests
* [CB-9189](https://issues.apache.org/jira/browse/CB-9189) **Android** Implementing `save/restore` API to handle Activity destruction
* [CB-10241](https://issues.apache.org/jira/browse/CB-10241) App Crash cause by Camera Plugin **iOS 7**
* [CB-8940](https://issues.apache.org/jira/browse/CB-8940) Setting `z-index` values to maximum for UI buttons.
### 2.0.0 (Nov 18, 2015)
* [CB-10035](https://issues.apache.org/jira/browse/CB-10035) Updated `RELEASENOTES` to be newest to oldest
* [CB-8863](https://issues.apache.org/jira/browse/CB-8863) correct block usage for `async` calls
* [CB-5479](https://issues.apache.org/jira/browse/CB-5479) changed `saveToPhotoAlbum` to save uncompressed images for **Android**
* [CB-9169](https://issues.apache.org/jira/browse/CB-9169) Fixed `filetype` for uncompressed images and added quirk for **Android**
* [CB-9446](https://issues.apache.org/jira/browse/CB-9446) Removing `CordovaResource` library code in favour of the code we're supposed to be deprecating because that at least works.
* [CB-9942](https://issues.apache.org/jira/browse/CB-9942) Normalize line endings in Camera plugin docs
* [CB-9910](https://issues.apache.org/jira/browse/CB-9910) Add permission request for some gallery requests for **Android**
* [CB-7668](https://issues.apache.org/jira/browse/CB-7668) Adding a sterner warning for `allowedit` on **Android**
* Fixing contribute link.
* Using the `CordovaResourceApi` to fine paths of files in the background thread. If the file doesn't exist, return the content `URI`.
* Add engine tag for **Cordova-Android 5.0.x**
* [CB-9583](https://issues.apache.org/jira/browse/CB-9583): Added support for **Marshmallow** permissions (**Android 6.0**)
* Try to use `realpath` filename instead of default `modified.jpg`
* [CB-6190](https://issues.apache.org/jira/browse/CB-6190) **iOS** camera plugin ignores quality parameter
* [CB-9633](https://issues.apache.org/jira/browse/CB-9633) **iOS** Taking a Picture With Option `destinationType:NATIVE_URI` doesn't show image
* [CB-9745](https://issues.apache.org/jira/browse/CB-9745) Camera plugin docs should be generated from the source
* [CB-9622](https://issues.apache.org/jira/browse/CB-9622) **WP8** Camera Option `destinationType:NATIVE_URI` is a `NO-OP`
* [CB-9623](https://issues.apache.org/jira/browse/CB-9623) Fixes various issues when `encodingType` set to `png`
* [CB-9591](https://issues.apache.org/jira/browse/CB-9591) Retaining aspect ratio when resizing
* [CB-9443](https://issues.apache.org/jira/browse/CB-9443) Pick correct `maxResolution`
* [CB-9151](https://issues.apache.org/jira/browse/CB-9151) Trigger `captureAction` only once
* [CB-9413](https://issues.apache.org/jira/browse/CB-9413) Close `RandomAccessStream` once copied
* [CB-5661](https://issues.apache.org/jira/browse/CB-5661) Remove outdated **iOS** quirks about memory
* [CB-9349](https://issues.apache.org/jira/browse/CB-9349) Focus control and nice UI
* [CB-9259](https://issues.apache.org/jira/browse/CB-9259) Forgot to add another check on which `URI` we're using when fixing this thing the first time
* [CB-9247](https://issues.apache.org/jira/browse/CB-9247) Added macro to conditionally add `NSData+Base64.h`
* [CB-9247](https://issues.apache.org/jira/browse/CB-9247) Fixes compilation errors with **cordova-ios 4.x**
* Fix returning native url on **Windows**.
### 1.2.0 (Jun 17, 2015)
* Closing stale pull request: close #84
* Closing stale pull request: close #66
* [CB-9128](https://issues.apache.org/jira/browse/CB-9128) cordova-plugin-camera documentation translation: cordova-plugin-camera
* Update docs. This closes #100
* attempt to fix npm markdown issue
* [CB-8883](https://issues.apache.org/jira/browse/CB-8883) fix picture rotation issue
* one more alias
* Fixed some nit white-space issues, aliased a little more
* major refactor : readability
* Patch for [CB-8498](https://issues.apache.org/jira/browse/CB-8498), this closes #64
* [CB-8879](https://issues.apache.org/jira/browse/CB-8879) fix stripe issue with correct aspect ratio
* [CB-8601](https://issues.apache.org/jira/browse/CB-8601) - iOS camera unit tests broken
* [CB-7667](https://issues.apache.org/jira/browse/CB-7667) iOS8: Handle case where camera is not authorized (closes #49)
* add missing license header
### 1.1.0 (May 06, 2015)
* [CB-8943](https://issues.apache.org/jira/browse/CB-8943) fix `PickAndContinue` issue on *Win10Phone*
* [CB-8253](https://issues.apache.org/jira/browse/CB-8253) Fix potential unreleased resources
* [CB-8909](https://issues.apache.org/jira/browse/CB-8909): Remove unused import from File
* [CB-8404](https://issues.apache.org/jira/browse/CB-8404) typo fix `cameraproxy.js`
* [CB-8404](https://issues.apache.org/jira/browse/CB-8404) Rotate camera feed with device orientation
* [CB-8054](https://issues.apache.org/jira/browse/CB-8054) Support taking pictures from file for *WP8*
* [CB-8405](https://issues.apache.org/jira/browse/CB-8405) Use `z-index` instead of `z-order`
### 1.0.0 (Apr 15, 2015)
* [CB-8780](https://issues.apache.org/jira/browse/CB-8780) - Display popover using main thread. Fixes popover slowness (closes #81)
* [CB-8746](https://issues.apache.org/jira/browse/CB-8746) bumped version of file dependency
* [CB-8746](https://issues.apache.org/jira/browse/CB-8746) gave plugin major version bump
* [CB-8707](https://issues.apache.org/jira/browse/CB-8707) refactoring windows code to improve readability
* [CB-8706](https://issues.apache.org/jira/browse/CB-8706) use filePicker if saveToPhotoAlbum is true
* [CB-8706](https://issues.apache.org/jira/browse/CB-8706) remove unnecessary capabilities from xml
* [CB-8747](https://issues.apache.org/jira/browse/CB-8747) updated dependency, added peer dependency
* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) updated blackberry specific references of org.apache.cordova.camera to cordova-plugin-camera
* [CB-8782](https://issues.apache.org/jira/browse/CB-8782): Updated the docs to talk about the allowEdit quirks, it's not 100% working, but better than it was
* [CB-8782](https://issues.apache.org/jira/browse/CB-8782): Fixed the flow so that we save the cropped image and use it, not the original non-cropped. Crop only supports G+ Photos Crop, other crops may not work, depending on the OEM
* [CB-8740](https://issues.apache.org/jira/browse/CB-8740): Removing FileHelper call that was failing on Samsung Galaxy S3, now that we have a real path, we only need to update the MediaStore, not pull from it in this case
* [CB-8740](https://issues.apache.org/jira/browse/CB-8740): Partial fix for Save Image to Gallery error found in MobileSpec
* [CB-8683](https://issues.apache.org/jira/browse/CB-8683) changed plugin-id to pacakge-name
* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) properly updated translated docs to use new id
* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) updated translated docs to use new id
* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) Fix custom implementation of integerValueForKey (close #79)
* Fix cordova-paramedic path change, build with TRAVIS_BUILD_DIR, use npm to install paramedic
* docs: added 'Windows' to supported platforms
* [CB-8653](https://issues.apache.org/jira/browse/CB-8653) Updated Readme
* [CB-8659](https://issues.apache.org/jira/browse/CB-8659): ios: 4.0.x Compatibility: Remove use of deprecated headers
### 0.3.6 (Mar 10, 2015)
* Fix localize key for Videos. This closes #58
* [CB-8235](https://issues.apache.org/jira/browse/CB-8235) android: Fix crash when selecting images from DropBox with spaces in path (close #65)
* add try ... catch for getting image orientation
* [CB-8599](https://issues.apache.org/jira/browse/CB-8599) fix threading issue with cameraPicker (fixes #72)
* [CB-8559](https://issues.apache.org/jira/browse/CB-8559) Integrate TravisCI
* [CB-8438](https://issues.apache.org/jira/browse/CB-8438) cordova-plugin-camera documentation translation: cordova-plugin-camera
* [CB-8538](https://issues.apache.org/jira/browse/CB-8538) Added package.json file
### 0.3.5 (Feb 04, 2015)
* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) ios: Stop using now-deprecated [NSData base64EncodedString]
* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) ios: Stop using now-deprecated integerValueForKey: class extension
* [CB-8351](https://issues.apache.org/jira/browse/CB-8351) ios: Use argumentForIndex rather than NSArray extension
* [CB-8032](https://issues.apache.org/jira/browse/CB-8032) ios: Add nativeURL external method support for CDVFileSystem->makeEntryForPath:isDirectory:
* [CB-7938](https://issues.apache.org/jira/browse/CB-7938) ios: Added XCTest unit tests project, with stubs (adapted from SplashScreen unit test setup)
* [CB-7937](https://issues.apache.org/jira/browse/CB-7937) ios: Re-factor iOS Camera plugin so that it is testable
### 0.3.4 (Dec 02, 2014)
* [CB-7977](https://issues.apache.org/jira/browse/CB-7977) Mention `deviceready` in plugin docs
* [CB-7979](https://issues.apache.org/jira/browse/CB-7979) Each plugin doc should have a ## Installation section
* Fix memory leak of image data in `imagePickerControllerReturnImageResult`
* Pass uri to crop instead of pulling the low resolution image out of the intent return (close #43)
* Add orientation support for PNG to Android (closes #45)
* [CB-7700](https://issues.apache.org/jira/browse/CB-7700) cordova-plugin-camera documentation translation: cordova-plugin-camera
### 0.3.3 (Oct 03, 2014)
* [CB-7600](https://issues.apache.org/jira/browse/CB-7600) Adds informative message to error callback in manual test.
### 0.3.2 (Sep 17, 2014)
* [CB-7551](https://issues.apache.org/jira/browse/CB-7551) [Camera][iOS 8] Scaled images show a white line
* [CB-7558](https://issues.apache.org/jira/browse/CB-7558) hasPendingOperation flag in Camera plugin's takePicture should be reversed to fix memory errors
* [CB-7557](https://issues.apache.org/jira/browse/CB-7557) Camera plugin tests is missing a File dependency
* [CB-7423](https://issues.apache.org/jira/browse/CB-7423) do cleanup after copyImage manual test
* [CB-7471](https://issues.apache.org/jira/browse/CB-7471) cordova-plugin-camera documentation translation: cordova-plugin-camera
* [CB-7413](https://issues.apache.org/jira/browse/CB-7413) Resolve 'ms-appdata' URIs with File plugin
* Fixed minor bugs with the browser
* [CB-7433](https://issues.apache.org/jira/browse/CB-7433) Adds missing window reference to prevent manual tests failure on Android and iOS
* [CB-7249](https://issues.apache.org/jira/browse/CB-7249) cordova-plugin-camera documentation translation: cordova-plugin-camera
* [CB-4003](https://issues.apache.org/jira/browse/CB-4003) Add config option to not use location information in Camera plugin (and default to not use it)
* [CB-7461](https://issues.apache.org/jira/browse/CB-7461) Geolocation fails in Camera plugin in iOS 8
* [CB-7378](https://issues.apache.org/jira/browse/CB-7378) Use single Proxy for both windows8 and windows.
* [CB-7378](https://issues.apache.org/jira/browse/CB-7378) Adds support for windows platform
* [CB-7433](https://issues.apache.org/jira/browse/CB-7433) Fixes manual tests failure on windows
* [CB-6958](https://issues.apache.org/jira/browse/CB-6958) Get the correct default for "quality" in the test
* add documentation for manual tests
* [CB-7249](https://issues.apache.org/jira/browse/CB-7249) cordova-plugin-camera documentation translation: cordova-plugin-camera
* [CB-4003](https://issues.apache.org/jira/browse/CB-4003) Add config option to not use location information in Camera plugin (and default to not use it)
* [CB-7461](https://issues.apache.org/jira/browse/CB-7461) Geolocation fails in Camera plugin in iOS 8
* [CB-7433](https://issues.apache.org/jira/browse/CB-7433) Fixes manual tests failure on windows
* [CB-7378](https://issues.apache.org/jira/browse/CB-7378) Use single Proxy for both windows8 and windows.
* [CB-7378](https://issues.apache.org/jira/browse/CB-7378) Adds support for windows platform
* [CB-6958](https://issues.apache.org/jira/browse/CB-6958) Get the correct default for "quality" in the test
* add documentation for manual tests
* Updated docs for browser
* Added support for the browser
* [CB-7286](https://issues.apache.org/jira/browse/CB-7286) [BlackBerry10] Use getUserMedia if camera card is unavailable
* [CB-7180](https://issues.apache.org/jira/browse/CB-7180) Update Camera plugin to support generic plugin webView UIView (which can be either a UIWebView or WKWebView)
* Renamed test dir, added nested plugin.xml
* [CB-6958](https://issues.apache.org/jira/browse/CB-6958) added manual tests
* [CB-6958](https://issues.apache.org/jira/browse/CB-6958) Port camera tests to plugin-test-framework
### 0.3.1 (Aug 06, 2014)
* **FFOS** update CameraProxy.js
* [CB-7187](https://issues.apache.org/jira/browse/CB-7187) ios: Add explicit dependency on CoreLocation.framework
* [BlackBerry10] Doc correction - sourceType is supported
* [CB-7071](https://issues.apache.org/jira/browse/CB-7071) android: Fix callback firing before CROP intent is sent when allowEdit=true
* [CB-6875](https://issues.apache.org/jira/browse/CB-6875) android: Handle exception when SDCard is not mounted
* ios: Delete postImage (dead code)
* Prevent NPE on processResiultFromGallery when intent comes null
* Remove iOS doc reference to non-existing navigator.fileMgr API
* Docs updated with some default values
* Removes File plugin dependency from windows8 code.
* Use WinJS functionality to resize image instead of File plugin functionality
* [CB-6127](https://issues.apache.org/jira/browse/CB-6127) Updated translations for docs
### 0.3.0 (Jun 05, 2014)
* [CB-5895](https://issues.apache.org/jira/browse/CB-5895) documented saveToPhotoAlbum quirk on WP8
* Remove deprecated symbols for iOS < 6
* documentation translation: cordova-plugin-camera
* ubuntu: use application directory for images
* [CB-6795](https://issues.apache.org/jira/browse/CB-6795) Add license
* Little fix in code formatting
* [CB-6613](https://issues.apache.org/jira/browse/CB-6613) Use WinJS functionality to get base64-encoded content of image instead of File plugin functionality
* [CB-6612](https://issues.apache.org/jira/browse/CB-6612) camera.getPicture now always returns encoded JPEG image
* Removed invalid note from [CB-5398](https://issues.apache.org/jira/browse/CB-5398)
* [CB-6576](https://issues.apache.org/jira/browse/CB-6576) - Returns a specific error message when app has no access to library.
* [CB-6491](https://issues.apache.org/jira/browse/CB-6491) add CONTRIBUTING.md
* [CB-6546](https://issues.apache.org/jira/browse/CB-6546) android: Fix a couple bugs with allowEdit pull request
* [CB-6546](https://issues.apache.org/jira/browse/CB-6546) android: Add support for allowEdit Camera option
### 0.2.9 (Apr 17, 2014)
* [CB-6460](https://issues.apache.org/jira/browse/CB-6460): Update license headers
* [CB-6422](https://issues.apache.org/jira/browse/CB-6422): [windows8] use cordova/exec/proxy
* [WP8] When only targetWidth or targetHeight is provided, use it as the only bound
* [CB-4027](https://issues.apache.org/jira/browse/CB-4027), [CB-5102](https://issues.apache.org/jira/browse/CB-5102), [CB-2737](https://issues.apache.org/jira/browse/CB-2737), [CB-2387](https://issues.apache.org/jira/browse/CB-2387): [WP] Fix camera issues, cropping, memory leaks
* [CB-6212](https://issues.apache.org/jira/browse/CB-6212): [iOS] fix warnings compiled under arm64 64-bit
* [BlackBerry10] Add rim xml namespaces declaration
* Add NOTICE file
### 0.2.8 (Feb 26, 2014)
* [CB-1826](https://issues.apache.org/jira/browse/CB-1826) Catch OOM on gallery image resize
### 0.2.7 (Feb 05, 2014)
* [CB-4919](https://issues.apache.org/jira/browse/CB-4919) firefox os quirks added and supported platforms list is updated
* getPicture via web activities
* Documented quirk for [CB-5335](https://issues.apache.org/jira/browse/CB-5335) + [CB-5206](https://issues.apache.org/jira/browse/CB-5206) for WP7+8
* reference the correct firefoxos implementation
* [BlackBerry10] Add permission to access_shared
### 0.2.6 (Jan 02, 2014)
* [CB-5658](https://issues.apache.org/jira/browse/CB-5658) Add doc/index.md for Camera plugin
* [CB-2442](https://issues.apache.org/jira/browse/CB-2442) [CB-2419](https://issues.apache.org/jira/browse/CB-2419) Use Windows.Storage.ApplicationData.current.localFolder, instead of writing to app package.
* [BlackBerry10] Adding platform level permissions
* [CB-5599](https://issues.apache.org/jira/browse/CB-5599) Android: Catch and ignore OutOfMemoryError in getRotatedBitmap()
### 0.2.5 (Dec 4, 2013)
* fix camera for firefox os
@@ -56,18 +421,30 @@
* 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.4 (Oct 28, 2013)
* [CB-5128](https://issues.apache.org/jira/browse/CB-5128): added repo + issue tag to plugin.xml for camera plugin
* [CB-4958](https://issues.apache.org/jira/browse/CB-4958) - iOS - Camera plugin should not show the status bar
* [CB-4919](https://issues.apache.org/jira/browse/CB-4919) updated plugin.xml for FxOS
* [CB-4915](https://issues.apache.org/jira/browse/CB-4915) Incremented plugin version on dev branch.
### 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.3 (Sept 25, 2013)
* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) bumping&resetting version
* [CB-4889](https://issues.apache.org/jira/browse/CB-4889) forgot index.html
* [CB-4889](https://issues.apache.org/jira/browse/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](https://issues.apache.org/jira/browse/CB-4823) Fix XCode 5 camera plugin warnings
* Fix compiler warnings
* [CB-4765](https://issues.apache.org/jira/browse/CB-4765) Move ExifHelper.java into Camera Plugin
* [CB-4764](https://issues.apache.org/jira/browse/CB-4764) Remove reference to DirectoryManager from CameraLauncher
* [CB-4763](https://issues.apache.org/jira/browse/CB-4763) Use a copy of FileHelper.java within camera-plugin.
* [CB-4752](https://issues.apache.org/jira/browse/CB-4752) Incremented plugin version on dev branch.
* [CB-4633](https://issues.apache.org/jira/browse/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](https://issues.apache.org/jira/browse/CB-4889) renaming org.apache.cordova.core.camera to org.apache.cordova.camera
### 0.2.8 (Feb 26, 2014)
* CB-1826 Catch OOM on gallery image resize
### 0.2.1 (Sept 5, 2013)
* [CB-4656](https://issues.apache.org/jira/browse/CB-4656) Don't add line-breaks to base64-encoded images (Fixes type=DataURI)
* [CB-4432](https://issues.apache.org/jira/browse/CB-4432) copyright notice change

View File

@@ -1,441 +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.
-->
# org.apache.cordova.camera
This plugin provides an API for taking pictures and for choosing images from
the system's image libarary.
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 `<img>` 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);
}

62
package.json Normal file
View File

@@ -0,0 +1,62 @@
{
"name": "cordova-plugin-camera",
"version": "4.2.0-dev",
"description": "Cordova Camera Plugin",
"types": "./types/index.d.ts",
"cordova": {
"id": "cordova-plugin-camera",
"platforms": [
"android",
"ios",
"browser",
"windows",
"osx"
]
},
"repository": {
"type": "git",
"url": "https://github.com/apache/cordova-plugin-camera"
},
"bugs": {
"url": "https://github.com/apache/cordova-plugin-camera/issues"
},
"keywords": [
"cordova",
"camera",
"ecosystem:cordova",
"cordova-android",
"cordova-ios",
"cordova-browser",
"cordova-windows",
"cordova-osx"
],
"scripts": {
"test": "npm run eslint",
"eslint": "node node_modules/eslint/bin/eslint www && node node_modules/eslint/bin/eslint src && node node_modules/eslint/bin/eslint tests"
},
"author": "Apache Software Foundation",
"license": "Apache-2.0",
"engines": {
"cordovaDependencies": {
"3.0.0": {
"cordova-android": ">=6.3.0"
},
"4.1.0": {
"cordova-android": ">=6.3.0",
"cordova": ">=7.1.0"
},
"5.0.0": {
"cordova": ">100"
}
}
},
"devDependencies": {
"eslint": "^4.3.0",
"eslint-config-semistandard": "^11.0.0",
"eslint-config-standard": "^10.2.1",
"eslint-plugin-import": "^2.3.0",
"eslint-plugin-node": "^5.0.0",
"eslint-plugin-promise": "^3.5.0",
"eslint-plugin-standard": "^3.0.1"
}
}

View File

@@ -1,15 +1,38 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="org.apache.cordova.camera"
version="0.2.8">
id="cordova-plugin-camera"
version="4.2.0-dev">
<name>Camera</name>
<description>Cordova Camera Plugin</description>
<license>Apache 2.0</license>
<keywords>cordova,camera</keywords>
<repo>https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git</repo>
<issue>https://issues.apache.org/jira/browse/CB/component/12320645</issue>
<repo>https://github.com/apache/cordova-plugin-camera</repo>
<issue>https://github.com/apache/cordova-plugin-camera/issues</issue>
<engines>
<engine name="cordova" version=">=7.1.0"/>
<engine name="cordova-android" version=">=6.3.0" />
</engines>
<js-module src="www/CameraConstants.js" name="Camera">
<clobbers target="Camera" />
@@ -19,25 +42,10 @@
<clobbers target="CameraPopoverOptions" />
</js-module>
<js-module src="www/Camera.js" name="camera">
<clobbers target="navigator.camera" />
</js-module>
<!-- firefoxos -->
<platform name="firefoxos">
<config-file target="config.xml" parent="/*">
<feature name="Camera">
<param name="firefoxos-package" value="Camera" />
</feature>
</config-file>
<js-module src="src/firefoxos/CameraProxy.js" name="CameraProxy">
<runs />
</js-module>
</platform>
<!-- android -->
<platform name="android">
<config-file target="res/xml/config.xml" parent="/*">
@@ -48,153 +56,170 @@
<config-file target="AndroidManifest.xml" parent="/*">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
</config-file>
<source-file src="src/android/CameraLauncher.java" target-dir="src/org/apache/cordova/camera" />
<source-file src="src/android/FileHelper.java" target-dir="src/org/apache/cordova/camera" />
<source-file src="src/android/ExifHelper.java" target-dir="src/org/apache/cordova/camera" />
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
</js-module>
</platform>
<!-- amazon-fireos -->
<platform name="amazon-fireos">
<config-file target="res/xml/config.xml" parent="/*">
<feature name="Camera">
<param name="android-package" value="org.apache.cordova.camera.CameraLauncher"/>
</feature>
</config-file>
<config-file target="AndroidManifest.xml" parent="/*">
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<config-file target="AndroidManifest.xml" parent="application">
<provider
android:name="org.apache.cordova.camera.FileProvider"
android:authorities="${applicationId}.camera.provider"
android:exported="false"
android:grantUriPermissions="true" >
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/camera_provider_paths"/>
</provider>
</config-file>
<source-file src="src/android/CameraLauncher.java" target-dir="src/org/apache/cordova/camera" />
<source-file src="src/android/CordovaUri.java" target-dir="src/org/apache/cordova/camera" />
<source-file src="src/android/FileHelper.java" target-dir="src/org/apache/cordova/camera" />
<source-file src="src/android/ExifHelper.java" target-dir="src/org/apache/cordova/camera" />
<source-file src="src/android/FileProvider.java" target-dir="src/org/apache/cordova/camera" />
<source-file src="src/android/xml/camera_provider_paths.xml" target-dir="res/xml" />
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
</js-module>
</js-module>
</platform>
<!-- ubuntu -->
<platform name="ubuntu">
<config-file target="config.xml" parent="/*">
<feature name="Camera">
<param policy_group="camera" policy_version="1" />
</feature>
</config-file>
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
</js-module>
<header-file src="src/ubuntu/camera.h" />
<source-file src="src/ubuntu/camera.cpp" />
<preference name="ANDROID_SUPPORT_V4_VERSION" default="27.+"/>
<framework src="com.android.support:support-v4:$ANDROID_SUPPORT_V4_VERSION"/>
<resource-file src="src/ubuntu/back.png" />
<resource-file src="src/ubuntu/CaptureWidget.qml" />
<resource-file src="src/ubuntu/shoot.png" />
<resource-file src="src/ubuntu/toolbar-left.png" />
<resource-file src="src/ubuntu/toolbar-middle.png" />
<resource-file src="src/ubuntu/toolbar-right.png" />
</platform>
</platform>
<!-- ios -->
<platform name="ios">
<!-- old plugin's ios -->
<!-- <platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="Camera">
<param name="ios-package" value="CDVCamera" />
</feature>
<preference name="CameraUsesGeolocation" value="false" />
</config-file>
<js-module src="www/ios/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
</js-module>
<header-file src="src/ios/UIImage+CropScaleOrientation.h" />
<source-file src="src/ios/UIImage+CropScaleOrientation.m" />
<header-file src="src/ios/CDVCamera.h" />
<source-file src="src/ios/CDVCamera.m" />
<header-file src="src/ios/CDVJpegHeaderWriter.h" />
<source-file src="src/ios/CDVJpegHeaderWriter.m" />
<header-file src="src/ios/CDVExif.h" />
<framework src="ImageIO.framework" weak="true" />
<framework src="CoreLocation.framework" />
<framework src="CoreGraphics.framework" />
<framework src="AssetsLibrary.framework" />
<source-file src="src/ios/CDVJpegHeaderWriter.m" />
<header-file src="src/ios/CDVExif.h" />
<framework src="ImageIO.framework" weak="true" />
<framework src="CoreLocation.framework" />
<framework src="CoreGraphics.framework" />
<framework src="AssetsLibrary.framework" />
<framework src="MobileCoreServices.framework" />
</platform>
<framework src="CoreGraphics.framework" />
<framework src="AVFoundation.framework" />
<!-- blackberry10 -->
<platform name="blackberry10">
<source-file src="src/blackberry10/index.js" target-dir="Camera" />
<config-file target="www/config.xml" parent="/widget">
<feature name="Camera" value="Camera"/>
</config-file>
<config-file target="www/config.xml" parent="/widget/rim:permissions">
<rim:permit>access_shared</rim:permit>
</config-file>
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
</js-module>
</platform>
<!-- wp7 -->
<platform name="wp7">
</platform> -->
<!-- ios -->
<platform name="ios">
<config-file target="config.xml" parent="/*">
<feature name="Camera">
<param name="wp-package" value="Camera"/>
<param name="ios-package" value="CustomCamera" />
</feature>
</config-file>
<config-file target="config.xml" parent="/*">
<feature name="LocalStorage">
<param name="ios-package" value="CDVLocalStorage" />
</feature>
</config-file>
<config-file target="Properties/WMAppManifest.xml" parent="/Deployment/App/Capabilities">
<Capability Name="ID_CAP_ISV_CAMERA" />
<Capability Name="ID_CAP_MEDIALIB" />
<header-file src="src/ios/UIImage+CropScaleOrientation.h" />
<source-file src="src/ios/UIImage+CropScaleOrientation.m" />
<header-file src="src/ios/classes/CustomCamera.h" />
<source-file src="src/ios/classes/CustomCamera.m" />
<header-file src="src/ios/classes/AVCamPreviewView.h" />
<source-file src="src/ios/classes/AVCamPreviewView.m" />
<header-file src="src/ios/classes/AVCamViewController.h" />
<source-file src="src/ios/classes/AVCamViewController.m" />
<header-file src="src/ios/classes/CameraParameter.h" />
<source-file src="src/ios/classes/CameraParameter.m" />
<resource-file src="src/ios/classes/AVCamViewController_iPhone.xib" />
<resource-file src="src/ios/classes/AVCamViewController_iPad.xib" />
<resource-file src="src/ios/image/icon_back.png" />
<resource-file src="src/ios/image/icon_capture_pressed.png" />
<resource-file src="src/ios/image/icon_capture.png" />
<resource-file src="src/ios/image/icon_delete.png" />
<resource-file src="src/ios/image/icon_flash_auto.png" />
<resource-file src="src/ios/image/icon_flash_off.png" />
<resource-file src="src/ios/image/icon_flash.png" />
<resource-file src="src/ios/image/icon_flip.png" />
<resource-file src="src/ios/image/icon_max.png" />
<resource-file src="src/ios/image/icon_min.png" />
<resource-file src="src/ios/image/icon_submit.png" />
<resource-file src="src/ios/image/sample.png" />
<framework src="CoreGraphics.framework" weak="true" />
<framework src="AssetsLibrary.framework" weak="true" />
<framework src="AVFoundation.framework" weak="true" />
<framework src="CoreAudio.framework" weak="true" />
<framework src="CoreLocation.framework" weak="true" />
<framework src="MobileCoreServices.framework" weak="true" />
<preference name="CAMERA_USAGE_DESCRIPTION" default="This app requires access to your camera to take pictures" />
<config-file target="*-Info.plist" parent="NSCameraUsageDescription">
<string>$CAMERA_USAGE_DESCRIPTION</string>
</config-file>
<preference name="MICROPHONE_USAGE_DESCRIPTION" default="This app requires access to your microphone to take pictures" />
<config-file target="*-Info.plist" parent="NSMicrophoneUsageDescription">
<string>$MICROPHONE_USAGE_DESCRIPTION</string>
</config-file>
<preference name="PHOTO_LIBRARY_ADD_USAGE_DESCRIPTION" default="This app requires access to your photo library to save your pictures" />
<config-file target="*-Info.plist" parent="NSPhotoLibraryAddUsageDescription">
<string>$PHOTO_LIBRARY_ADD_USAGE_DESCRIPTION</string>
</config-file>
<source-file src="src/wp/Camera.cs" />
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
</js-module>
</platform>
<!-- wp8 -->
<platform name="wp8">
<!-- browser -->
<platform name="browser">
<config-file target="config.xml" parent="/*">
<feature name="Camera">
<param name="wp-package" value="Camera"/>
<param name="browser-package" value="Camera" />
</feature>
</config-file>
<config-file target="Properties/WMAppManifest.xml" parent="/Deployment/App/Capabilities">
<Capability Name="ID_CAP_ISV_CAMERA" />
<Capability Name="ID_CAP_MEDIALIB_PHOTO"/>
</config-file>
<source-file src="src/wp/Camera.cs" />
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
<js-module src="src/browser/CameraProxy.js" name="CameraProxy">
<runs />
</js-module>
</platform>
<!-- windows8 -->
<platform name="windows8">
<dependency id="org.apache.cordova.file" />
<!-- windows -->
<platform name="windows">
<config-file target="package.appxmanifest" parent="/Package/Capabilities">
<Capability Name="picturesLibrary" />
<DeviceCapability Name="webcam" />
</config-file>
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
</js-module>
<js-module src="src/windows8/CameraProxy.js" name="CameraProxy">
<merges target="" />
<js-module src="src/windows/CameraProxy.js" name="CameraProxy">
<runs />
</js-module>
</platform>
<!-- osx -->
<platform name="osx">
<config-file target="config.xml" parent="/*">
<feature name="Camera">
<param name="osx-package" value="CDVCamera"/>
</feature>
</config-file>
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
<clobbers target="CameraPopoverHandle" />
</js-module>
<header-file src="src/osx/CDVCamera.h" />
<source-file src="src/osx/CDVCamera.m" />
<framework src="Quartz.framework" />
<framework src="AppKit.framework" />
</platform>
</plugin>

1091
src/android/CameraLauncher.java Executable file → Normal file

File diff suppressed because it is too large Load Diff

103
src/android/CordovaUri.java Normal file
View File

@@ -0,0 +1,103 @@
/*
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.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.support.v4.content.FileProvider;
import java.io.File;
/*
* This class exists because Andorid FilesProvider doesn't work on Android 4.4.4 and below and throws
* weird errors. I'm not sure why writing to shared cache directories is somehow verboten, but it is
* and this error is irritating for a Compatibility library to have.
*
*/
public class CordovaUri {
private Uri androidUri;
private String fileName;
private Uri fileUri;
/*
* We always expect a FileProvider string to be passed in for the file that we create
*
*/
CordovaUri (File dir,Uri inputUri)
{
//Determine whether the file is a content or file URI
if(inputUri.getScheme().equals("content"))
{
androidUri = inputUri;
fileName = getFileNameFromUri(dir,androidUri);
fileUri = Uri.parse("file://" + fileName);
}
else
{
fileUri = inputUri;
fileName = FileHelper.stripFileProtocol(inputUri.toString());
}
}
public Uri getFileUri()
{
return fileUri;
}
public String getFilePath()
{
return fileName;
}
/*
* This only gets called by takePicture
*/
public Uri getCorrectUri()
{
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
return androidUri;
else
return fileUri;
}
/*
* This is dirty, but it does the job.
*
* Since the FilesProvider doesn't really provide you a way of getting a URL from the file,
* and since we actually need the Camera to create the file for us most of the time, we don't
* actually write the file, just generate the location based on a timestamp, we need to get it
* back from the Intent.
*
* However, the FilesProvider preserves the path, so we can at least write to it from here, since
* we own the context in this case.
*/
private String getFileNameFromUri(File external_storage,Uri uri) {
String fullUri = uri.toString();
String partial_path = fullUri.split("external_files")[1];
String path = external_storage.getAbsolutePath() + partial_path;
return path;
}
}

View File

@@ -6,9 +6,7 @@
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
@@ -18,8 +16,16 @@
*/
package org.apache.cordova.camera;
import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.content.CursorLoader;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.webkit.MimeTypeMap;
import org.apache.cordova.CordovaInterface;
@@ -43,27 +49,15 @@ public class FileHelper {
* @return the full path to the file
*/
@SuppressWarnings("deprecation")
public static String getRealPath(String uriString, CordovaInterface cordova) {
public static String getRealPath(Uri uri, 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;
}
if (Build.VERSION.SDK_INT < 11)
realPath = FileHelper.getRealPathFromURI_BelowAPI11(cordova.getActivity(), uri);
// SDK >= 11
else
realPath = FileHelper.getRealPathFromURI_API11_And_Above(cordova.getActivity(), uri);
return realPath;
}
@@ -76,8 +70,103 @@ public class FileHelper {
* @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);
public static String getRealPath(String uriString, CordovaInterface cordova) {
return FileHelper.getRealPath(Uri.parse(uriString), cordova);
}
@SuppressLint("NewApi")
public static String getRealPathFromURI_API11_And_Above(final Context context, final Uri uri) {
final boolean isKitKat = Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT;
// DocumentProvider
if (isKitKat && DocumentsContract.isDocumentUri(context, uri)) {
// ExternalStorageProvider
if (isExternalStorageDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
if ("primary".equalsIgnoreCase(type)) {
return Environment.getExternalStorageDirectory() + "/" + split[1];
}
// TODO handle non-primary volumes
}
// DownloadsProvider
else if (isDownloadsDocument(uri)) {
final String id = DocumentsContract.getDocumentId(uri);
if (id != null && id.length() > 0) {
if (id.startsWith("raw:")) {
return id.replaceFirst("raw:", "");
}
try {
final Uri contentUri = ContentUris.withAppendedId(
Uri.parse("content://downloads/public_downloads"), Long.valueOf(id));
return getDataColumn(context, contentUri, null, null);
} catch (NumberFormatException e) {
return null;
}
} else {
return null;
}
}
// MediaProvider
else if (isMediaDocument(uri)) {
final String docId = DocumentsContract.getDocumentId(uri);
final String[] split = docId.split(":");
final String type = split[0];
Uri contentUri = null;
if ("image".equals(type)) {
contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
} else if ("video".equals(type)) {
contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
} else if ("audio".equals(type)) {
contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
}
final String selection = "_id=?";
final String[] selectionArgs = new String[] {
split[1]
};
return getDataColumn(context, contentUri, selection, selectionArgs);
}
}
// MediaStore (and general)
else if ("content".equalsIgnoreCase(uri.getScheme())) {
// Return the remote address
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
return getDataColumn(context, uri, null, null);
}
// File
else if ("file".equalsIgnoreCase(uri.getScheme())) {
return uri.getPath();
}
return null;
}
public static String getRealPathFromURI_BelowAPI11(Context context, Uri contentUri) {
String[] proj = { MediaStore.Images.Media.DATA };
String result = null;
try {
Cursor cursor = context.getContentResolver().query(contentUri, proj, null, null, null);
int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
cursor.moveToFirst();
result = cursor.getString(column_index);
} catch (Exception e) {
result = null;
}
return result;
}
/**
@@ -88,25 +177,36 @@ public class FileHelper {
* @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 {
public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova)
throws IOException {
InputStream returnValue = null;
if (uriString.startsWith("content")) {
Uri uri = Uri.parse(uriString);
return cordova.getActivity().getContentResolver().openInputStream(uri);
returnValue = cordova.getActivity().getContentResolver().openInputStream(uri);
} else if (uriString.startsWith("file://")) {
int question = uriString.indexOf("?");
if (question > -1) {
uriString = uriString.substring(0,question);
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);
returnValue = cordova.getActivity().getAssets().open(relativePath);
} else {
return new FileInputStream(getRealPath(uriString, cordova));
// might still be content so try that first
try {
returnValue = cordova.getActivity().getContentResolver().openInputStream(Uri.parse(uriString));
} catch (Exception e) {
returnValue = null;
}
if (returnValue == null) {
returnValue = new FileInputStream(getRealPath(uriString, cordova));
}
}
} else {
return new FileInputStream(getRealPath(uriString, cordova));
returnValue = new FileInputStream(uriString);
}
return returnValue;
}
/**
@@ -155,4 +255,76 @@ public class FileHelper {
return mimeType;
}
/**
* Get the value of the data column for this Uri. This is useful for
* MediaStore Uris, and other file-based ContentProviders.
*
* @param context The context.
* @param uri The Uri to query.
* @param selection (Optional) Filter used in the query.
* @param selectionArgs (Optional) Selection arguments used in the query.
* @return The value of the _data column, which is typically a file path.
* @author paulburke
*/
public static String getDataColumn(Context context, Uri uri, String selection,
String[] selectionArgs) {
Cursor cursor = null;
final String column = "_data";
final String[] projection = {
column
};
try {
cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs,
null);
if (cursor != null && cursor.moveToFirst()) {
final int column_index = cursor.getColumnIndexOrThrow(column);
return cursor.getString(column_index);
}
} catch (Exception e) {
return null;
} finally {
if (cursor != null)
cursor.close();
}
return null;
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is ExternalStorageProvider.
* @author paulburke
*/
public static boolean isExternalStorageDocument(Uri uri) {
return "com.android.externalstorage.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is DownloadsProvider.
* @author paulburke
*/
public static boolean isDownloadsDocument(Uri uri) {
return "com.android.providers.downloads.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is MediaProvider.
* @author paulburke
*/
public static boolean isMediaDocument(Uri uri) {
return "com.android.providers.media.documents".equals(uri.getAuthority());
}
/**
* @param uri The Uri to check.
* @return Whether the Uri authority is Google Photos.
*/
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
}

View File

@@ -0,0 +1,21 @@
/*
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;
public class FileProvider extends android.support.v4.content.FileProvider {}

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
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.
-->
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<cache-path name="external_files" path="."/>
</paths>

View File

@@ -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);
}
};

126
src/browser/CameraProxy.js Normal file
View File

@@ -0,0 +1,126 @@
/*
*
* 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 HIGHEST_POSSIBLE_Z_INDEX = 2147483647;
function takePicture (success, error, opts) {
if (opts && opts[2] === 1) {
capture(success, error, opts);
} else {
var input = document.createElement('input');
input.style.position = 'relative';
input.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX;
input.className = 'cordova-camera-select';
input.type = 'file';
input.name = 'files[]';
input.onchange = function (inputEvent) {
var reader = new FileReader(); /* eslint no-undef : 0 */
reader.onload = function (readerEvent) {
input.parentNode.removeChild(input);
var imageData = readerEvent.target.result;
return success(imageData.substr(imageData.indexOf(',') + 1));
};
reader.readAsDataURL(inputEvent.target.files[0]);
};
document.body.appendChild(input);
}
}
function capture (success, errorCallback, opts) {
var localMediaStream;
var targetWidth = opts[3];
var targetHeight = opts[4];
targetWidth = targetWidth === -1 ? 320 : targetWidth;
targetHeight = targetHeight === -1 ? 240 : targetHeight;
var video = document.createElement('video');
var button = document.createElement('button');
var parent = document.createElement('div');
parent.style.position = 'relative';
parent.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX;
parent.className = 'cordova-camera-capture';
parent.appendChild(video);
parent.appendChild(button);
video.width = targetWidth;
video.height = targetHeight;
button.innerHTML = 'Capture!';
button.onclick = function () {
// create a canvas and capture a frame from video stream
var canvas = document.createElement('canvas');
canvas.width = targetWidth;
canvas.height = targetHeight;
canvas.getContext('2d').drawImage(video, 0, 0, targetWidth, targetHeight);
// convert image stored in canvas to base64 encoded image
var imageData = canvas.toDataURL('image/png');
imageData = imageData.replace('data:image/png;base64,', '');
// stop video stream, remove video and button.
// Note that MediaStream.stop() is deprecated as of Chrome 47.
if (localMediaStream.stop) {
localMediaStream.stop();
} else {
localMediaStream.getTracks().forEach(function (track) {
track.stop();
});
}
parent.parentNode.removeChild(parent);
return success(imageData);
};
navigator.getUserMedia = navigator.getUserMedia ||
navigator.webkitGetUserMedia ||
navigator.mozGetUserMedia ||
navigator.msGetUserMedia;
var successCallback = function (stream) {
localMediaStream = stream;
if ('srcObject' in video) {
video.srcObject = localMediaStream;
} else {
video.src = window.URL.createObjectURL(localMediaStream);
}
video.play();
document.body.appendChild(parent);
};
if (navigator.getUserMedia) {
navigator.getUserMedia({video: true, audio: false}, successCallback, errorCallback);
} else {
alert('Browser does not support camera :(');
}
}
module.exports = {
takePicture: takePicture,
cleanup: function () {}
};
require('cordova/exec/proxy').add('Camera', module.exports);

View File

@@ -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);

View File

@@ -42,21 +42,39 @@ enum CDVMediaType {
};
typedef NSUInteger CDVMediaType;
@interface CDVCameraPicker : UIImagePickerController
{}
@interface CDVPictureOptions : NSObject
@property (strong) NSNumber* quality;
@property (assign) CDVDestinationType destinationType;
@property (assign) UIImagePickerControllerSourceType sourceType;
@property (assign) CGSize targetSize;
@property (assign) CDVEncodingType encodingType;
@property (assign) CDVMediaType mediaType;
@property (assign) BOOL allowsEditing;
@property (assign) BOOL correctOrientation;
@property (assign) BOOL saveToPhotoAlbum;
@property (strong) NSDictionary* popoverOptions;
@property (assign) UIImagePickerControllerCameraDevice cameraDirection;
@property (assign) BOOL popoverSupported;
@property (assign) BOOL usesGeolocation;
@property (assign) BOOL cropToSize;
+ (instancetype) createFromTakePictureArguments:(CDVInvokedUrlCommand*)command;
@end
@interface CDVCameraPicker : UIImagePickerController
@property (strong) CDVPictureOptions* pictureOptions;
@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;
@property (strong) UIPopoverController* pickerPopoverController;
@property (assign) BOOL cropToSize;
@property (strong) UIView* webView;
+ (instancetype) createFromPictureOptions:(CDVPictureOptions*)options;
@end
@@ -84,7 +102,6 @@ typedef NSUInteger CDVMediaType;
* 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;
@@ -92,9 +109,6 @@ typedef NSUInteger CDVMediaType;
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo;
- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker;
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
- (UIImage*)imageByScalingAndCroppingForSize:(UIImage*)anImage toSize:(CGSize)targetSize;
- (UIImage*)imageByScalingNotCroppingForSize:(UIImage*)anImage toSize:(CGSize)frameSize;
- (UIImage*)imageCorrectedForCaptureOrientation:(UIImage*)anImage;
- (void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation;
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error;

File diff suppressed because it is too large Load Diff

View File

@@ -190,7 +190,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
// construct the complete app1 data block
app1 = [[NSMutableString alloc] initWithFormat: @"%@%04x%@%@%@%@%@",
app1marker,
16 + ([exifIFD length]/2) + ([subExifIFD length]/2) /*16+[exifIFD length]/2*/,
(unsigned int)(16 + ([exifIFD length]/2) + ([subExifIFD length]/2)) /*16+[exifIFD length]/2*/,
exifmarker,
tiffheader,
ifd0offset,
@@ -268,10 +268,10 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
}
// calculate IFD0 terminal offset tags, currently ExifSubIFD
int entrycount = [ifdblock count];
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 numberWithInt:[exifstr length] / 2 + [dbstr length] / 2 + 18+8];
NSNumber * offset = [NSNumber numberWithUnsignedInteger:[exifstr length] / 2 + [dbstr length] / 2 + 18+8];
[self appendExifOffsetTagTo: exifstr
withOffset : offset];
@@ -293,7 +293,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
NSNumber * dataformat = [formtemplate objectAtIndex:1];
NSNumber * components = [formtemplate objectAtIndex:2];
if([components intValue] == 0) {
components = [NSNumber numberWithInt: [data length] * DataTypeToWidth[[dataformat intValue]-1]];
components = [NSNumber numberWithUnsignedInteger:[data length] * DataTypeToWidth[[dataformat intValue]-1]];
}
return [[NSString alloc] initWithFormat: @"%@%@%08x",
@@ -344,7 +344,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
[datastr appendString:[dataformat objectAtIndex:3]];
}
if ([datastr length] < 8) {
NSString * format = [NSString stringWithFormat:@"%%0%dd", 8 - [datastr length]];
NSString * format = [NSString stringWithFormat:@"%%0%dd", (int)(8 - [datastr length])];
[datastr appendFormat:format,0];
}
return datastr;
@@ -464,7 +464,7 @@ const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a
-(void) expandContinuedFraction: (NSArray*) fractionlist
withResultNumerator: (NSNumber**) numerator
withResultDenominator: (NSNumber**) denominator {
int i = 0;
NSUInteger i = 0;
int den = 0;
int num = 0;
if ([fractionlist count] == 1) {

View File

@@ -0,0 +1,29 @@
/*
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 <UIKit/UIKit.h>
@interface UIImage (CropScaleOrientation)
- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize;
- (UIImage*)imageCorrectedForCaptureOrientation;
- (UIImage*)imageCorrectedForCaptureOrientation:(UIImageOrientation)imageOrientation;
- (UIImage*)imageByScalingNotCroppingForSize:(CGSize)targetSize;
@end

View File

@@ -0,0 +1,175 @@
/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License. You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied. See the License for the
specific language governing permissions and limitations
under the License.
*/
#import "UIImage+CropScaleOrientation.h"
@implementation UIImage (CropScaleOrientation)
- (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize
{
UIImage* sourceImage = self;
UIImage* newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGFloat scaledWidth = targetWidth;
CGFloat scaledHeight = targetHeight;
CGPoint thumbnailPoint = CGPointMake(0.0, 0.0);
if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
if (widthFactor > heightFactor) {
scaleFactor = widthFactor; // scale to fit height
} else {
scaleFactor = heightFactor; // scale to fit width
}
scaledWidth = width * scaleFactor;
scaledHeight = height * scaleFactor;
// center the image
if (widthFactor > heightFactor) {
thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5;
} else if (widthFactor < heightFactor) {
thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5;
}
}
UIGraphicsBeginImageContext(targetSize); // this will crop
CGRect thumbnailRect = CGRectZero;
thumbnailRect.origin = thumbnailPoint;
thumbnailRect.size.width = scaledWidth;
thumbnailRect.size.height = scaledHeight;
[sourceImage drawInRect:thumbnailRect];
newImage = UIGraphicsGetImageFromCurrentImageContext();
if (newImage == nil) {
NSLog(@"could not scale image");
}
// pop the context to get back to the default
UIGraphicsEndImageContext();
return newImage;
}
- (UIImage*)imageCorrectedForCaptureOrientation:(UIImageOrientation)imageOrientation
{
float rotation_radians = 0;
bool perpendicular = false;
switch (imageOrientation) {
case UIImageOrientationUp :
rotation_radians = 0.0;
break;
case UIImageOrientationDown:
rotation_radians = M_PI; // don't be scared of radians, if you're reading this, you're good at math
break;
case UIImageOrientationRight:
rotation_radians = M_PI_2;
perpendicular = true;
break;
case UIImageOrientationLeft:
rotation_radians = -M_PI_2;
perpendicular = true;
break;
default:
break;
}
UIGraphicsBeginImageContext(CGSizeMake(self.size.width, self.size.height));
CGContextRef context = UIGraphicsGetCurrentContext();
// Rotate around the center point
CGContextTranslateCTM(context, self.size.width / 2, self.size.height / 2);
CGContextRotateCTM(context, rotation_radians);
CGContextScaleCTM(context, 1.0, -1.0);
float width = perpendicular ? self.size.height : self.size.width;
float height = perpendicular ? self.size.width : self.size.height;
CGContextDrawImage(context, CGRectMake(-width / 2, -height / 2, width, height), [self CGImage]);
// Move the origin back since the rotation might've change it (if its 90 degrees)
if (perpendicular) {
CGContextTranslateCTM(context, -self.size.height / 2, -self.size.width / 2);
}
UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
- (UIImage*)imageCorrectedForCaptureOrientation
{
return [self imageCorrectedForCaptureOrientation:[self imageOrientation]];
}
- (UIImage*)imageByScalingNotCroppingForSize:(CGSize)targetSize
{
UIImage* sourceImage = self;
UIImage* newImage = nil;
CGSize imageSize = sourceImage.size;
CGFloat width = imageSize.width;
CGFloat height = imageSize.height;
CGFloat targetWidth = targetSize.width;
CGFloat targetHeight = targetSize.height;
CGFloat scaleFactor = 0.0;
CGSize scaledSize = targetSize;
if (CGSizeEqualToSize(imageSize, targetSize) == NO) {
CGFloat widthFactor = targetWidth / width;
CGFloat heightFactor = targetHeight / height;
// opposite comparison to imageByScalingAndCroppingForSize in order to contain the image within the given bounds
if (widthFactor > heightFactor) {
scaleFactor = heightFactor; // scale to fit height
} else {
scaleFactor = widthFactor; // scale to fit width
}
scaledSize = CGSizeMake(MIN(width * scaleFactor, targetWidth), MIN(height * scaleFactor, targetHeight));
}
// If the pixels are floats, it causes a white line in iOS8 and probably other versions too
scaledSize.width = (int)scaledSize.width;
scaledSize.height = (int)scaledSize.height;
UIGraphicsBeginImageContext(scaledSize); // this will resize
[sourceImage drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)];
newImage = UIGraphicsGetImageFromCurrentImageContext();
if (newImage == nil) {
NSLog(@"could not scale image");
}
// pop the context to get back to the default
UIGraphicsEndImageContext();
return newImage;
}
@end

View File

@@ -0,0 +1,9 @@
#import <UIKit/UIKit.h>
@class AVCaptureSession;
@interface AVCamPreviewView : UIView
@property (nonatomic) AVCaptureSession *session;
@end

View File

@@ -0,0 +1,21 @@
#import "AVCamPreviewView.h"
#import <AVFoundation/AVFoundation.h>
@implementation AVCamPreviewView
+ (Class)layerClass
{
return [AVCaptureVideoPreviewLayer class];
}
- (AVCaptureSession *)session
{
return [(AVCaptureVideoPreviewLayer *)[self layer] session];
}
- (void)setSession:(AVCaptureSession *)session
{
[(AVCaptureVideoPreviewLayer *)[self layer] setSession:session];
}
@end

View File

@@ -0,0 +1,35 @@
#import <UIKit/UIKit.h>
#import "CameraParameter.h"
@interface AVCamViewController : UIViewController
{
NSData *_imageData;
void (^_callback)(UIImage *, NSString *, NSString *);
UIPinchGestureRecognizer *twoFingerPinch;
CGRect frameBtnThumb;
UIImage *capturedImage;
NSData *capturedImageData;
BOOL isRotated;
CGFloat fDist;
}
@property (weak, nonatomic) IBOutlet UIView *saveBgPanel;
@property (weak, nonatomic) IBOutlet UIView *topBgPanel;
@property (weak, nonatomic) IBOutlet UIImageView *capturedImageView;
@property (weak, nonatomic) IBOutlet UIButton *btnBigDeletePicture;
@property (weak, nonatomic) IBOutlet UIButton *btnDeletePicture;
@property (weak, nonatomic) IBOutlet UIButton *btnSaveImage;
@property (weak, nonatomic) IBOutlet UIButton *btnBigSaveImage;
@property (weak, nonatomic) IBOutlet UISlider *opacitySlider;
@property (nonatomic, retain) CameraParameter *params;
- (id)initWithParams:(CameraParameter *)parameter WithCallback:(void (^)(UIImage *, NSString *, NSString *))callback;
@end

View File

@@ -0,0 +1,811 @@
#import "AVCamViewController.h"
#import <AVFoundation/AVFoundation.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import "AVCamPreviewView.h"
static void *CapturingStillImageContext = &CapturingStillImageContext;
static void *RecordingContext = &RecordingContext;
static void *SessionRunningAndDeviceAuthorizedContext = &SessionRunningAndDeviceAuthorizedContext;
@interface AVCamViewController () <AVCaptureFileOutputRecordingDelegate>
// For use in the storyboards.
@property (nonatomic, weak) IBOutlet AVCamPreviewView *previewView;
@property (nonatomic, weak) IBOutlet UIButton *recordButton;
@property (nonatomic, weak) IBOutlet UIButton *cameraButton;
@property (nonatomic, weak) IBOutlet UIButton *stillButton;
@property (weak, nonatomic) IBOutlet UIButton *btnThumb;
@property (weak, nonatomic) IBOutlet UIButton *btnFlash;
@property (weak, nonatomic) IBOutlet UIButton *btnBack;
@property (nonatomic, weak) IBOutlet UIImageView *imgSmallThumbNail;
@property (nonatomic, weak) IBOutlet UIImageView *imgBigThumbNail;
- (IBAction)onTapThumb:(id)sender;
- (IBAction)onTapCameraFlash:(id)sender;
- (IBAction)onBack:(id)sender;
- (IBAction)toggleMovieRecording:(id)sender;
- (IBAction)changeCamera:(id)sender;
- (IBAction)snapStillImage:(id)sender;
- (IBAction)focusAndExposeTap:(UIGestureRecognizer *)gestureRecognizer;
// Session management.
@property (nonatomic) dispatch_queue_t sessionQueue; // Communicate with the session and other session objects on this queue.
@property (nonatomic) AVCaptureSession *session;
@property (nonatomic) AVCaptureDeviceInput *videoDeviceInput;
@property (nonatomic) AVCaptureMovieFileOutput *movieFileOutput;
@property (nonatomic) AVCaptureStillImageOutput *stillImageOutput;
// Utilities.
@property (nonatomic) UIBackgroundTaskIdentifier backgroundRecordingID;
@property (nonatomic, getter = isDeviceAuthorized) BOOL deviceAuthorized;
@property (nonatomic, readonly, getter = isSessionRunningAndDeviceAuthorized) BOOL sessionRunningAndDeviceAuthorized;
@property (nonatomic) BOOL lockInterfaceRotation;
@property (nonatomic) id runtimeErrorHandlingObserver;
@end
@implementation AVCamViewController
@synthesize params;
- (BOOL)isSessionRunningAndDeviceAuthorized {
return [[self session] isRunning] && [self isDeviceAuthorized];
}
+ (NSSet *)keyPathsForValuesAffectingSessionRunningAndDeviceAuthorized {
return [NSSet setWithObjects:@"session.running", @"deviceAuthorized", nil];
}
- (id)initWithParams:(CameraParameter *)parameter WithCallback:(void (^)(UIImage *, NSString *, NSString *))callback {
self = [super initWithNibName:nil bundle:nil];
self.params = parameter;
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
self = [super initWithNibName:@"AVCamViewController_iPad" bundle:nil];
}
else {
self = [super initWithNibName:@"AVCamViewController_iPhone" bundle:nil];
}
if (self) {
_callback = callback;
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Create the AVCaptureSession
AVCaptureSession *session = [[AVCaptureSession alloc] init];
[self setSession:session];
// Setup the preview view
[[self previewView] setSession:session];
// Check for device authorization
[self checkDeviceAuthorizationStatus];
// In general it is not safe to mutate an AVCaptureSession or any of its inputs, outputs, or connections from multiple threads at the same time.
// Why not do all of this on the main queue?
// -[AVCaptureSession startRunning] is a blocking call which can take a long time. We dispatch session setup to the sessionQueue so that the main queue isn't blocked (which keeps the UI responsive).
dispatch_queue_t sessionQueue = dispatch_queue_create("session queue", DISPATCH_QUEUE_SERIAL);
[self setSessionQueue:sessionQueue];
dispatch_async(sessionQueue, ^{
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
NSError *error = nil;
AVCaptureDevice *videoDevice;
if (params.nDefaultCamera == 0) {
videoDevice = [AVCamViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionBack];
}
else {
videoDevice = [AVCamViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:AVCaptureDevicePositionFront];
}
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:&error];
dispatch_async(dispatch_get_main_queue(), ^{
if (![videoDevice hasTorch]) {
self.btnFlash.hidden = YES;
// self.cameraButton.center = self.btnThumb.center;
// self.btnThumb.center = self.btnFlash.center;
}
});
if (error) {
NSLog(@"%@", error);
}
if ([session canAddInput:videoDeviceInput]) {
[session addInput:videoDeviceInput];
[self setVideoDeviceInput:videoDeviceInput];
dispatch_async(dispatch_get_main_queue(), ^{
// Why are we dispatching this to the main queue?
// Because AVCaptureVideoPreviewLayer is the backing layer for AVCamPreviewView and UIView can only be manipulated on main thread.
// Note: As an exception to the above rule, it is not necessary to serialize video orientation changes on the AVCaptureVideoPreviewLayers connection with other session manipulation.
[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] setVideoOrientation:(AVCaptureVideoOrientation)[[UIApplication sharedApplication] statusBarOrientation]];
});
}
AVCaptureDevice *audioDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];
AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:&error];
if (error) {
NSLog(@"%@", error);
}
if ([session canAddInput:audioDeviceInput]) {
[session addInput:audioDeviceInput];
}
AVCaptureMovieFileOutput *movieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
if ([session canAddOutput:movieFileOutput]) {
[session addOutput:movieFileOutput];
AVCaptureConnection *connection = [movieFileOutput connectionWithMediaType:AVMediaTypeVideo];
if ([connection isVideoStabilizationSupported])
//connection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
//[connection setEnablesVideoStabilizationWhenAvailable:YES];
[self setMovieFileOutput:movieFileOutput];
}
AVCaptureStillImageOutput *stillImageOutput = [[AVCaptureStillImageOutput alloc] init];
if ([session canAddOutput:stillImageOutput]) {
[stillImageOutput setOutputSettings:@{ AVVideoCodecKey : AVVideoCodecJPEG }];
[session addOutput:stillImageOutput];
[self setStillImageOutput:stillImageOutput];
}
});
[self initialize];
}
- (void)viewWillAppear:(BOOL)animated {
dispatch_async([self sessionQueue], ^{
[self addObserver:self forKeyPath:@"sessionRunningAndDeviceAuthorized" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:SessionRunningAndDeviceAuthorizedContext];
[self addObserver:self forKeyPath:@"stillImageOutput.capturingStillImage" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:CapturingStillImageContext];
[self addObserver:self forKeyPath:@"movieFileOutput.recording" options:(NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew) context:RecordingContext];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]];
__weak AVCamViewController *weakSelf = self;
[self setRuntimeErrorHandlingObserver:[[NSNotificationCenter defaultCenter] addObserverForName:AVCaptureSessionRuntimeErrorNotification object:[self session] queue:nil usingBlock: ^(NSNotification *note) {
AVCamViewController *strongSelf = weakSelf;
dispatch_async([strongSelf sessionQueue], ^{
// Manually restarting the session since it must have been stopped due to an error.
[[strongSelf session] startRunning];
[[strongSelf recordButton] setTitle:NSLocalizedString(@"Record", @"Recording button record title") forState:UIControlStateNormal];
});
}]];
[[self session] startRunning];
});
}
- (void)viewDidDisappear:(BOOL)animated {
dispatch_async([self sessionQueue], ^{
[[self session] stopRunning];
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:[[self videoDeviceInput] device]];
[[NSNotificationCenter defaultCenter] removeObserver:[self runtimeErrorHandlingObserver]];
[self removeObserver:self forKeyPath:@"sessionRunningAndDeviceAuthorized" context:SessionRunningAndDeviceAuthorizedContext];
[self removeObserver:self forKeyPath:@"stillImageOutput.capturingStillImage" context:CapturingStillImageContext];
[self removeObserver:self forKeyPath:@"movieFileOutput.recording" context:RecordingContext];
});
}
- (BOOL)prefersStatusBarHidden {
return YES;
}
- (BOOL)shouldAutorotate {
// Disable autorotation of the interface when recording is in progress.
return ![self lockInterfaceRotation];
}
- (NSUInteger)supportedInterfaceOrientations {
return UIInterfaceOrientationMaskAll;
// return UIInterfaceOrientationMaskPortrait;
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] setVideoOrientation:(AVCaptureVideoOrientation)toInterfaceOrientation];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context == CapturingStillImageContext) {
BOOL isCapturingStillImage = [change[NSKeyValueChangeNewKey] boolValue];
if (isCapturingStillImage) {
[self runStillImageCaptureAnimation];
}
}
else if (context == RecordingContext) {
BOOL isRecording = [change[NSKeyValueChangeNewKey] boolValue];
dispatch_async(dispatch_get_main_queue(), ^{
if (isRecording) {
[[self cameraButton] setEnabled:NO];
[[self recordButton] setTitle:NSLocalizedString(@"Stop", @"Recording button stop title") forState:UIControlStateNormal];
[[self recordButton] setEnabled:YES];
}
else {
[[self cameraButton] setEnabled:YES];
[[self recordButton] setTitle:NSLocalizedString(@"Record", @"Recording button record title") forState:UIControlStateNormal];
[[self recordButton] setEnabled:YES];
}
});
}
else if (context == SessionRunningAndDeviceAuthorizedContext) {
BOOL isRunning = [change[NSKeyValueChangeNewKey] boolValue];
dispatch_async(dispatch_get_main_queue(), ^{
if (isRunning) {
[[self cameraButton] setEnabled:YES];
[[self recordButton] setEnabled:YES];
[[self stillButton] setEnabled:YES];
}
else {
[[self cameraButton] setEnabled:NO];
[[self recordButton] setEnabled:NO];
[[self stillButton] setEnabled:NO];
}
});
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
#pragma mark Actions
- (IBAction)toggleMovieRecording:(id)sender {
[[self recordButton] setEnabled:NO];
dispatch_async([self sessionQueue], ^{
if (![[self movieFileOutput] isRecording]) {
[self setLockInterfaceRotation:YES];
if ([[UIDevice currentDevice] isMultitaskingSupported]) {
// Setup background task. This is needed because the captureOutput:didFinishRecordingToOutputFileAtURL: callback is not received until AVCam returns to the foreground unless you request background execution time. This also ensures that there will be time to write the file to the assets library when AVCam is backgrounded. To conclude this background execution, -endBackgroundTask is called in -recorder:recordingDidFinishToOutputFileURL:error: after the recorded file has been saved.
[self setBackgroundRecordingID:[[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil]];
}
// Update the orientation on the movie file output video connection before starting recording.
[[[self movieFileOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] videoOrientation]];
// Turning OFF flash for video recording
[AVCamViewController setFlashMode:AVCaptureFlashModeOff forDevice:[[self videoDeviceInput] device]];
// Start recording to a temporary file.
NSString *outputFilePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[@"movie" stringByAppendingPathExtension:@"mov"]];
[[self movieFileOutput] startRecordingToOutputFileURL:[NSURL fileURLWithPath:outputFilePath] recordingDelegate:self];
}
else {
[[self movieFileOutput] stopRecording];
}
});
}
- (IBAction)changeCamera:(id)sender {
[[self cameraButton] setEnabled:NO];
[[self recordButton] setEnabled:NO];
[[self stillButton] setEnabled:NO];
dispatch_async([self sessionQueue], ^{
AVCaptureDevice *currentVideoDevice = [[self videoDeviceInput] device];
AVCaptureDevicePosition preferredPosition = AVCaptureDevicePositionUnspecified;
AVCaptureDevicePosition currentPosition = [currentVideoDevice position];
switch (currentPosition) {
case AVCaptureDevicePositionUnspecified:
preferredPosition = AVCaptureDevicePositionBack;
break;
case AVCaptureDevicePositionBack:
preferredPosition = AVCaptureDevicePositionFront;
break;
case AVCaptureDevicePositionFront:
preferredPosition = AVCaptureDevicePositionBack;
break;
}
AVCaptureDevice *videoDevice = [AVCamViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:preferredPosition];
AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:nil];
dispatch_async(dispatch_get_main_queue(), ^{
[self.btnFlash setImage:[UIImage imageNamed:@"icon_flash_auto.png"] forState:UIControlStateNormal];
self.btnFlash.tag = 0;
if ([videoDevice hasTorch] && [videoDevice hasFlash]) {
[videoDevice lockForConfiguration:nil];
[videoDevice setTorchMode:NO];
[videoDevice setFlashMode:AVCaptureFlashModeOn];
[videoDevice unlockForConfiguration];
[self.btnFlash setImage:[UIImage imageNamed:@"icon_flash_auto.png"] forState:UIControlStateNormal];
self.btnFlash.tag = 0;
self.btnFlash.hidden = NO;
return;
}
if (![videoDevice hasTorch]) {
self.btnFlash.hidden = YES;
}
else if ([videoDevice hasTorch] && params.bSwitchFlash) {
self.btnFlash.hidden = NO;
}
});
[[self session] beginConfiguration];
[[self session] removeInput:[self videoDeviceInput]];
if ([[self session] canAddInput:videoDeviceInput]) {
[[NSNotificationCenter defaultCenter] removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:currentVideoDevice];
[AVCamViewController setFlashMode:AVCaptureFlashModeAuto forDevice:videoDevice];
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(subjectAreaDidChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:videoDevice];
[[self session] addInput:videoDeviceInput];
[self setVideoDeviceInput:videoDeviceInput];
}
else {
[[self session] addInput:[self videoDeviceInput]];
}
[[self session] commitConfiguration];
dispatch_async(dispatch_get_main_queue(), ^{
[[self cameraButton] setEnabled:YES];
[[self recordButton] setEnabled:YES];
[[self stillButton] setEnabled:YES];
});
});
}
- (IBAction)snapStillImage:(id)sender {
dispatch_async([self sessionQueue], ^{
// Update the orientation on the still image output video connection before capturing.
[[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] setVideoOrientation:[[(AVCaptureVideoPreviewLayer *)[[self previewView] layer] connection] videoOrientation]];
// Flash set to Auto for Still Capture
[AVCamViewController setFlashMode:AVCaptureFlashModeAuto forDevice:[[self videoDeviceInput] device]];
// Capture a still image.
[[self stillImageOutput] captureStillImageAsynchronouslyFromConnection:[[self stillImageOutput] connectionWithMediaType:AVMediaTypeVideo] completionHandler: ^(CMSampleBufferRef imageDataSampleBuffer, NSError *error) {
if (imageDataSampleBuffer) {
NSData *imageData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageDataSampleBuffer];
capturedImage = [[UIImage alloc] initWithData:imageData];
capturedImageData = imageData;
[self takePicture];
}
}];
});
}
- (IBAction)focusAndExposeTap:(UIGestureRecognizer *)gestureRecognizer {
CGPoint devicePoint = [(AVCaptureVideoPreviewLayer *)[[self previewView] layer] captureDevicePointOfInterestForPoint:[gestureRecognizer locationInView:[gestureRecognizer view]]];
[self focusWithMode:AVCaptureFocusModeAutoFocus exposeWithMode:AVCaptureExposureModeAutoExpose atDevicePoint:devicePoint monitorSubjectAreaChange:YES];
}
- (void)subjectAreaDidChange:(NSNotification *)notification {
CGPoint devicePoint = CGPointMake(.5, .5);
[self focusWithMode:AVCaptureFocusModeContinuousAutoFocus exposeWithMode:AVCaptureExposureModeContinuousAutoExposure atDevicePoint:devicePoint monitorSubjectAreaChange:NO];
}
#pragma mark File Output Delegate
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error {
if (error)
NSLog(@"%@", error);
[self setLockInterfaceRotation:NO];
// Note the backgroundRecordingID for use in the ALAssetsLibrary completion handler to end the background task associated with this recording. This allows a new recording to be started, associated with a new UIBackgroundTaskIdentifier, once the movie file output's -isRecording is back to NO which happens sometime after this method returns.
UIBackgroundTaskIdentifier backgroundRecordingID = [self backgroundRecordingID];
[self setBackgroundRecordingID:UIBackgroundTaskInvalid];
[[[ALAssetsLibrary alloc] init] writeVideoAtPathToSavedPhotosAlbum:outputFileURL completionBlock: ^(NSURL *assetURL, NSError *error) {
if (error)
NSLog(@"%@", error);
[[NSFileManager defaultManager] removeItemAtURL:outputFileURL error:nil];
if (backgroundRecordingID != UIBackgroundTaskInvalid)
[[UIApplication sharedApplication] endBackgroundTask:backgroundRecordingID];
}];
}
#pragma mark Device Configuration
- (void)focusWithMode:(AVCaptureFocusMode)focusMode exposeWithMode:(AVCaptureExposureMode)exposureMode atDevicePoint:(CGPoint)point monitorSubjectAreaChange:(BOOL)monitorSubjectAreaChange {
dispatch_async([self sessionQueue], ^{
AVCaptureDevice *device = [[self videoDeviceInput] device];
NSError *error = nil;
if ([device lockForConfiguration:&error]) {
if ([device isFocusPointOfInterestSupported] && [device isFocusModeSupported:focusMode]) {
[device setFocusMode:focusMode];
[device setFocusPointOfInterest:point];
}
if ([device isExposurePointOfInterestSupported] && [device isExposureModeSupported:exposureMode]) {
[device setExposureMode:exposureMode];
[device setExposurePointOfInterest:point];
}
[device setSubjectAreaChangeMonitoringEnabled:monitorSubjectAreaChange];
[device unlockForConfiguration];
}
else {
NSLog(@"%@", error);
}
});
}
+ (void)setFlashMode:(AVCaptureFlashMode)flashMode forDevice:(AVCaptureDevice *)device {
if ([device hasFlash] && [device isFlashModeSupported:flashMode]) {
NSError *error = nil;
if ([device lockForConfiguration:&error]) {
[device setFlashMode:flashMode];
[device unlockForConfiguration];
}
else {
NSLog(@"%@", error);
}
}
}
+ (AVCaptureDevice *)deviceWithMediaType:(NSString *)mediaType preferringPosition:(AVCaptureDevicePosition)position {
NSArray *devices = [AVCaptureDevice devicesWithMediaType:mediaType];
AVCaptureDevice *captureDevice = [devices firstObject];
for (AVCaptureDevice *device in devices) {
if ([device position] == position) {
captureDevice = device;
break;
}
}
return captureDevice;
}
#pragma mark UI
- (void)runStillImageCaptureAnimation {
dispatch_async(dispatch_get_main_queue(), ^{
[[[self previewView] layer] setOpacity:0.0];
[UIView animateWithDuration:.25 animations: ^{
[[[self previewView] layer] setOpacity:1.0];
}];
});
}
- (void)checkDeviceAuthorizationStatus {
NSString *mediaType = AVMediaTypeVideo;
[AVCaptureDevice requestAccessForMediaType:mediaType completionHandler: ^(BOOL granted) {
if (granted) {
//Granted access to mediaType
[self setDeviceAuthorized:YES];
}
else {
//Not granted access to mediaType
dispatch_async(dispatch_get_main_queue(), ^{
[[[UIAlertView alloc] initWithTitle:@"AVCam!"
message:@"AVCam doesn't have permission to use Camera, please change privacy settings"
delegate:self
cancelButtonTitle:@"OK"
otherButtonTitles:nil] show];
[self setDeviceAuthorized:NO];
});
}
}];
}
- (IBAction)onTapThumb:(id)sender {
UIButton *btnThumb = (UIButton *)sender;
self.imgSmallThumbNail.hidden = btnThumb.selected;
self.imgBigThumbNail.hidden = !btnThumb.selected;
btnThumb.selected = !btnThumb.selected;
}
- (IBAction)onTapCameraFlash:(id)sender {
UIButton *btnCameraFlash = (UIButton *)sender;
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if (btnCameraFlash.tag == 0) {
[btnCameraFlash setImage:[UIImage imageNamed:@"icon_flash.png"] forState:UIControlStateNormal];
btnCameraFlash.tag = 1;
if ([device hasTorch] && [device hasFlash]) {
[device lockForConfiguration:nil];
[device setTorchMode:!device.torchActive];
[device setFlashMode:AVCaptureFlashModeOn];
[device unlockForConfiguration];
}
return;
}
else if (btnCameraFlash.tag == 1) {
[btnCameraFlash setImage:[UIImage imageNamed:@"icon_flash_auto.png"] forState:UIControlStateNormal];
btnCameraFlash.tag = 0;
if ([device hasTorch] && [device hasFlash]) {
[device lockForConfiguration:nil];
[device setTorchMode:!device.torchActive];
[device setFlashMode:AVCaptureFlashModeOff];
[device unlockForConfiguration];
}
return;
}
}
- (IBAction)onBack:(id)sender {
_callback(nil, @"3", @"Camera closed before takin a picture.");
}
- (void)addPinchGesture {
twoFingerPinch = [[UIPinchGestureRecognizer alloc]
initWithTarget:self
action:@selector(twoFingerPinch:)];
[self.view addGestureRecognizer:twoFingerPinch];
}
- (void)addOpacitySlider {
CGAffineTransform trans = CGAffineTransformMakeRotation(M_PI_2 * (-1));
self.opacitySlider.transform = trans;
[self.opacitySlider addTarget:self action:@selector(onChangeOpacitySlider) forControlEvents:UIControlEventValueChanged];
self.opacitySlider.value = 1;
}
- (void)initialize {
fDist = self.btnThumb.center.x - self.cameraButton.center.x;
capturedImage = [[UIImage alloc] init];
capturedImageData = [[NSData alloc] init];
[self addOpacitySlider];
[self addPinchGesture];
self.capturedImageView.hidden = YES;
self.saveBgPanel.hidden = YES;
self.btnBigDeletePicture.hidden = self.btnDeletePicture.hidden = YES;
self.btnBigSaveImage.hidden = self.btnSaveImage.hidden = YES;
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGFloat screenScale = [[UIScreen mainScreen] scale];
CGSize screenSize = CGSizeMake(screenBounds.size.width * screenScale, screenBounds.size.height * screenScale);
NSInteger max = (screenSize.width > screenSize.height) ? screenSize.width : screenSize.height;
UIImage *newImage = [self imageWithImage:[UIImage imageWithData:self.params.bgImageData] scaledToMaxWidth:max maxHeight:max];
self.imgBigThumbNail.image = newImage;
self.imgSmallThumbNail.image = [UIImage imageWithData:self.params.bgImageData];
self.btnThumb.hidden = !params.bMiniature;
self.btnFlash.hidden = !params.bSwitchFlash;
self.cameraButton.hidden = !params.bSwitchCamera;
self.opacitySlider.hidden = !params.bOpacity;
if (!params.bgImageData) {
self.imgBigThumbNail.hidden = YES;
self.imgSmallThumbNail.hidden = YES;
}
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
if (params.nDefaultFlash == 1) {
[self.btnFlash setImage:[UIImage imageNamed:@"icon_flash.png"] forState:UIControlStateNormal];
self.btnFlash.tag = 1;
if ([device hasTorch] && [device hasFlash]) {
[device lockForConfiguration:nil];
[device setTorchMode:YES];
[device setFlashMode:AVCaptureFlashModeOn];
[device unlockForConfiguration];
}
}
else {
[self.btnFlash setImage:[UIImage imageNamed:@"icon_flash_auto.png"] forState:UIControlStateNormal];
self.btnFlash.tag = 0;
if ([device hasTorch] && [device hasFlash]) {
[device lockForConfiguration:nil];
[device setTorchMode:NO];
[device setFlashMode:AVCaptureFlashModeOn];
[device unlockForConfiguration];
}
}
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation {
if (params.bgImageData1) {
isRotated = !isRotated;
CGRect screenBounds = [[UIScreen mainScreen] bounds];
CGFloat screenScale = [[UIScreen mainScreen] scale];
CGSize screenSize = CGSizeMake(screenBounds.size.width * screenScale, screenBounds.size.height * screenScale);
NSInteger max = (screenSize.width > screenSize.height) ? screenSize.width : screenSize.height;
if (isRotated) {
UIImage *newImage = [self imageWithImage:[UIImage imageWithData:self.params.bgImageData1] scaledToMaxWidth:max maxHeight:max];
self.imgBigThumbNail.image = newImage;
self.imgSmallThumbNail.image = [UIImage imageWithData:params.bgImageData1];
}
else {
UIImage *newImage = [self imageWithImage:[UIImage imageWithData:self.params.bgImageData] scaledToMaxWidth:max maxHeight:max];
self.imgBigThumbNail.image = newImage;
self.imgSmallThumbNail.image = [UIImage imageWithData:params.bgImageData];
}
}
}
- (void)takePicture {
[self setLockInterfaceRotation:YES];
self.capturedImageView.image = capturedImage;
self.capturedImageView.hidden = NO;
self.saveBgPanel.hidden = NO;
self.btnBigDeletePicture.hidden = self.btnDeletePicture.hidden = NO;
self.btnBigSaveImage.hidden = self.btnSaveImage.hidden = NO;
self.stillButton.hidden = self.btnFlash.hidden = self.cameraButton.hidden = YES;
frameBtnThumb = self.btnThumb.frame;
self.btnThumb.frame = self.btnFlash.frame;
self.imgSmallThumbNail.frame = CGRectOffset(self.imgSmallThumbNail.frame, 0, -self.saveBgPanel.frame.size.height);
}
- (IBAction)onDeletePicture:(id)sender {
[self setLockInterfaceRotation:NO];
capturedImage = nil;
self.capturedImageView.image = nil;
self.capturedImageView.hidden = YES;
self.btnBigDeletePicture.hidden = self.btnDeletePicture.hidden = YES;
self.btnBigSaveImage.hidden = self.btnSaveImage.hidden = YES;
self.saveBgPanel.hidden = YES;
self.btnThumb.frame = frameBtnThumb;
self.stillButton.hidden = self.btnFlash.hidden = NO;
//control camera button
self.cameraButton.hidden = !params.bSwitchCamera;
[self.cameraButton setEnabled:params.bSwitchCamera];
//control flash button
if (params.bSwitchFlash) {
AVCaptureDevice *currentVideoDevice = [[self videoDeviceInput] device];
AVCaptureDevicePosition currentPosition = [currentVideoDevice position];
AVCaptureDevice *videoDevice = [AVCamViewController deviceWithMediaType:AVMediaTypeVideo preferringPosition:currentPosition];
switch (currentPosition) {
case AVCaptureDevicePositionUnspecified:
case AVCaptureDevicePositionBack:
{
if (self.btnFlash.tag == 0) {
[self.btnFlash setImage:[UIImage imageNamed:@"icon_flash_auto.png"] forState:UIControlStateNormal];
if ([videoDevice hasTorch] && [videoDevice hasFlash]) {
[videoDevice lockForConfiguration:nil];
[videoDevice setTorchMode:videoDevice.torchActive];
[videoDevice setFlashMode:AVCaptureFlashModeOff];
[videoDevice unlockForConfiguration];
}
}
else if (self.btnFlash.tag == 1) {
[self.btnFlash setImage:[UIImage imageNamed:@"icon_flash.png"] forState:UIControlStateNormal];
if ([videoDevice hasTorch] && [videoDevice hasFlash]) {
[videoDevice lockForConfiguration:nil];
[videoDevice setTorchMode:videoDevice.torchActive];
[videoDevice setFlashMode:AVCaptureFlashModeOn];
[videoDevice unlockForConfiguration];
}
}
break;
}
case AVCaptureDevicePositionFront:
break;
}
if (![videoDevice hasTorch] || ![videoDevice hasFlash]) {
self.btnFlash.hidden = YES;
}
else {
self.btnFlash.hidden = !params.bSwitchFlash;
[self.btnFlash setEnabled:params.bSwitchFlash];
}
}
else {
self.btnFlash.hidden = YES;
}
self.imgSmallThumbNail.frame = CGRectOffset(self.imgSmallThumbNail.frame, 0, self.saveBgPanel.frame.size.height);
}
- (IBAction)onSaveImage:(id)sender {
UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
activityIndicator.center = self.view.center;
[self.view addSubview:activityIndicator];
[activityIndicator startAnimating];
if (params.bSaveInGallery) {
[[[ALAssetsLibrary alloc] init] writeImageToSavedPhotosAlbum:[capturedImage CGImage] orientation:(ALAssetOrientation)[capturedImage imageOrientation] completionBlock:nil];
}
[self.view setUserInteractionEnabled:NO];
_callback([UIImage imageWithData:capturedImageData], nil, nil);
}
- (void)onChangeOpacitySlider {
self.imgSmallThumbNail.alpha = self.opacitySlider.value;
self.imgBigThumbNail.alpha = self.opacitySlider.value;
}
- (void)twoFingerPinch:(UIPinchGestureRecognizer *)recognizer {
if (self.lockInterfaceRotation) {
return;
}
AVCaptureDevice *device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
CGFloat fMaxZoomFactor = device.activeFormat.videoMaxZoomFactor;
if (fMaxZoomFactor > 5)
fMaxZoomFactor = 5;
CGFloat fNewScale = recognizer.scale * device.videoZoomFactor;
if (fNewScale > 1.0f && fNewScale < fMaxZoomFactor) {
[device lockForConfiguration:nil];
[device rampToVideoZoomFactor:fNewScale withRate:3];
[device unlockForConfiguration];
}
}
- (UIInterfaceOrientation)preferredInterfaceOrientationForPresentation {
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)orientation {
return orientation == UIDeviceOrientationPortrait;
}
#pragma mark -Scale image
- (UIImage *)imageWithImage:(UIImage *)image scaledToMaxWidth:(CGFloat)width maxHeight:(CGFloat)height {
CGFloat oldWidth = image.size.width;
CGFloat oldHeight = image.size.height;
CGFloat scaleFactor = (oldWidth > oldHeight) ? width / oldWidth : height / oldHeight;
CGFloat newHeight = oldHeight * scaleFactor;
CGFloat newWidth = oldWidth * scaleFactor;
CGSize newSize = CGSizeMake(newWidth, newHeight);
if ([[UIScreen mainScreen] respondsToSelector:@selector(scale)]) {
UIGraphicsBeginImageContextWithOptions(newSize, NO, [[UIScreen mainScreen] scale]);
}
else {
UIGraphicsBeginImageContext(newSize);
}
[image drawInRect:CGRectMake(0, 0, newSize.width, newSize.height)];
UIImage *newImage = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return newImage;
}
@end

View File

@@ -0,0 +1,181 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.iPad.XIB" version="3.0" toolsVersion="6254" systemVersion="14A389" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AVCamViewController">
<connections>
<outlet property="btnBigDeletePicture" destination="IqJ-oc-995" id="T1H-10-ESB"/>
<outlet property="btnBigSaveImage" destination="EFe-fE-P8a" id="P0Z-Xm-thh"/>
<outlet property="btnDeletePicture" destination="S1N-v6-cZw" id="1TW-yQ-2Ul"/>
<outlet property="btnFlash" destination="KMs-9J-eHV" id="pdI-VZ-buj"/>
<outlet property="btnSaveImage" destination="JJc-KF-LjK" id="att-go-Xq7"/>
<outlet property="btnThumb" destination="NW3-H0-02v" id="9az-rc-6zl"/>
<outlet property="cameraButton" destination="br3-lo-te3" id="9er-L2-Q49"/>
<outlet property="capturedImageView" destination="aNd-OH-3PR" id="FB6-Dl-sSA"/>
<outlet property="imgBigThumbNail" destination="hb3-4z-EqI" id="bXK-S1-JY5"/>
<outlet property="imgSmallThumbNail" destination="7Tf-kP-S1C" id="yk1-9p-mnP"/>
<outlet property="opacitySlider" destination="D3e-gE-Un5" id="Vl5-37-0Gj"/>
<outlet property="previewView" destination="vHe-RW-WQc" id="WqV-SM-Xgc"/>
<outlet property="saveBgPanel" destination="xaA-dP-8ce" id="FGL-y1-FJb"/>
<outlet property="stillButton" destination="cxS-Qn-d9p" id="Joi-8C-0gM"/>
<outlet property="topBgPanel" destination="kso-6k-eTa" id="sZi-gu-mzH"/>
<outlet property="view" destination="iN0-l3-epB" id="88I-Oa-O0G"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" id="vHe-RW-WQc" customClass="AVCamPreviewView">
<rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" id="aNd-OH-3PR">
<rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sample.png" id="hb3-4z-EqI">
<rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<button opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="cxS-Qn-d9p">
<rect key="frame" x="344" y="941" width="80" height="76"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<state key="normal" image="icon_capture.png"/>
<state key="selected" image="icon_capture_pressed.png"/>
<state key="highlighted" image="icon_capture_pressed.png"/>
<connections>
<action selector="snapStillImage:" destination="-1" eventType="touchUpInside" id="LsD-dw-Fw0"/>
</connections>
</button>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sample.png" id="7Tf-kP-S1C">
<rect key="frame" x="20" y="934" width="90" height="90"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<view alpha="0.5" contentMode="scaleToFill" id="xaA-dP-8ce">
<rect key="frame" x="0.0" y="934" width="768" height="90"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="IqJ-oc-995">
<rect key="frame" x="0.0" y="0.0" width="376" height="90"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<state key="normal">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onDeletePicture:" destination="-1" eventType="touchUpInside" id="XkX-0N-K4g"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="EFe-fE-P8a">
<rect key="frame" x="384" y="0.0" width="384" height="90"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" heightSizable="YES"/>
<state key="normal">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onSaveImage:" destination="-1" eventType="touchUpInside" id="pMu-f6-poC"/>
</connections>
</button>
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="S1N-v6-cZw">
<rect key="frame" x="147" y="20" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<state key="normal" image="icon_delete.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onDeletePicture:" destination="-1" eventType="touchUpInside" id="7ty-gh-NHC"/>
</connections>
</button>
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="JJc-KF-LjK">
<rect key="frame" x="566" y="20" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
<state key="normal" image="icon_submit.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onSaveImage:" destination="-1" eventType="touchUpInside" id="mry-0F-fqI"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</view>
<view alpha="0.5" contentMode="scaleToFill" id="kso-6k-eTa">
<rect key="frame" x="0.0" y="0.0" width="768" height="90"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="7Wz-zM-ysY">
<rect key="frame" x="20" y="20" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" image="icon_back.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onBack:" destination="-1" eventType="touchUpInside" id="zpX-8h-Pcs"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="br3-lo-te3">
<rect key="frame" x="480" y="20" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<state key="normal" image="icon_flip.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="changeCamera:" destination="-1" eventType="touchUpInside" id="2JV-vM-qU3"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="NW3-H0-02v">
<rect key="frame" x="597" y="25" width="40" height="40"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<state key="normal" image="icon_min.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="selected" image="icon_max.png"/>
<connections>
<action selector="onTapThumb:" destination="-1" eventType="touchUpInside" id="kJr-cv-LaQ"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="KMs-9J-eHV">
<rect key="frame" x="690" y="20" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<state key="normal" image="icon_flash_auto.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onTapCameraFlash:" destination="-1" eventType="touchUpInside" id="hq4-uE-TO5"/>
</connections>
</button>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" id="D3e-gE-Un5">
<rect key="frame" x="479" y="497" width="512" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</slider>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<gestureRecognizers/>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
</view>
</objects>
<resources>
<image name="icon_back.png" width="60" height="60"/>
<image name="icon_capture.png" width="128" height="128"/>
<image name="icon_capture_pressed.png" width="128" height="128"/>
<image name="icon_delete.png" width="60" height="60"/>
<image name="icon_flash_auto.png" width="60" height="60"/>
<image name="icon_flip.png" width="60" height="60"/>
<image name="icon_max.png" width="60" height="60"/>
<image name="icon_min.png" width="60" height="60"/>
<image name="icon_submit.png" width="60" height="60"/>
<image name="sample.png" width="483" height="263"/>
</resources>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination"/>
</simulatedMetricsContainer>
</document>

View File

@@ -0,0 +1,187 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="6254" systemVersion="14A389" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none">
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="6247"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="AVCamViewController">
<connections>
<outlet property="btnBack" destination="JSx-s3-uHS" id="gtj-U7-7eS"/>
<outlet property="btnBigDeletePicture" destination="9ml-dK-r4P" id="v1z-D4-2aN"/>
<outlet property="btnBigSaveImage" destination="P2D-hm-Kcg" id="81p-6x-fIz"/>
<outlet property="btnDeletePicture" destination="J6B-b3-9jL" id="Odf-du-kBy"/>
<outlet property="btnFlash" destination="BRk-mk-jo0" id="JMg-ha-GzP"/>
<outlet property="btnSaveImage" destination="gCj-9O-Lhz" id="Tg2-gh-nlr"/>
<outlet property="btnThumb" destination="OWo-yv-W9g" id="0S3-x9-HAa"/>
<outlet property="cameraButton" destination="jnK-sC-Roz" id="yhA-LL-bdK"/>
<outlet property="capturedImageView" destination="mfI-LM-QPE" id="aXs-aV-ggH"/>
<outlet property="imgBigThumbNail" destination="GAn-hK-ROm" id="dc7-tm-wNM"/>
<outlet property="imgSmallThumbNail" destination="MJV-kJ-EX5" id="HgP-9H-c4t"/>
<outlet property="opacitySlider" destination="gf9-Ju-OcL" id="jn8-NJ-iVO"/>
<outlet property="previewView" destination="wgh-5M-pgU" id="03T-sp-Ynl"/>
<outlet property="saveBgPanel" destination="AJN-IB-tiU" id="epU-gC-TWb"/>
<outlet property="stillButton" destination="usa-GD-lMO" id="hXu-yT-Tuj"/>
<outlet property="topBgPanel" destination="qKn-KP-yGM" id="bL1-dO-Na2"/>
<outlet property="view" destination="iN0-l3-epB" id="98Z-ee-Lmg"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view contentMode="scaleToFill" id="iN0-l3-epB">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<view contentMode="scaleToFill" id="wgh-5M-pgU" customClass="AVCamPreviewView">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" id="mfI-LM-QPE">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<imageView userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sample.png" id="GAn-hK-ROm">
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
</imageView>
<button opaque="NO" clearsContextBeforeDrawing="NO" contentMode="scaleToFill" enabled="NO" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="usa-GD-lMO">
<rect key="frame" x="135" y="463" width="50" height="50"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxX="YES" flexibleMinY="YES"/>
<state key="normal" image="icon_capture.png"/>
<state key="selected" image="icon_capture_pressed.png"/>
<state key="highlighted" image="icon_capture_pressed.png"/>
<connections>
<action selector="snapStillImage:" destination="-1" eventType="touchUpInside" id="l6I-0I-IBm"/>
</connections>
</button>
<imageView hidden="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" image="sample.png" id="MJV-kJ-EX5">
<rect key="frame" x="10" y="508" width="60" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
</imageView>
<view alpha="0.5" contentMode="scaleToFill" id="AJN-IB-tiU">
<rect key="frame" x="0.0" y="488" width="320" height="80"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="9ml-dK-r4P">
<rect key="frame" x="0.0" y="0.0" width="160" height="60"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMaxX="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<state key="normal">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onDeletePicture:" destination="-1" eventType="touchUpInside" id="MyT-W6-Zcm"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" id="P2D-hm-Kcg">
<rect key="frame" x="160" y="0.0" width="160" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/>
<state key="normal">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onSaveImage:" destination="-1" eventType="touchUpInside" id="HXF-We-dau"/>
</connections>
</button>
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="gCj-9O-Lhz">
<rect key="frame" x="245" y="5" width="30" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/>
<state key="normal" image="icon_submit.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onSaveImage:" destination="-1" eventType="touchUpInside" id="hLE-rb-Fpv"/>
</connections>
</button>
<button opaque="NO" userInteractionEnabled="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="J6B-b3-9jL">
<rect key="frame" x="45" y="5" width="30" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/>
<state key="normal" image="icon_delete.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onDeletePicture:" destination="-1" eventType="touchUpInside" id="vby-qq-Okp"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</view>
<view alpha="0.5" contentMode="scaleToFill" id="qKn-KP-yGM">
<rect key="frame" x="0.0" y="0.0" width="320" height="60"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMaxY="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="OWo-yv-W9g">
<rect key="frame" x="234" y="17" width="25" height="25"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<state key="normal" image="icon_min.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<state key="selected" image="icon_max.png"/>
<connections>
<action selector="onTapThumb:" destination="-1" eventType="touchUpInside" id="zSf-cq-fIV"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="jnK-sC-Roz">
<rect key="frame" x="230" y="15" width="30" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<state key="normal" image="icon_flip.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="changeCamera:" destination="-1" eventType="touchUpInside" id="UhB-S7-CvX"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
</view>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="JSx-s3-uHS">
<rect key="frame" x="10" y="15" width="30" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<state key="normal" image="icon_back.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onBack:" destination="-1" eventType="touchUpInside" id="dpX-Bq-HAw"/>
</connections>
</button>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" lineBreakMode="middleTruncation" id="BRk-mk-jo0">
<rect key="frame" x="280" y="15" width="30" height="30"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMaxY="YES"/>
<state key="normal" image="icon_flash_auto.png">
<color key="titleShadowColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
</state>
<connections>
<action selector="onTapCameraFlash:" destination="-1" eventType="touchUpInside" id="mKZ-w5-NhW"/>
</connections>
</button>
<slider opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" value="0.5" minValue="0.0" maxValue="1" id="gf9-Ju-OcL">
<rect key="frame" x="199" y="269" width="200" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES" flexibleMaxY="YES"/>
</slider>
</subviews>
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="calibratedWhite"/>
<gestureRecognizers/>
</view>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
<nil key="simulatedStatusBarMetrics"/>
</view>
</objects>
<resources>
<image name="icon_back.png" width="60" height="60"/>
<image name="icon_capture.png" width="128" height="128"/>
<image name="icon_capture_pressed.png" width="128" height="128"/>
<image name="icon_delete.png" width="60" height="60"/>
<image name="icon_flash_auto.png" width="60" height="60"/>
<image name="icon_flip.png" width="60" height="60"/>
<image name="icon_max.png" width="60" height="60"/>
<image name="icon_min.png" width="60" height="60"/>
<image name="icon_submit.png" width="60" height="60"/>
<image name="sample.png" width="483" height="263"/>
</resources>
<simulatedMetricsContainer key="defaultSimulatedMetrics">
<simulatedStatusBarMetrics key="statusBar"/>
<simulatedOrientationMetrics key="orientation"/>
<simulatedScreenMetrics key="destination" type="retina4"/>
</simulatedMetricsContainer>
</document>

View File

@@ -0,0 +1,33 @@
#import <Foundation/Foundation.h>
#import <Cordova/CDV.h>
@interface CameraParameter : NSObject
{
}
@property(nonatomic, retain) NSData *bgImageData;
@property(nonatomic, retain) NSData *bgImageData1;
@property(nonatomic, assign) BOOL bMiniature;
@property(nonatomic, assign) BOOL bSaveInGallery;
@property(nonatomic, assign) int nCameraFlashMode;
@property(nonatomic, retain) NSString* strCameraBGColor;
@property(nonatomic, retain) NSString* strCameraPressedBG;
@property(nonatomic, assign) CGFloat fQuality;
@property(nonatomic, assign) BOOL bOpacity;
@property(nonatomic, assign) int nDefaultFlash;
@property(nonatomic, assign) BOOL bSwitchFlash;
@property(nonatomic, assign) int targetWidth;
@property(nonatomic, assign) int targetHeight;
@property(nonatomic, assign) int nDefaultCamera;
@property(nonatomic, assign) BOOL bSwitchCamera;
-(id) initWithCommand :(CDVInvokedUrlCommand *)command;
@end

View File

@@ -0,0 +1,66 @@
#import "CameraParameter.h"
@implementation CameraParameter
{
}
@synthesize bgImageData;
@synthesize bgImageData1;
@synthesize bMiniature;
@synthesize bSaveInGallery;
@synthesize nCameraFlashMode;
@synthesize strCameraBGColor;
@synthesize strCameraPressedBG;
@synthesize fQuality;
@synthesize targetWidth;
@synthesize targetHeight;
@synthesize bOpacity;
@synthesize nDefaultFlash;
@synthesize bSwitchFlash;
@synthesize nDefaultCamera;
@synthesize bSwitchCamera;
- (id)initWithCommand:(CDVInvokedUrlCommand *)command {
// [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
// mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
if (self = [super init]) {
// NSString *strData = [command argumentAtIndex:0];
// if (strData) {
// bgImageData = [[NSData alloc] initWithBase64EncodedString:strData options:0];
// }
// else {
bgImageData = nil;
// }
// NSString *strData1 = [command argumentAtIndex:1];
// if (strData1) {
// bgImageData1 = [[NSData alloc] initWithBase64EncodedString:strData1 options:0];
// }
// else {
bgImageData1 = nil;
// }
bMiniature = false; //[[command argumentAtIndex:2] boolValue];
bSaveInGallery = [[command argumentAtIndex:9] boolValue];
strCameraBGColor = @"#e26760"; //[command argumentAtIndex:4];
strCameraPressedBG = @"#dc453d"; //[command argumentAtIndex:5];
fQuality = [[command argumentAtIndex:0] intValue];
targetWidth = [[command argumentAtIndex:3] intValue];
targetHeight = [[command argumentAtIndex:4] intValue];
bOpacity = false; //[[command argumentAtIndex:7] boolValue];
nDefaultFlash = 2; //[[command argumentAtIndex:8] intValue];
bSwitchFlash = true; //[[command argumentAtIndex:9] boolValue];
nDefaultCamera = 0; //[[command argumentAtIndex:10] intValue];
bSwitchCamera = true; //[[command argumentAtIndex:11] boolValue];
}
return self;
}
@end

93
src/ios/classes/CustomCamera.h Executable file
View File

@@ -0,0 +1,93 @@
#import <Cordova/CDV.h>
#import <CoreLocation/CoreLocation.h>
#import <CoreLocation/CLLocationManager.h>
enum CDVDestinationType {
DestinationTypeDataUrl = 0,
DestinationTypeFileUri,
DestinationTypeNativeUri
};
typedef NSUInteger CDVDestinationType;
enum CDVEncodingType {
EncodingTypeJPEG = 0,
EncodingTypePNG
};
typedef NSUInteger CDVEncodingType;
enum CDVMediaType {
MediaTypePicture = 0,
MediaTypeVideo,
MediaTypeAll
};
typedef NSUInteger CDVMediaType;
@interface CDVPictureOptions : NSObject
@property (strong) NSNumber* quality;
@property (assign) CDVDestinationType destinationType;
@property (assign) UIImagePickerControllerSourceType sourceType;
@property (assign) CGSize targetSize;
@property (assign) CDVEncodingType encodingType;
@property (assign) CDVMediaType mediaType;
@property (assign) BOOL allowsEditing;
@property (assign) BOOL correctOrientation;
@property (assign) BOOL saveToPhotoAlbum;
@property (strong) NSDictionary* popoverOptions;
@property (assign) UIImagePickerControllerCameraDevice cameraDirection;
@property (assign) BOOL popoverSupported;
@property (assign) BOOL usesGeolocation;
@property (assign) BOOL cropToSize;
+ (instancetype) createFromTakePictureArguments:(CDVInvokedUrlCommand*)command;
@end
@interface CDVCameraPicker : UIImagePickerController
@property (strong) CDVPictureOptions* pictureOptions;
@property (copy) NSString* callbackId;
@property (copy) NSString* postUrl;
@property (strong) UIPopoverController* pickerPopoverController;
@property (assign) BOOL cropToSize;
@property (strong) UIView* webView;
+ (instancetype) createFromPictureOptions:(CDVPictureOptions*)options;
@end
@interface CustomCamera : CDVPlugin<UIImagePickerControllerDelegate, UINavigationControllerDelegate>
{
CDVInvokedUrlCommand *lastCommand;
int nSourceType;
int nDestType;
NSData *bgImageData;
NSData *bgImageData1;
BOOL miniature;
BOOL saveInGallery;
int nCameraFlashMode;
NSString* clrCameraBG;
NSString* clrCameraPressedBG;
CGFloat quality;
BOOL opacity;
int defaultFlash;
BOOL switchFlash;
int defaultCamera;
BOOL switchCamera;
NSString *filename;
}
@property (strong) NSData* data;
@property (strong) NSMutableDictionary *metadata;
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong) CDVCameraPicker* pickerController;
- (void)startCamera:(CDVInvokedUrlCommand*)command;
- (void)takePicture:(CDVInvokedUrlCommand*)command;
- (void)showCameraPicker:(NSString*)callbackId withOptions:(CDVPictureOptions *) pictureOptions;
@end

584
src/ios/classes/CustomCamera.m Executable file
View File

@@ -0,0 +1,584 @@
#import "CustomCamera.h"
#import "AVCamViewController.h"
#import "CameraParameter.h"
#import <MobileCoreServices/UTCoreTypes.h>
#import <AssetsLibrary/ALAssetRepresentation.h>
#import <AssetsLibrary/AssetsLibrary.h>
#import "UIImage+CropScaleOrientation.h"
#import <objc/message.h>
#import <AVFoundation/AVFoundation.h>
#ifndef __CORDOVA_4_0_0
#import <Cordova/NSData+Base64.h>
#endif
#define CDV_PHOTO_PREFIX @"cdv_photo_"
static NSSet* org_apache_cordova_validArrowDirections;
static NSString* toBase64(NSData* data) {
SEL s1 = NSSelectorFromString(@"cdv_base64EncodedString");
SEL s2 = NSSelectorFromString(@"base64EncodedString");
SEL s3 = NSSelectorFromString(@"base64EncodedStringWithOptions:");
if ([data respondsToSelector:s1]) {
NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s1];
return func(data, s1);
} else if ([data respondsToSelector:s2]) {
NSString* (*func)(id, SEL) = (void *)[data methodForSelector:s2];
return func(data, s2);
} else if ([data respondsToSelector:s3]) {
NSString* (*func)(id, SEL, NSUInteger) = (void *)[data methodForSelector:s3];
return func(data, s3, 0);
} else {
return nil;
}
}
@implementation CDVPictureOptions
+ (instancetype) createFromTakePictureArguments:(CDVInvokedUrlCommand*)command
{
CDVPictureOptions* pictureOptions = [[CDVPictureOptions alloc] init];
pictureOptions.quality = [command argumentAtIndex:0 withDefault:@(100)];
pictureOptions.destinationType = [[command argumentAtIndex:1 withDefault:@(DestinationTypeFileUri)] unsignedIntegerValue];
pictureOptions.sourceType = [[command argumentAtIndex:2 withDefault:@(UIImagePickerControllerSourceTypeCamera)] unsignedIntegerValue];
NSNumber* targetWidth = [command argumentAtIndex:3 withDefault:nil];
NSNumber* targetHeight = [command argumentAtIndex:4 withDefault:nil];
pictureOptions.targetSize = CGSizeMake(0, 0);
if ((targetWidth != nil) && (targetHeight != nil)) {
pictureOptions.targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]);
}
pictureOptions.encodingType = [[command argumentAtIndex:5 withDefault:@(EncodingTypeJPEG)] unsignedIntegerValue];
pictureOptions.mediaType = [[command argumentAtIndex:6 withDefault:@(MediaTypePicture)] unsignedIntegerValue];
pictureOptions.allowsEditing = [[command argumentAtIndex:7 withDefault:@(NO)] boolValue];
pictureOptions.correctOrientation = [[command argumentAtIndex:8 withDefault:@(NO)] boolValue];
pictureOptions.saveToPhotoAlbum = [[command argumentAtIndex:9 withDefault:@(NO)] boolValue];
pictureOptions.popoverOptions = [command argumentAtIndex:10 withDefault:nil];
pictureOptions.cameraDirection = [[command argumentAtIndex:11 withDefault:@(UIImagePickerControllerCameraDeviceRear)] unsignedIntegerValue];
pictureOptions.popoverSupported = NO;
pictureOptions.usesGeolocation = NO;
return pictureOptions;
}
@end
@implementation CDVCameraPicker
- (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];
}
+ (instancetype) createFromPictureOptions:(CDVPictureOptions*)pictureOptions;
{
CDVCameraPicker* cameraPicker = [[CDVCameraPicker alloc] init];
cameraPicker.pictureOptions = pictureOptions;
cameraPicker.sourceType = pictureOptions.sourceType;
cameraPicker.allowsEditing = pictureOptions.allowsEditing;
if (cameraPicker.sourceType == UIImagePickerControllerSourceTypeCamera) {
// We only allow taking pictures (no video) in this API.
cameraPicker.mediaTypes = @[(NSString*)kUTTypeImage];
// We can only set the camera device if we're actually using the camera.
cameraPicker.cameraDevice = pictureOptions.cameraDirection;
} else if (pictureOptions.mediaType == MediaTypeAll) {
cameraPicker.mediaTypes = [UIImagePickerController availableMediaTypesForSourceType:cameraPicker.sourceType];
} else {
NSArray* mediaArray = @[(NSString*)(pictureOptions.mediaType == MediaTypeVideo ? kUTTypeMovie : kUTTypeImage)];
cameraPicker.mediaTypes = mediaArray;
}
return cameraPicker;
}
@end
@interface CustomCamera ()
@property (readwrite, assign) BOOL hasPendingOperation;
@end
@implementation CustomCamera
+ (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;
- (void)takePicture:(CDVInvokedUrlCommand *)command {
self.hasPendingOperation = YES;
CDVPictureOptions* pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command];
if (pictureOptions.sourceType == 1) {
[self startCamera: command];
} else {
[self showCameraPicker:command.callbackId withOptions:pictureOptions];
}
}
- (BOOL)popoverSupported
{
return (NSClassFromString(@"UIPopoverController") != nil) &&
(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
}
- (NSInteger)integerValueForKey:(NSDictionary*)dict key:(NSString*)key defaultValue:(NSInteger)defaultValue
{
NSInteger value = defaultValue;
NSNumber* val = [dict valueForKey:key]; // value is an NSNumber
if (val != nil) {
value = [val integerValue];
}
return value;
}
- (void)displayPopover:(NSDictionary*)options
{
NSInteger x = 0;
NSInteger y = 32;
NSInteger width = 320;
NSInteger height = 480;
UIPopoverArrowDirection arrowDirection = UIPopoverArrowDirectionAny;
if (options) {
x = [self integerValueForKey:options key:@"x" defaultValue:0];
y = [self integerValueForKey:options key:@"y" defaultValue:32];
width = [self integerValueForKey:options key:@"width" defaultValue:320];
height = [self integerValueForKey:options key:@"height" defaultValue:480];
arrowDirection = [self integerValueForKey:options key:@"arrowDir" defaultValue:UIPopoverArrowDirectionAny];
if (![org_apache_cordova_validArrowDirections containsObject:[NSNumber numberWithUnsignedInteger:arrowDirection]]) {
arrowDirection = UIPopoverArrowDirectionAny;
}
}
[[[self pickerController] pickerPopoverController] setDelegate:self];
[[[self pickerController] pickerPopoverController] presentPopoverFromRect:CGRectMake(x, y, width, height)
inView:[self.webView superview]
permittedArrowDirections:arrowDirection
animated:YES];
}
- (void)showCameraPicker:(NSString*)callbackId withOptions:(CDVPictureOptions *) pictureOptions
{
// Perform UI operations on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
CDVCameraPicker* cameraPicker = [CDVCameraPicker createFromPictureOptions:pictureOptions];
self.pickerController = cameraPicker;
cameraPicker.delegate = self;
cameraPicker.callbackId = callbackId;
// we need to capture this state for memory warnings that dealloc this object
cameraPicker.webView = self.webView;
// If a popover is already open, close it; we only want one at a time.
if (([[self pickerController] pickerPopoverController] != nil) && [[[self pickerController] pickerPopoverController] isPopoverVisible]) {
[[[self pickerController] pickerPopoverController] dismissPopoverAnimated:YES];
[[[self pickerController] pickerPopoverController] setDelegate:nil];
[[self pickerController] setPickerPopoverController:nil];
}
if ([self popoverSupported] && (pictureOptions.sourceType != UIImagePickerControllerSourceTypeCamera)) {
if (cameraPicker.pickerPopoverController == nil) {
cameraPicker.pickerPopoverController = [[NSClassFromString(@"UIPopoverController") alloc] initWithContentViewController:cameraPicker];
}
[self displayPopover:pictureOptions.popoverOptions];
self.hasPendingOperation = NO;
} else {
cameraPicker.modalPresentationStyle = UIModalPresentationCurrentContext;
[self.viewController presentViewController:cameraPicker animated:YES completion:^{
self.hasPendingOperation = NO;
}];
}
});
}
- (UIImage*)retrieveImage:(NSDictionary*)info options:(CDVPictureOptions*)options
{
// get the image
UIImage* image = nil;
if (options.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) {
image = [info objectForKey:UIImagePickerControllerEditedImage];
} else {
image = [info objectForKey:UIImagePickerControllerOriginalImage];
}
if (options.correctOrientation) {
image = [image imageCorrectedForCaptureOrientation];
}
UIImage* scaledImage = nil;
if ((options.targetSize.width > 0) && (options.targetSize.height > 0)) {
// if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
if (options.cropToSize) {
scaledImage = [image imageByScalingAndCroppingForSize:options.targetSize];
} else {
scaledImage = [image imageByScalingNotCroppingForSize:options.targetSize];
}
}
return (scaledImage == nil ? image : scaledImage);
}
- (NSURL*) urlTransformer:(NSURL*)url
{
NSURL* urlToTransform = url;
// for backwards compatibility - we check if this property is there
SEL sel = NSSelectorFromString(@"urlTransformer");
if ([self.commandDelegate respondsToSelector:sel]) {
// grab the block from the commandDelegate
NSURL* (^urlTransformer)(NSURL*) = ((id(*)(id, SEL))objc_msgSend)(self.commandDelegate, sel);
// if block is not null, we call it
if (urlTransformer) {
urlToTransform = urlTransformer(url);
}
}
return urlToTransform;
}
- (NSData*)processImage:(UIImage*)image info:(NSDictionary*)info options:(CDVPictureOptions*)options
{
NSData* data = nil;
switch (options.encodingType) {
case EncodingTypePNG:
data = UIImagePNGRepresentation(image);
break;
case EncodingTypeJPEG:
{
if ((options.allowsEditing == NO) && (options.targetSize.width <= 0) && (options.targetSize.height <= 0) && (options.correctOrientation == NO) && (([options.quality integerValue] == 100) || (options.sourceType != UIImagePickerControllerSourceTypeCamera))){
// use image unedited as requested , don't resize
data = UIImageJPEGRepresentation(image, 1.0);
} else {
data = UIImageJPEGRepresentation(image, [options.quality floatValue] / 100.0f);
}
if (options.usesGeolocation) {
NSDictionary* controllerMetadata = [info objectForKey:@"UIImagePickerControllerMediaMetadata"];
if (controllerMetadata) {
self.data = data;
self.metadata = [[NSMutableDictionary alloc] init];
NSMutableDictionary* EXIFDictionary = [[controllerMetadata objectForKey:(NSString*)kCGImagePropertyExifDictionary]mutableCopy];
if (EXIFDictionary) {
[self.metadata setObject:EXIFDictionary forKey:(NSString*)kCGImagePropertyExifDictionary];
}
if (IsAtLeastiOSVersion(@"8.0")) {
[[self locationManager] performSelector:NSSelectorFromString(@"requestWhenInUseAuthorization") withObject:nil afterDelay:0];
}
[[self locationManager] startUpdatingLocation];
}
}
}
break;
default:
break;
};
return data;
}
- (NSString*)tempFilePath:(NSString*)extension
{
NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
NSFileManager* fileMgr = [[NSFileManager alloc] init]; // recommended by Apple (vs [NSFileManager defaultManager]) to be threadsafe
NSString* filePath;
// unique file name
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
NSNumber *timeStampObj = [NSNumber numberWithDouble: timeStamp];
do {
filePath = [NSString stringWithFormat:@"%@/%@%ld.%@", docsPath, CDV_PHOTO_PREFIX, [timeStampObj longValue], extension];
} while ([fileMgr fileExistsAtPath:filePath]);
return filePath;
}
- (void)resultForImage:(CDVPictureOptions*)options info:(NSDictionary*)info completion:(void (^)(CDVPluginResult* res))completion
{
CDVPluginResult* result = nil;
BOOL saveToPhotoAlbum = options.saveToPhotoAlbum;
UIImage* image = nil;
switch (options.destinationType) {
case DestinationTypeNativeUri:
{
NSURL* url = [info objectForKey:UIImagePickerControllerReferenceURL];
saveToPhotoAlbum = NO;
// If, for example, we use sourceType = Camera, URL might be nil because image is stored in memory.
// In this case we must save image to device before obtaining an URI.
if (url == nil) {
image = [self retrieveImage:info options:options];
ALAssetsLibrary* library = [ALAssetsLibrary new];
[library writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)(image.imageOrientation) completionBlock:^(NSURL *assetURL, NSError *error) {
CDVPluginResult* resultToReturn = nil;
if (error) {
resultToReturn = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[error localizedDescription]];
} else {
NSString* nativeUri = [[self urlTransformer:assetURL] absoluteString];
resultToReturn = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri];
}
completion(resultToReturn);
}];
return;
} else {
NSString* nativeUri = [[self urlTransformer:url] absoluteString];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:nativeUri];
}
}
break;
case DestinationTypeFileUri:
{
image = [self retrieveImage:info options:options];
NSData* data = [self processImage:image info:info options:options];
if (data) {
NSString* extension = options.encodingType == EncodingTypePNG? @"png" : @"jpg";
NSString* filePath = [self tempFilePath:extension];
NSError* err = nil;
// 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:[[self urlTransformer:[NSURL fileURLWithPath:filePath]] absoluteString]];
}
}
}
break;
case DestinationTypeDataUrl:
{
image = [self retrieveImage:info options:options];
NSData* data = [self processImage:image info:info options:options];
if (data) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:toBase64(data)];
}
}
break;
default:
break;
};
if (saveToPhotoAlbum && image) {
ALAssetsLibrary* library = [ALAssetsLibrary new];
[library writeImageToSavedPhotosAlbum:image.CGImage orientation:(ALAssetOrientation)(image.imageOrientation) completionBlock:nil];
}
completion(result);
}
- (NSString *) createTmpVideo:(NSString *) moviePath {
NSString* moviePathExtension = [moviePath pathExtension];
NSString* copyMoviePath = [self tempFilePath:moviePathExtension];
NSFileManager* fileMgr = [[NSFileManager alloc] init];
NSError *error;
[fileMgr copyItemAtPath:moviePath toPath:copyMoviePath error:&error];
return [[NSURL fileURLWithPath:copyMoviePath] absoluteString];
}
- (CDVPluginResult*)resultForVideo:(NSDictionary*)info
{
NSString* moviePath = [[info objectForKey:UIImagePickerControllerMediaURL] absoluteString];
// On iOS 13 the movie path becomes inaccessible, create and return a copy
if (IsAtLeastiOSVersion(@"13.0")) {
moviePath = [self createTmpVideo:[[info objectForKey:UIImagePickerControllerMediaURL] path]];
}
return [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:moviePath];
}
- (BOOL)usesGeolocation
{
id useGeo = [self.commandDelegate.settings objectForKey:[@"CameraUsesGeolocation" lowercaseString]];
return [(NSNumber*)useGeo boolValue];
}
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
{
__weak CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
__weak CustomCamera* weakSelf = self;
dispatch_block_t invoke = ^(void) {
__block CDVPluginResult* result = nil;
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
[weakSelf resultForImage:cameraPicker.pictureOptions info:info completion:^(CDVPluginResult* res) {
if (![self usesGeolocation] || picker.sourceType != UIImagePickerControllerSourceTypeCamera) {
[weakSelf.commandDelegate sendPluginResult:res callbackId:cameraPicker.callbackId];
weakSelf.hasPendingOperation = NO;
weakSelf.pickerController = nil;
}
}];
}
else {
result = [weakSelf resultForVideo:info];
[weakSelf.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId];
weakSelf.hasPendingOperation = NO;
weakSelf.pickerController = nil;
}
};
if (cameraPicker.pictureOptions.popoverSupported && (cameraPicker.pickerPopoverController != nil)) {
[cameraPicker.pickerPopoverController dismissPopoverAnimated:YES];
cameraPicker.pickerPopoverController.delegate = nil;
cameraPicker.pickerPopoverController = nil;
invoke();
} else {
[[cameraPicker presentingViewController] dismissViewControllerAnimated:YES completion:invoke];
}
}
// older api calls newer didFinishPickingMediaWithInfo
- (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
{
__weak CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
__weak CustomCamera* weakSelf = self;
dispatch_block_t invoke = ^ (void) {
CDVPluginResult* result;
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera && [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != ALAuthorizationStatusAuthorized) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"has no access to camera"];
} else if (picker.sourceType != UIImagePickerControllerSourceTypeCamera && ! IsAtLeastiOSVersion(@"11.0") && [ALAssetsLibrary authorizationStatus] != ALAuthorizationStatusAuthorized) {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"has no access to assets"];
} else {
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"No Image Selected"];
}
[weakSelf.commandDelegate sendPluginResult:result callbackId:cameraPicker.callbackId];
weakSelf.hasPendingOperation = NO;
weakSelf.pickerController = nil;
};
[[cameraPicker presentingViewController] dismissViewControllerAnimated:YES completion:invoke];
}
- (void)startCamera:(CDVInvokedUrlCommand *)command {
lastCommand = command;
NSString *guid = [[NSUUID new] UUIDString];
NSString *uniqueFileName = [NSString stringWithFormat:@"%@.jpg", guid];
filename = uniqueFileName;
nSourceType = 1;
nDestType = 0;
CameraParameter *param = [[CameraParameter alloc] initWithCommand:lastCommand];
if (nSourceType == 0) {
UIImagePickerController *imagePickerController = [[UIImagePickerController alloc] init];
imagePickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
imagePickerController.delegate = self;
[self.viewController presentViewController:imagePickerController animated:YES completion:nil];
}
else {
if (![UIImagePickerController isCameraDeviceAvailable:UIImagePickerControllerCameraDeviceRear]) {
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"No rear camera detected"];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
else if (![UIImagePickerController isSourceTypeAvailable:UIImagePickerControllerSourceTypeCamera]) {
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Camera is not accessible"];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
else {
AVCamViewController *cameraViewController = [[AVCamViewController alloc] initWithParams:param WithCallback: ^(UIImage *image, NSString *errorCode, NSString *message) {
@autoreleasepool {
if (image) {
if (nDestType == 0) {
CDVPictureOptions* options = [CDVPictureOptions createFromTakePictureArguments:command];
UIImage* scaledImage = nil;
if ((options.targetSize.width > 0) && (options.targetSize.height > 0)) {
// if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
if (options.cropToSize) {
scaledImage = [image imageByScalingAndCroppingForSize:options.targetSize];
} else {
scaledImage = [image imageByScalingNotCroppingForSize:options.targetSize];
}
}
image= (scaledImage == nil ? image : scaledImage);
NSData *imageData = UIImageJPEGRepresentation(image, quality / 100);
NSString *strEncodeData = [imageData base64EncodedStringWithOptions:0];
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsString:strEncodeData];
[self.viewController dismissViewControllerAnimated:YES completion:nil];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
else {
NSString *documentsDirectory = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) objectAtIndex:0];
NSString *imagePath = [documentsDirectory stringByAppendingPathComponent:filename];
NSData *imageData = UIImageJPEGRepresentation(image, quality / 100);
[imageData writeToFile:imagePath atomically:YES];
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsString:[[NSURL fileURLWithPath:imagePath] absoluteString]];
[self.viewController dismissViewControllerAnimated:YES completion:nil];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
}
else {
//error
NSDictionary *error = @{ @"code":errorCode, @"message":message };
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsDictionary:error];
[self.viewController dismissViewControllerAnimated:YES completion:nil];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
}
}];
if (@available(iOS 13.0, *)){
cameraViewController.modalPresentationStyle = UIModalPresentationFullScreen;
}
[self.viewController presentViewController:cameraViewController animated:YES completion:nil];
}
}
}
- (void)deleteFileWithName:(NSString *)fileName {
NSFileManager *manager = [NSFileManager defaultManager];
// Need to check if the to be deleted file exists.
if ([manager fileExistsAtPath:fileName]) {
NSError *error = nil;
// This function also returnsYES if the item was removed successfully or if path was nil.
// Returns NO if an error occurred.
[manager removeItemAtPath:fileName error:&error];
if (error) {
NSLog(@"There is an Error: %@", error);
}
}
else {
NSLog(@"File %@ doesn't exists", fileName);
}
}
@end

BIN
src/ios/image/icon_back.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

BIN
src/ios/image/icon_delete.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
src/ios/image/icon_flash.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
src/ios/image/icon_flash_auto.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.5 KiB

BIN
src/ios/image/icon_flash_off.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
src/ios/image/icon_flip.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

BIN
src/ios/image/icon_max.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
src/ios/image/icon_min.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

BIN
src/ios/image/icon_submit.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

BIN
src/ios/image/sample.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 256 KiB

81
src/osx/CDVCamera.h Normal file
View File

@@ -0,0 +1,81 @@
/*
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 <Quartz/Quartz.h>
#import <AppKit/AppKit.h>
#import <Cordova/CDVPlugin.h>
enum CDVDestinationType {
DestinationTypeDataUrl = 0,
DestinationTypeFileUri,
DestinationTypeNativeUri
};
typedef NSUInteger CDVDestinationType;
enum CDVSourceType {
SourceTypePhotoLibrary = 0,
SourceTypeCamera,
SourceTypePhotoAlbum
};
typedef NSUInteger CDVSourceType;
enum CDVEncodingType {
EncodingTypeJPEG = 0,
EncodingTypePNG
};
typedef NSUInteger CDVEncodingType;
enum CDVMediaType {
MediaTypePicture = 0,
MediaTypeVideo,
MediaTypeAll
};
typedef NSUInteger CDVMediaType;
// ======================================================================= //
@interface CDVPictureOptions : NSObject
@property (strong) NSNumber *quality;
@property (assign) CDVDestinationType destinationType;
@property (assign) CDVSourceType sourceType;
@property (assign) CGSize targetSize;
@property (assign) CDVEncodingType encodingType;
@property (assign) CDVMediaType mediaType;
@property (assign) BOOL allowsEditing;
@property (assign) BOOL correctOrientation;
@property (assign) BOOL saveToPhotoAlbum;
+ (instancetype) createFromTakePictureArguments:(CDVInvokedUrlCommand *)command;
@end
// ======================================================================= //
@interface CDVCamera : CDVPlugin
- (void)takePicture:(CDVInvokedUrlCommand *)command;
- (void)cleanup:(CDVInvokedUrlCommand *)command;
@end

258
src/osx/CDVCamera.m Normal file
View File

@@ -0,0 +1,258 @@
/*
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"
@implementation CDVPictureOptions
+ (instancetype) createFromTakePictureArguments:(CDVInvokedUrlCommand*)command {
CDVPictureOptions *pictureOptions = [[CDVPictureOptions alloc] init];
pictureOptions.quality = [command argumentAtIndex:0 withDefault:@(50)];
pictureOptions.destinationType = [[command argumentAtIndex:1 withDefault:@(DestinationTypeFileUri)] unsignedIntegerValue];
pictureOptions.sourceType = [[command argumentAtIndex:2 withDefault:@(SourceTypeCamera)] unsignedIntegerValue];
NSNumber *targetWidth = [command argumentAtIndex:3 withDefault:nil];
NSNumber *targetHeight = [command argumentAtIndex:4 withDefault:nil];
pictureOptions.targetSize = CGSizeMake(0, 0);
if ((targetWidth != nil) && (targetHeight != nil)) {
pictureOptions.targetSize = CGSizeMake([targetWidth floatValue], [targetHeight floatValue]);
}
pictureOptions.encodingType = [[command argumentAtIndex:5 withDefault:@(EncodingTypeJPEG)] unsignedIntegerValue];
pictureOptions.mediaType = [[command argumentAtIndex:6 withDefault:@(MediaTypePicture)] unsignedIntegerValue];
pictureOptions.allowsEditing = [[command argumentAtIndex:7 withDefault:@(NO)] boolValue];
pictureOptions.correctOrientation = [[command argumentAtIndex:8 withDefault:@(NO)] boolValue];
pictureOptions.saveToPhotoAlbum = [[command argumentAtIndex:9 withDefault:@(NO)] boolValue];
return pictureOptions;
}
@end
// ======================================================================= //
@implementation CDVCamera
/*!
Static array that stores the temporary created files allowing to delete them when calling navigator.camera.cleanup(...)
*/
static NSMutableArray *cleanUpFiles;
+ (void)initialize {
cleanUpFiles = [NSMutableArray array];
}
- (void)takePicture:(CDVInvokedUrlCommand *)command {
CDVPictureOptions *pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command];
if (pictureOptions.sourceType == SourceTypeCamera) {
[self takePictureFromCamera:command withOptions:pictureOptions];
} else {
[self takePictureFromFile:command withOptions:pictureOptions];
}
}
- (void)cleanup:(CDVInvokedUrlCommand*)command {
[self.commandDelegate runInBackground:^{
if (cleanUpFiles.count > 0) {
for (int i=0; i<cleanUpFiles.count; i++) {
NSString *path = [cleanUpFiles objectAtIndex:i];
[[NSFileManager defaultManager] removeItemAtPath:path error:nil];
}
[cleanUpFiles removeAllObjects];
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
}];
}
#pragma mark - Camera
/*!
Takes a picture from the iSight camera using the default OS dialog.
@see https://developer.apple.com/documentation/quartz/ikpicturetaker
*/
- (void)takePictureFromCamera:(CDVInvokedUrlCommand *)command withOptions:(CDVPictureOptions *)pictureOptions {
IKPictureTaker *pictureTaker = [IKPictureTaker pictureTaker];
[pictureTaker setValue:[NSNumber numberWithBool:YES] forKey:IKPictureTakerAllowsVideoCaptureKey];
[pictureTaker setValue:[NSNumber numberWithBool:NO] forKey:IKPictureTakerAllowsFileChoosingKey];
[pictureTaker setValue:[NSNumber numberWithBool:pictureOptions.allowsEditing] forKey:IKPictureTakerShowEffectsKey];
[pictureTaker setValue:[NSNumber numberWithBool:pictureOptions.allowsEditing] forKey:IKPictureTakerAllowsEditingKey];
NSDictionary *contextInfo = @{ @"command": command, @"pictureOptions" : pictureOptions};
[pictureTaker beginPictureTakerSheetForWindow:self.viewController.contentView.window withDelegate:self didEndSelector:@selector(pictureTakerDidEnd:returnCode:contextInfo:) contextInfo:(void *)CFBridgingRetain(contextInfo)];
}
- (void)pictureTakerDidEnd:(IKPictureTaker *)pictureTaker returnCode:(NSInteger)returnCode contextInfo:(void *)contextInfo {
if (returnCode == NSOKButton) {
NSDictionary *contextInfoDictionary = (NSDictionary *)CFBridgingRelease(contextInfo);
CDVInvokedUrlCommand *command = [contextInfoDictionary valueForKey:@"command"];
CDVPictureOptions *pictureOptions = [contextInfoDictionary valueForKey:@"pictureOptions"];
[self returnImage:pictureTaker.outputImage command:command options:pictureOptions];
}
}
#pragma mark - File
/*!
Allows to select an image or video using the system native dialog.
*/
- (void)takePictureFromFile:(CDVInvokedUrlCommand *)command withOptions:(CDVPictureOptions *)pictureOptions {
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
openPanel.canChooseFiles = YES;
openPanel.canChooseDirectories = NO;
openPanel.canCreateDirectories = YES;
openPanel.allowsMultipleSelection = NO;
NSMutableArray *allowedTypes = [NSMutableArray array];
if (pictureOptions.mediaType == MediaTypePicture || pictureOptions.mediaType == MediaTypeAll) {
[allowedTypes addObjectsFromArray:[NSImage imageTypes]];
}
if (pictureOptions.mediaType == MediaTypeVideo || pictureOptions.mediaType == MediaTypeAll) {
[allowedTypes addObjectsFromArray:@[(NSString *)kUTTypeMovie]];
}
[openPanel setAllowedFileTypes:allowedTypes];
[openPanel beginSheetModalForWindow:self.viewController.contentView.window completionHandler:^(NSInteger result) {
if (result == NSOKButton) {
NSURL *fileURL = [openPanel.URLs objectAtIndex:0];
if ([self fileIsImage:fileURL]) {
NSImage *image = [[NSImage alloc] initWithContentsOfFile:fileURL.path];
[self returnImage:image command:command options:pictureOptions];
} else {
if (pictureOptions.destinationType == DestinationTypeDataUrl) {
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"Camera.DestinationType.DATA_URL is only available with image files"];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
} else {
[self returnUri:fileURL.path command:command options:pictureOptions];
}
}
}
}];
}
#pragma mark - Common
/*!
Returns to JavaScript a URI.
Called when Camera.DestinationType.FILE_URI or Camera.DestinationType.NATIVE_URI.
*/
- (void)returnUri:(NSString *)path command:(CDVInvokedUrlCommand *)command options:(CDVPictureOptions *)pictureOptions {
NSString *protocol = (pictureOptions.destinationType == DestinationTypeFileUri) ? @"file://" : @"";
NSString *uri = [NSString stringWithFormat:@"%@%@", protocol, path];
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:uri];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
}
/*!
Returns to JavaScript a base64 encoded image.
Called when Camera.DestinationType.DATA_URL.
*/
- (void)returnImage:(NSImage *)image command:(CDVInvokedUrlCommand *)command options:(CDVPictureOptions *)pictureOptions {
[self.commandDelegate runInBackground:^{
NSData *processedImageData = [self processImage:image options:pictureOptions];
if (pictureOptions.destinationType == DestinationTypeDataUrl) {
CDVPluginResult *result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[processedImageData base64EncodedStringWithOptions:NSDataBase64EncodingEndLineWithLineFeed]];
[self.commandDelegate sendPluginResult:result callbackId:command.callbackId];
} else {
NSString *tempFilePath = [self uniqueImageName:pictureOptions];
[processedImageData writeToFile:tempFilePath atomically:YES];
[cleanUpFiles addObject:tempFilePath];
[self returnUri:tempFilePath command:command options:pictureOptions];
}
}];
}
/*!
Top level method to apply the size and quality required changes to an image.
*/
- (NSData *)processImage:(NSImage *)image options:(CDVPictureOptions *)pictureOptions {
NSImage *sourceImage = image;
if (pictureOptions.targetSize.width > 0 && pictureOptions.targetSize.height > 0) {
sourceImage = [self resizeImage:sourceImage toSize:pictureOptions.targetSize];
}
CGImageRef cgRef = [sourceImage CGImageForProposedRect:NULL context:nil hints:nil];
NSBitmapImageRep *imageRepresentation = [[NSBitmapImageRep alloc] initWithCGImage:cgRef];
NSData *data = (pictureOptions.encodingType == EncodingTypeJPEG)
? [imageRepresentation representationUsingType:NSJPEGFileType properties:@{NSImageCompressionFactor: [NSNumber numberWithFloat:pictureOptions.quality.floatValue/100.f]}]
: [imageRepresentation representationUsingType:NSPNGFileType properties:@{NSImageCompressionFactor: @1.0}];
return data;
}
/*!
Auxiliar method to resize an image.
*/
- (NSImage *)resizeImage:(NSImage *)image toSize:(CGSize)newSize {
CGFloat aspectWidth = newSize.width / image.size.width;
CGFloat aspectHeight = newSize.height / image.size.height;
CGFloat aspectRatio = MIN(aspectWidth, aspectHeight);
CGSize scaledSize = NSMakeSize(image.size.width*aspectRatio, image.size.height*aspectRatio);
NSImage *smallImage = [[NSImage alloc] initWithSize: scaledSize];
[smallImage lockFocus];
[image setSize: scaledSize];
[[NSGraphicsContext currentContext] setImageInterpolation:NSImageInterpolationHigh];
[image drawAtPoint:NSZeroPoint fromRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height) operation:NSCompositeCopy fraction:1.0];
[smallImage unlockFocus];
return smallImage;
}
/*!
Auxiliar method to know if a given file is an image or not.
*/
- (BOOL)fileIsImage:(NSURL *)fileURL {
NSString *type;
BOOL isImage = NO;
if ([fileURL getResourceValue:&type forKey:NSURLTypeIdentifierKey error:nil]) {
isImage = [[NSImage imageTypes] containsObject:type];
}
return isImage;
}
/*!
Auxiliar method that generates an unique filename for an image in the temporary directory.
*/
- (NSString *)uniqueImageName:(CDVPictureOptions *)pictureOptions {
NSString *tempDir = NSTemporaryDirectory();
NSString *guid = [[NSProcessInfo processInfo] globallyUniqueString] ;
NSString *extension = (pictureOptions.encodingType == EncodingTypeJPEG) ? @"jpeg" : @"png";
NSString *uniqueFileName = [NSString stringWithFormat:@"%@%@.%@", tempDir, guid, extension];
return uniqueFileName;
}
@end

View File

@@ -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"
}
}
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

View File

@@ -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 <cordova.h>
#include <QCameraViewfinder>
#include <QCameraImageCapture>
#include <QGraphicsObject>
#include <QCloseEvent>
#include <QQuickItem>
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<QCamera>(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;
}

View File

@@ -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 <cplugin.h>
#include <QtCore>
#include <QQuickView>
#include <QCamera>
#include <QtMultimediaWidgets/QCameraViewfinder>
#include <QCameraImageCapture>
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<QCamera> _camera;
QVariantMap _options;
protected:
enum DestinationType {
DATA_URL = 0,
FILE_URI = 1
};
enum EncodingType {
JPEG = 0,
PNG = 1
};
};
#endif // CAMERA_H

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.1 KiB

872
src/windows/CameraProxy.js Normal file
View File

@@ -0,0 +1,872 @@
/*
*
* 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, module:true, require:true, WinJS:true */
var Camera = require('./Camera');
var getAppData = function () {
return Windows.Storage.ApplicationData.current;
};
var encodeToBase64String = function (buffer) {
return Windows.Security.Cryptography.CryptographicBuffer.encodeToBase64String(buffer);
};
var OptUnique = Windows.Storage.CreationCollisionOption.generateUniqueName;
var CapMSType = Windows.Media.Capture.MediaStreamType;
var webUIApp = Windows.UI.WebUI.WebUIApplication;
var fileIO = Windows.Storage.FileIO;
var pickerLocId = Windows.Storage.Pickers.PickerLocationId;
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
// 11 cameraDirection:0
takePicture: function (successCallback, errorCallback, args) {
var sourceType = args[2];
if (sourceType !== Camera.PictureSourceType.CAMERA) {
takePictureFromFile(successCallback, errorCallback, args);
} else {
takePictureFromCamera(successCallback, errorCallback, args);
}
}
};
// https://msdn.microsoft.com/en-us/library/windows/apps/ff462087(v=vs.105).aspx
var windowsVideoContainers = ['.avi', '.flv', '.asx', '.asf', '.mov', '.mp4', '.mpg', '.rm', '.srt', '.swf', '.wmv', '.vob'];
var windowsPhoneVideoContainers = ['.avi', '.3gp', '.3g2', '.wmv', '.3gp', '.3g2', '.mp4', '.m4v'];
// Default aspect ratio 1.78 (16:9 hd video standard)
var DEFAULT_ASPECT_RATIO = '1.8';
// Highest possible z-index supported across browsers. Anything used above is converted to this value.
var HIGHEST_POSSIBLE_Z_INDEX = 2147483647;
// Resize method
function resizeImage (successCallback, errorCallback, file, targetWidth, targetHeight, encodingType) {
var tempPhotoFileName = '';
var targetContentType = '';
if (encodingType === Camera.EncodingType.PNG) {
tempPhotoFileName = 'camera_cordova_temp_return.png';
targetContentType = 'image/png';
} else {
tempPhotoFileName = 'camera_cordova_temp_return.jpg';
targetContentType = 'image/jpeg';
}
var storageFolder = getAppData().localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting)
.then(function (storageFile) {
return fileIO.readBufferAsync(storageFile);
})
.then(function (buffer) {
var strBase64 = encodeToBase64String(buffer);
var imageData = 'data:' + file.contentType + ';base64,' + strBase64;
var image = new Image(); /* eslint no-undef : 0 */
image.src = imageData;
image.onload = function () {
var ratio = Math.min(targetWidth / this.width, targetHeight / this.height);
var imageWidth = ratio * this.width;
var imageHeight = ratio * this.height;
var canvas = document.createElement('canvas');
var storageFileName;
canvas.width = imageWidth;
canvas.height = imageHeight;
canvas.getContext('2d').drawImage(this, 0, 0, imageWidth, imageHeight);
var fileContent = canvas.toDataURL(targetContentType).split(',')[1];
var storageFolder = getAppData().localFolder;
storageFolder.createFileAsync(tempPhotoFileName, OptUnique)
.then(function (storagefile) {
var content = Windows.Security.Cryptography.CryptographicBuffer.decodeFromBase64String(fileContent);
storageFileName = storagefile.name;
return fileIO.writeBufferAsync(storagefile, content);
})
.done(function () {
successCallback('ms-appdata:///local/' + storageFileName);
}, errorCallback);
};
})
.done(null, function (err) {
errorCallback(err);
});
}
// Because of asynchronous method, so let the successCallback be called in it.
function resizeImageBase64 (successCallback, errorCallback, file, targetWidth, targetHeight) {
fileIO.readBufferAsync(file).done(function (buffer) {
var strBase64 = encodeToBase64String(buffer);
var imageData = 'data:' + file.contentType + ';base64,' + strBase64;
var image = new Image(); /* eslint no-undef : 0 */
image.src = imageData;
image.onload = function () {
var ratio = Math.min(targetWidth / this.width, targetHeight / this.height);
var imageWidth = ratio * this.width;
var imageHeight = ratio * this.height;
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(file.contentType);
// 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);
};
}, function (err) { errorCallback(err); });
}
function takePictureFromFile (successCallback, errorCallback, args) {
// Detect Windows Phone
if (navigator.appVersion.indexOf('Windows Phone 8.1') >= 0) {
takePictureFromFileWP(successCallback, errorCallback, args);
} else {
takePictureFromFileWindows(successCallback, errorCallback, args);
}
}
function takePictureFromFileWP (successCallback, errorCallback, args) {
var mediaType = args[6];
var destinationType = args[1];
var targetWidth = args[3];
var targetHeight = args[4];
var encodingType = args[5];
/*
Need to add and remove an event listener to catch activation state
Using FileOpenPicker will suspend the app and it's required to catch the PickSingleFileAndContinue
https://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn631755.aspx
*/
var filePickerActivationHandler = function (eventArgs) {
if (eventArgs.kind === Windows.ApplicationModel.Activation.ActivationKind.pickFileContinuation) {
var file = eventArgs.files[0];
if (!file) {
errorCallback("User didn't choose a file.");
webUIApp.removeEventListener('activated', filePickerActivationHandler);
return;
}
if (destinationType === Camera.DestinationType.FILE_URI || destinationType === Camera.DestinationType.NATIVE_URI) {
if (targetHeight > 0 && targetWidth > 0) {
resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType);
} else {
var storageFolder = getAppData().localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).done(function (storageFile) {
if (destinationType === Camera.DestinationType.NATIVE_URI) {
successCallback('ms-appdata:///local/' + storageFile.name);
} else {
successCallback(URL.createObjectURL(storageFile));
}
}, function () {
errorCallback("Can't access localStorage folder.");
});
}
} else {
if (targetHeight > 0 && targetWidth > 0) {
resizeImageBase64(successCallback, errorCallback, file, targetWidth, targetHeight);
} else {
fileIO.readBufferAsync(file).done(function (buffer) {
var strBase64 = encodeToBase64String(buffer);
successCallback(strBase64);
}, errorCallback);
}
}
webUIApp.removeEventListener('activated', filePickerActivationHandler);
}
};
var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker();
if (mediaType === Camera.MediaType.PICTURE) {
fileOpenPicker.fileTypeFilter.replaceAll(['.png', '.jpg', '.jpeg']);
fileOpenPicker.suggestedStartLocation = pickerLocId.picturesLibrary;
} else if (mediaType === Camera.MediaType.VIDEO) {
fileOpenPicker.fileTypeFilter.replaceAll(windowsPhoneVideoContainers);
fileOpenPicker.suggestedStartLocation = pickerLocId.videosLibrary;
} else {
fileOpenPicker.fileTypeFilter.replaceAll(['*']);
fileOpenPicker.suggestedStartLocation = pickerLocId.documentsLibrary;
}
webUIApp.addEventListener('activated', filePickerActivationHandler);
fileOpenPicker.pickSingleFileAndContinue();
}
function takePictureFromFileWindows (successCallback, errorCallback, args) {
var mediaType = args[6];
var destinationType = args[1];
var targetWidth = args[3];
var targetHeight = args[4];
var encodingType = args[5];
var fileOpenPicker = new Windows.Storage.Pickers.FileOpenPicker();
if (mediaType === Camera.MediaType.PICTURE) {
fileOpenPicker.fileTypeFilter.replaceAll(['.png', '.jpg', '.jpeg']);
fileOpenPicker.suggestedStartLocation = pickerLocId.picturesLibrary;
} else if (mediaType === Camera.MediaType.VIDEO) {
fileOpenPicker.fileTypeFilter.replaceAll(windowsVideoContainers);
fileOpenPicker.suggestedStartLocation = pickerLocId.videosLibrary;
} else {
fileOpenPicker.fileTypeFilter.replaceAll(['*']);
fileOpenPicker.suggestedStartLocation = pickerLocId.documentsLibrary;
}
fileOpenPicker.pickSingleFileAsync().done(function (file) {
if (!file) {
errorCallback("User didn't choose a file.");
return;
}
if (destinationType === Camera.DestinationType.FILE_URI || destinationType === Camera.DestinationType.NATIVE_URI) {
if (targetHeight > 0 && targetWidth > 0) {
resizeImage(successCallback, errorCallback, file, targetWidth, targetHeight, encodingType);
} else {
var storageFolder = getAppData().localFolder;
file.copyAsync(storageFolder, file.name, Windows.Storage.NameCollisionOption.replaceExisting).done(function (storageFile) {
if (destinationType === Camera.DestinationType.NATIVE_URI) {
successCallback('ms-appdata:///local/' + storageFile.name);
} else {
successCallback(URL.createObjectURL(storageFile));
}
}, function () {
errorCallback("Can't access localStorage folder.");
});
}
} else {
if (targetHeight > 0 && targetWidth > 0) {
resizeImageBase64(successCallback, errorCallback, file, targetWidth, targetHeight);
} else {
fileIO.readBufferAsync(file).done(function (buffer) {
var strBase64 = encodeToBase64String(buffer);
successCallback(strBase64);
}, errorCallback);
}
}
}, function () {
errorCallback("User didn't choose a file.");
});
}
function takePictureFromCamera (successCallback, errorCallback, args) {
// Check if necessary API available
if (!Windows.Media.Capture.CameraCaptureUI) {
takePictureFromCameraWP(successCallback, errorCallback, args);
} else {
takePictureFromCameraWindows(successCallback, errorCallback, args);
}
}
function takePictureFromCameraWP (successCallback, errorCallback, args) {
// We are running on WP8.1 which lacks CameraCaptureUI class
// so we need to use MediaCapture class instead and implement custom UI for camera
var destinationType = args[1];
var targetWidth = args[3];
var targetHeight = args[4];
var encodingType = args[5];
var saveToPhotoAlbum = args[9];
var cameraDirection = args[11];
var capturePreview = null;
var cameraCaptureButton = null;
var cameraCancelButton = null;
var capture = null;
var captureSettings = null;
var CaptureNS = Windows.Media.Capture;
var sensor = null;
function createCameraUI () {
// create style for take and cancel buttons
var buttonStyle = 'width:45%;padding: 10px 16px;font-size: 18px;line-height: 1.3333333;color: #333;background-color: #fff;border-color: #ccc; border: 1px solid transparent;border-radius: 6px; display: block; margin: 20px; z-index: 1000;border-color: #adadad;';
// Create fullscreen preview
// z-order style element for capturePreview and cameraCancelButton elts
// is necessary to avoid overriding by another page elements, -1 sometimes is not enough
capturePreview = document.createElement('video');
capturePreview.style.cssText = 'position: fixed; left: 0; top: 0; width: 100%; height: 100%; z-index: ' + (HIGHEST_POSSIBLE_Z_INDEX - 1) + ';';
// Create capture button
cameraCaptureButton = document.createElement('button');
cameraCaptureButton.innerText = 'Take';
cameraCaptureButton.style.cssText = buttonStyle + 'position: fixed; left: 0; bottom: 0; margin: 20px; z-index: ' + HIGHEST_POSSIBLE_Z_INDEX + ';';
// Create cancel button
cameraCancelButton = document.createElement('button');
cameraCancelButton.innerText = 'Cancel';
cameraCancelButton.style.cssText = buttonStyle + 'position: fixed; right: 0; bottom: 0; margin: 20px; z-index: ' + HIGHEST_POSSIBLE_Z_INDEX + ';';
capture = new CaptureNS.MediaCapture();
captureSettings = new CaptureNS.MediaCaptureInitializationSettings();
captureSettings.streamingCaptureMode = CaptureNS.StreamingCaptureMode.video;
}
function continueVideoOnFocus () {
// if preview is defined it would be stuck, play it
if (capturePreview) {
capturePreview.play();
}
}
function startCameraPreview () {
// Search for available camera devices
// This is necessary to detect which camera (front or back) we should use
var DeviceEnum = Windows.Devices.Enumeration;
var expectedPanel = cameraDirection === 1 ? DeviceEnum.Panel.front : DeviceEnum.Panel.back;
// Add focus event handler to capture the event when user suspends the app and comes back while the preview is on
window.addEventListener('focus', continueVideoOnFocus);
DeviceEnum.DeviceInformation.findAllAsync(DeviceEnum.DeviceClass.videoCapture).then(function (devices) {
if (devices.length <= 0) {
destroyCameraPreview();
errorCallback('Camera not found');
return;
}
devices.forEach(function (currDev) {
if (currDev.enclosureLocation.panel && currDev.enclosureLocation.panel === expectedPanel) {
captureSettings.videoDeviceId = currDev.id;
}
});
captureSettings.photoCaptureSource = Windows.Media.Capture.PhotoCaptureSource.photo;
return capture.initializeAsync(captureSettings);
}).then(function () {
// create focus control if available
var VideoDeviceController = capture.videoDeviceController;
var FocusControl = VideoDeviceController.focusControl;
if (FocusControl.supported === true) {
capturePreview.addEventListener('click', function () {
// Make sure function isn't called again before previous focus is completed
if (this.getAttribute('clicked') === '1') {
return false;
} else {
this.setAttribute('clicked', '1');
}
var preset = Windows.Media.Devices.FocusPreset.autoNormal;
var parent = this;
FocusControl.setPresetAsync(preset).done(function () {
// set the clicked attribute back to '0' to allow focus again
parent.setAttribute('clicked', '0');
});
});
}
// msdn.microsoft.com/en-us/library/windows/apps/hh452807.aspx
capturePreview.msZoom = true;
capturePreview.src = URL.createObjectURL(capture);
capturePreview.play();
// Bind events to controls
sensor = Windows.Devices.Sensors.SimpleOrientationSensor.getDefault();
if (sensor !== null) {
sensor.addEventListener('orientationchanged', onOrientationChange);
}
// add click events to capture and cancel buttons
cameraCaptureButton.addEventListener('click', onCameraCaptureButtonClick);
cameraCancelButton.addEventListener('click', onCameraCancelButtonClick);
// Change default orientation
if (sensor) {
setPreviewRotation(sensor.getCurrentOrientation());
} else {
setPreviewRotation(Windows.Graphics.Display.DisplayInformation.getForCurrentView().currentOrientation);
}
// Get available aspect ratios
var aspectRatios = getAspectRatios(capture);
// Couldn't find a good ratio
if (aspectRatios.length === 0) {
destroyCameraPreview();
errorCallback('There\'s not a good aspect ratio available');
return;
}
// add elements to body
document.body.appendChild(capturePreview);
document.body.appendChild(cameraCaptureButton);
document.body.appendChild(cameraCancelButton);
if (aspectRatios.indexOf(DEFAULT_ASPECT_RATIO) > -1) {
return setAspectRatio(capture, DEFAULT_ASPECT_RATIO);
} else {
// Doesn't support 16:9 - pick next best
return setAspectRatio(capture, aspectRatios[0]);
}
}).done(null, function (err) {
destroyCameraPreview();
errorCallback('Camera intitialization error ' + err);
});
}
function destroyCameraPreview () {
// If sensor is available, remove event listener
if (sensor !== null) {
sensor.removeEventListener('orientationchanged', onOrientationChange);
}
// Pause and dispose preview element
capturePreview.pause();
capturePreview.src = null;
// Remove event listeners from buttons
cameraCaptureButton.removeEventListener('click', onCameraCaptureButtonClick);
cameraCancelButton.removeEventListener('click', onCameraCancelButtonClick);
// Remove the focus event handler
window.removeEventListener('focus', continueVideoOnFocus);
// Remove elements
[capturePreview, cameraCaptureButton, cameraCancelButton].forEach(function (elem) {
if (elem /* && elem in document.body.childNodes */) {
document.body.removeChild(elem);
}
});
// Stop and dispose media capture manager
if (capture) {
capture.stopRecordAsync();
capture = null;
}
}
function captureAction () {
var encodingProperties;
var fileName;
var tempFolder = getAppData().temporaryFolder;
if (encodingType === Camera.EncodingType.PNG) {
fileName = 'photo.png';
encodingProperties = Windows.Media.MediaProperties.ImageEncodingProperties.createPng();
} else {
fileName = 'photo.jpg';
encodingProperties = Windows.Media.MediaProperties.ImageEncodingProperties.createJpeg();
}
tempFolder.createFileAsync(fileName, OptUnique)
.then(function (tempCapturedFile) {
return new WinJS.Promise(function (complete) {
var photoStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
var finalStream = new Windows.Storage.Streams.InMemoryRandomAccessStream();
capture.capturePhotoToStreamAsync(encodingProperties, photoStream)
.then(function () {
return Windows.Graphics.Imaging.BitmapDecoder.createAsync(photoStream);
})
.then(function (dec) {
finalStream.size = 0; // BitmapEncoder requires the output stream to be empty
return Windows.Graphics.Imaging.BitmapEncoder.createForTranscodingAsync(finalStream, dec);
})
.then(function (enc) {
// We need to rotate the photo wrt sensor orientation
enc.bitmapTransform.rotation = orientationToRotation(sensor.getCurrentOrientation());
return enc.flushAsync();
})
.then(function () {
return tempCapturedFile.openAsync(Windows.Storage.FileAccessMode.readWrite);
})
.then(function (fileStream) {
return Windows.Storage.Streams.RandomAccessStream.copyAndCloseAsync(finalStream, fileStream);
})
.done(function () {
photoStream.close();
finalStream.close();
complete(tempCapturedFile);
}, function () {
photoStream.close();
finalStream.close();
throw new Error('An error has occured while capturing the photo.');
});
});
})
.done(function (capturedFile) {
destroyCameraPreview();
savePhoto(capturedFile, {
destinationType: destinationType,
targetHeight: targetHeight,
targetWidth: targetWidth,
encodingType: encodingType,
saveToPhotoAlbum: saveToPhotoAlbum
}, successCallback, errorCallback);
}, function (err) {
destroyCameraPreview();
errorCallback(err);
});
}
function getAspectRatios (capture) {
var videoDeviceController = capture.videoDeviceController;
var photoAspectRatios = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.photo).map(function (element) {
return (element.width / element.height).toFixed(1);
}).filter(function (element, index, array) { return (index === array.indexOf(element)); });
var videoAspectRatios = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.videoRecord).map(function (element) {
return (element.width / element.height).toFixed(1);
}).filter(function (element, index, array) { return (index === array.indexOf(element)); });
var videoPreviewAspectRatios = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.videoPreview).map(function (element) {
return (element.width / element.height).toFixed(1);
}).filter(function (element, index, array) { return (index === array.indexOf(element)); });
var allAspectRatios = [].concat(photoAspectRatios, videoAspectRatios, videoPreviewAspectRatios);
var aspectObj = allAspectRatios.reduce(function (map, item) {
if (!map[item]) {
map[item] = 0;
}
map[item]++;
return map;
}, {});
return Object.keys(aspectObj).filter(function (k) {
return aspectObj[k] === 3;
});
}
function setAspectRatio (capture, aspect) {
// Max photo resolution with desired aspect ratio
var videoDeviceController = capture.videoDeviceController;
var photoResolution = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.photo)
.filter(function (elem) {
return ((elem.width / elem.height).toFixed(1) === aspect);
})
.reduce(function (prop1, prop2) {
return (prop1.width * prop1.height) > (prop2.width * prop2.height) ? prop1 : prop2;
});
// Max video resolution with desired aspect ratio
var videoRecordResolution = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.videoRecord)
.filter(function (elem) {
return ((elem.width / elem.height).toFixed(1) === aspect);
})
.reduce(function (prop1, prop2) {
return (prop1.width * prop1.height) > (prop2.width * prop2.height) ? prop1 : prop2;
});
// Max video preview resolution with desired aspect ratio
var videoPreviewResolution = videoDeviceController.getAvailableMediaStreamProperties(CapMSType.videoPreview)
.filter(function (elem) {
return ((elem.width / elem.height).toFixed(1) === aspect);
})
.reduce(function (prop1, prop2) {
return (prop1.width * prop1.height) > (prop2.width * prop2.height) ? prop1 : prop2;
});
return videoDeviceController.setMediaStreamPropertiesAsync(CapMSType.photo, photoResolution)
.then(function () {
return videoDeviceController.setMediaStreamPropertiesAsync(CapMSType.videoPreview, videoPreviewResolution);
})
.then(function () {
return videoDeviceController.setMediaStreamPropertiesAsync(CapMSType.videoRecord, videoRecordResolution);
});
}
/**
* When Capture button is clicked, try to capture a picture and return
*/
function onCameraCaptureButtonClick () {
// Make sure user can't click more than once
if (this.getAttribute('clicked') === '1') {
return false;
} else {
this.setAttribute('clicked', '1');
}
captureAction();
}
/**
* When Cancel button is clicked, destroy camera preview and return with error callback
*/
function onCameraCancelButtonClick () {
// Make sure user can't click more than once
if (this.getAttribute('clicked') === '1') {
return false;
} else {
this.setAttribute('clicked', '1');
}
destroyCameraPreview();
errorCallback('no image selected');
}
/**
* When the phone orientation change, get the event and change camera preview rotation
* @param {Object} e - SimpleOrientationSensorOrientationChangedEventArgs
*/
function onOrientationChange (e) {
setPreviewRotation(e.orientation);
}
/**
* Converts SimpleOrientation to a VideoRotation to remove difference between camera sensor orientation
* and video orientation
* @param {number} orientation - Windows.Devices.Sensors.SimpleOrientation
* @return {number} - Windows.Media.Capture.VideoRotation
*/
function orientationToRotation (orientation) {
// VideoRotation enumerable and BitmapRotation enumerable have the same values
// https://msdn.microsoft.com/en-us/library/windows/apps/windows.media.capture.videorotation.aspx
// https://msdn.microsoft.com/en-us/library/windows/apps/windows.graphics.imaging.bitmaprotation.aspx
switch (orientation) {
// portrait
case Windows.Devices.Sensors.SimpleOrientation.notRotated:
return Windows.Media.Capture.VideoRotation.clockwise90Degrees;
// landscape
case Windows.Devices.Sensors.SimpleOrientation.rotated90DegreesCounterclockwise:
return Windows.Media.Capture.VideoRotation.none;
// portrait-flipped (not supported by WinPhone Apps)
case Windows.Devices.Sensors.SimpleOrientation.rotated180DegreesCounterclockwise:
// Falling back to portrait default
return Windows.Media.Capture.VideoRotation.clockwise90Degrees;
// landscape-flipped
case Windows.Devices.Sensors.SimpleOrientation.rotated270DegreesCounterclockwise:
return Windows.Media.Capture.VideoRotation.clockwise180Degrees;
// faceup & facedown
default:
// Falling back to portrait default
return Windows.Media.Capture.VideoRotation.clockwise90Degrees;
}
}
/**
* Rotates the current MediaCapture's video
* @param {number} orientation - Windows.Devices.Sensors.SimpleOrientation
*/
function setPreviewRotation (orientation) {
capture.setPreviewRotation(orientationToRotation(orientation));
}
try {
createCameraUI();
startCameraPreview();
} catch (ex) {
errorCallback(ex);
}
}
function takePictureFromCameraWindows (successCallback, errorCallback, args) {
var destinationType = args[1];
var targetWidth = args[3];
var targetHeight = args[4];
var encodingType = args[5];
var allowCrop = !!args[7];
var saveToPhotoAlbum = args[9];
var WMCapture = Windows.Media.Capture;
var cameraCaptureUI = new WMCapture.CameraCaptureUI();
cameraCaptureUI.photoSettings.allowCropping = allowCrop;
if (encodingType === Camera.EncodingType.PNG) {
cameraCaptureUI.photoSettings.format = WMCapture.CameraCaptureUIPhotoFormat.png;
} else {
cameraCaptureUI.photoSettings.format = WMCapture.CameraCaptureUIPhotoFormat.jpeg;
}
// decide which max pixels should be supported by targetWidth or targetHeight.
var maxRes = null;
var UIMaxRes = WMCapture.CameraCaptureUIMaxPhotoResolution;
var totalPixels = targetWidth * targetHeight;
if (targetWidth === -1 && targetHeight === -1) {
maxRes = UIMaxRes.highestAvailable;
// Temp fix for CB-10539
/* else if (totalPixels <= 320 * 240) {
maxRes = UIMaxRes.verySmallQvga;
} */
} else if (totalPixels <= 640 * 480) {
maxRes = UIMaxRes.smallVga;
} else if (totalPixels <= 1024 * 768) {
maxRes = UIMaxRes.mediumXga;
} else if (totalPixels <= 3 * 1000 * 1000) {
maxRes = UIMaxRes.large3M;
} else if (totalPixels <= 5 * 1000 * 1000) {
maxRes = UIMaxRes.veryLarge5M;
} else {
maxRes = UIMaxRes.highestAvailable;
}
cameraCaptureUI.photoSettings.maxResolution = maxRes;
var cameraPicture;
// define focus handler for windows phone 10.0
var savePhotoOnFocus = function () {
window.removeEventListener('focus', savePhotoOnFocus);
// call only when the app is in focus again
savePhoto(cameraPicture, {
destinationType: destinationType,
targetHeight: targetHeight,
targetWidth: targetWidth,
encodingType: encodingType,
saveToPhotoAlbum: saveToPhotoAlbum
}, successCallback, errorCallback);
};
// if windows phone 10, add and delete focus eventHandler to capture the focus back from cameraUI to app
if (navigator.appVersion.indexOf('Windows Phone 10.0') >= 0) {
window.addEventListener('focus', savePhotoOnFocus);
}
cameraCaptureUI.captureFileAsync(WMCapture.CameraCaptureUIMode.photo).done(function (picture) {
if (!picture) {
errorCallback("User didn't capture a photo.");
// Remove the focus handler if present
window.removeEventListener('focus', savePhotoOnFocus);
return;
}
cameraPicture = picture;
// If not windows 10, call savePhoto() now. If windows 10, wait for the app to be in focus again
if (navigator.appVersion.indexOf('Windows Phone 10.0') < 0) {
savePhoto(cameraPicture, {
destinationType: destinationType,
targetHeight: targetHeight,
targetWidth: targetWidth,
encodingType: encodingType,
saveToPhotoAlbum: saveToPhotoAlbum
}, successCallback, errorCallback);
}
}, function () {
errorCallback('Fail to capture a photo.');
window.removeEventListener('focus', savePhotoOnFocus);
});
}
function savePhoto (picture, options, successCallback, errorCallback) {
// success callback for capture operation
var success = function (picture) {
if (options.destinationType === Camera.DestinationType.FILE_URI || options.destinationType === Camera.DestinationType.NATIVE_URI) {
if (options.targetHeight > 0 && options.targetWidth > 0) {
resizeImage(successCallback, errorCallback, picture, options.targetWidth, options.targetHeight, options.encodingType);
} else {
// CB-11714: check if target content-type is PNG to just rename as *.jpg since camera is captured as JPEG
if (options.encodingType === Camera.EncodingType.PNG) {
picture.name = picture.name.replace(/\.png$/, '.jpg');
}
picture.copyAsync(getAppData().localFolder, picture.name, OptUnique).done(function (copiedFile) {
successCallback('ms-appdata:///local/' + copiedFile.name);
}, errorCallback);
}
} else {
if (options.targetHeight > 0 && options.targetWidth > 0) {
resizeImageBase64(successCallback, errorCallback, picture, options.targetWidth, options.targetHeight);
} else {
fileIO.readBufferAsync(picture).done(function (buffer) {
var strBase64 = encodeToBase64String(buffer);
picture.deleteAsync().done(function () {
successCallback(strBase64);
}, function (err) {
errorCallback(err);
});
}, errorCallback);
}
}
};
if (!options.saveToPhotoAlbum) {
success(picture);
} else {
var savePicker = new Windows.Storage.Pickers.FileSavePicker();
var saveFile = function (file) {
if (file) {
// Prevent updates to the remote version of the file until we're done
Windows.Storage.CachedFileManager.deferUpdates(file);
picture.moveAndReplaceAsync(file)
.then(function () {
// Let Windows know that we're finished changing the file so
// the other app can update the remote version of the file.
return Windows.Storage.CachedFileManager.completeUpdatesAsync(file);
})
.done(function (updateStatus) {
if (updateStatus === Windows.Storage.Provider.FileUpdateStatus.complete) {
success(picture);
} else {
errorCallback('File update status is not complete.');
}
}, errorCallback);
} else {
errorCallback('Failed to select a file.');
}
};
savePicker.suggestedStartLocation = pickerLocId.picturesLibrary;
if (options.encodingType === Camera.EncodingType.PNG) {
savePicker.fileTypeChoices.insert('PNG', ['.png']);
savePicker.suggestedFileName = 'photo.png';
} else {
savePicker.fileTypeChoices.insert('JPEG', ['.jpg']);
savePicker.suggestedFileName = 'photo.jpg';
}
// If Windows Phone 8.1 use pickSaveFileAndContinue()
if (navigator.appVersion.indexOf('Windows Phone 8.1') >= 0) {
/*
Need to add and remove an event listener to catch activation state
Using FileSavePicker will suspend the app and it's required to catch the pickSaveFileContinuation
https://msdn.microsoft.com/en-us/library/windows/apps/xaml/dn631755.aspx
*/
var fileSaveHandler = function (eventArgs) {
if (eventArgs.kind === Windows.ApplicationModel.Activation.ActivationKind.pickSaveFileContinuation) {
var file = eventArgs.file;
saveFile(file);
webUIApp.removeEventListener('activated', fileSaveHandler);
}
};
webUIApp.addEventListener('activated', fileSaveHandler);
savePicker.pickSaveFileAndContinue();
} else {
savePicker.pickSaveFileAsync()
.done(saveFile, errorCallback);
}
}
}
require('cordova/exec/proxy').add('Camera', module.exports);

View File

@@ -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/windows8/commandProxy").add("Camera",module.exports);

View File

@@ -1,490 +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
{
/// <summary>
/// Return base64 encoded string
/// </summary>
private const int DATA_URL = 0;
/// <summary>
/// Return file uri
/// </summary>
private const int FILE_URI = 1;
/// <summary>
/// Choose image from picture library
/// </summary>
private const int PHOTOLIBRARY = 0;
/// <summary>
/// Take picture from camera
/// </summary>
private const int CAMERA = 1;
/// <summary>
/// Choose image from picture library
/// </summary>
private const int SAVEDPHOTOALBUM = 2;
/// <summary>
/// Take a picture of type JPEG
/// </summary>
private const int JPEG = 0;
/// <summary>
/// Take a picture of type PNG
/// </summary>
private const int PNG = 1;
/// <summary>
/// Folder to store captured images
/// </summary>
private const string isoFolder = "CapturedImagesCache";
/// <summary>
/// Represents captureImage action options.
/// </summary>
[DataContract]
public class CameraOptions
{
/// <summary>
/// Source to getPicture from.
/// </summary>
[DataMember(IsRequired = false, Name = "sourceType")]
public int PictureSourceType { get; set; }
/// <summary>
/// Format of image that returned from getPicture.
/// </summary>
[DataMember(IsRequired = false, Name = "destinationType")]
public int DestinationType { get; set; }
/// <summary>
/// Quality of saved image
/// </summary>
[DataMember(IsRequired = false, Name = "quality")]
public int Quality { get; set; }
/// <summary>
/// Controls whether or not the image is also added to the device photo album.
/// </summary>
[DataMember(IsRequired = false, Name = "saveToPhotoAlbum")]
public bool SaveToPhotoAlbum { get; set; }
/// <summary>
/// Ignored
/// </summary>
[DataMember(IsRequired = false, Name = "correctOrientation")]
public bool CorrectOrientation { get; set; }
/// <summary>
/// Ignored
/// </summary>
[DataMember(IsRequired = false, Name = "allowEdit")]
public bool AllowEdit { get; set; }
/// <summary>
/// Height in pixels to scale image
/// </summary>
[DataMember(IsRequired = false, Name = "encodingType")]
public int EncodingType { get; set; }
/// <summary>
/// Height in pixels to scale image
/// </summary>
[DataMember(IsRequired = false, Name = "mediaType")]
public int MediaType { get; set; }
/// <summary>
/// Height in pixels to scale image
/// </summary>
[DataMember(IsRequired = false, Name = "targetHeight")]
public int TargetHeight { get; set; }
/// <summary>
/// Width in pixels to scale image
/// </summary>
[DataMember(IsRequired = false, Name = "targetWidth")]
public int TargetWidth { get; set; }
/// <summary>
/// Creates options object with default parameters
/// </summary>
public CameraOptions()
{
this.SetDefaultValues(new StreamingContext());
}
/// <summary>
/// Initializes default values for class fields.
/// Implemented in separate method because default constructor is not invoked during deserialization.
/// </summary>
/// <param name="context"></param>
[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;
}
}
/// <summary>
/// Used to open photo library
/// </summary>
PhotoChooserTask photoChooserTask;
/// <summary>
/// Used to open camera application
/// </summary>
CameraCaptureTask cameraTask;
/// <summary>
/// Camera options
/// </summary>
CameraOptions cameraOptions;
public void takePicture(string options)
{
try
{
string[] args = JSON.JsonHelper.Deserialize<string[]>(options);
// ["quality", "destinationType", "sourceType", "targetWidth", "targetHeight", "encodingType",
// "mediaType", "allowEdit", "correctOrientation", "saveToPhotoAlbum" ]
this.cameraOptions = new CameraOptions();
this.cameraOptions.Quality = int.Parse(args[0]);
this.cameraOptions.DestinationType = int.Parse(args[1]);
this.cameraOptions.PictureSourceType = int.Parse(args[2]);
this.cameraOptions.TargetWidth = int.Parse(args[3]);
this.cameraOptions.TargetHeight = int.Parse(args[4]);
this.cameraOptions.EncodingType = int.Parse(args[5]);
this.cameraOptions.MediaType = int.Parse(args[6]);
this.cameraOptions.AllowEdit = bool.Parse(args[7]);
this.cameraOptions.CorrectOrientation = bool.Parse(args[8]);
this.cameraOptions.SaveToPhotoAlbum = bool.Parse(args[9]);
//this.cameraOptions = String.IsNullOrEmpty(options) ?
// new CameraOptions() : JSON.JsonHelper.Deserialize<CameraOptions>(options);
}
catch (Exception ex)
{
this.DispatchCommandResult(new PluginResult(PluginResult.Status.JSON_EXCEPTION, ex.Message));
return;
}
//TODO Check if all the options are acceptable
if (cameraOptions.PictureSourceType == CAMERA)
{
cameraTask = new CameraCaptureTask();
cameraTask.Completed += onCameraTaskCompleted;
cameraTask.Show();
}
else
{
if ((cameraOptions.PictureSourceType == PHOTOLIBRARY) || (cameraOptions.PictureSourceType == SAVEDPHOTOALBUM))
{
photoChooserTask = new PhotoChooserTask();
photoChooserTask.Completed += onPickerTaskCompleted;
photoChooserTask.Show();
}
else
{
DispatchCommandResult(new PluginResult(PluginResult.Status.NO_RESULT));
}
}
}
public void onCameraTaskCompleted(object sender, PhotoResult e)
{
if (e.Error != null)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
return;
}
switch (e.TaskResult)
{
case TaskResult.OK:
try
{
string imagePathOrContent = string.Empty;
if (cameraOptions.DestinationType == FILE_URI)
{
// Save image in media library
if (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
}
Stream rotImageStream = ImageExifHelper.RotateStream(e.ChosenPhoto, newAngle);
// we should return stream position back after saving stream to media library
rotImageStream.Seek(0, SeekOrigin.Begin);
WriteableBitmap image = PictureDecoder.DecodeJpeg(rotImageStream);
imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName));
}
else if (cameraOptions.DestinationType == DATA_URL)
{
imagePathOrContent = this.GetImageContent(e.ChosenPhoto);
}
else
{
// TODO: shouldn't this happen before we launch the camera-picker?
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
return;
}
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;
}
}
public void onPickerTaskCompleted(object sender, PhotoResult e)
{
if (e.Error != null)
{
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR));
return;
}
switch (e.TaskResult)
{
case TaskResult.OK:
try
{
string imagePathOrContent = string.Empty;
if (cameraOptions.DestinationType == FILE_URI)
{
WriteableBitmap image = PictureDecoder.DecodeJpeg(e.ChosenPhoto);
imagePathOrContent = this.SaveImageToLocalStorage(image, Path.GetFileName(e.OriginalFileName));
}
else if (cameraOptions.DestinationType == DATA_URL)
{
imagePathOrContent = this.GetImageContent(e.ChosenPhoto);
}
else
{
// TODO: shouldn't this happen before we launch the camera-picker?
DispatchCommandResult(new PluginResult(PluginResult.Status.ERROR, "Incorrect option: destinationType"));
return;
}
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;
}
}
/// <summary>
/// Returns image content in a form of base64 string
/// </summary>
/// <param name="stream">Image stream</param>
/// <returns>Base64 representation of the image</returns>
private string GetImageContent(Stream stream)
{
int streamLength = (int)stream.Length;
byte[] fileData = new byte[streamLength + 1];
stream.Read(fileData, 0, streamLength);
//use photo's actual width & height if user doesn't provide width & height
if (cameraOptions.TargetWidth < 0 && cameraOptions.TargetHeight < 0)
{
stream.Close();
return Convert.ToBase64String(fileData);
}
else
{
// resize photo
byte[] resizedFile = ResizePhoto(stream, fileData);
stream.Close();
return Convert.ToBase64String(resizedFile);
}
}
/// <summary>
/// Resize image
/// </summary>
/// <param name="stream">Image stream</param>
/// <param name="fileData">File data</param>
/// <returns>resized image</returns>
private byte[] ResizePhoto(Stream stream, byte[] fileData)
{
int streamLength = (int)stream.Length;
int intResult = 0;
byte[] resizedFile;
stream.Read(fileData, 0, streamLength);
BitmapImage objBitmap = new BitmapImage();
MemoryStream objBitmapStream = new MemoryStream(fileData);
MemoryStream objBitmapStreamResized = new MemoryStream();
WriteableBitmap objWB;
objBitmap.SetSource(stream);
objWB = new WriteableBitmap(objBitmap);
// resize the photo with user defined TargetWidth & TargetHeight
Extensions.SaveJpeg(objWB, objBitmapStreamResized, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality);
//Convert the resized stream to a byte array.
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...
intResult = objBitmapStreamResized.Read(resizedFile, 0, streamLength);
return resizedFile;
}
/// <summary>
/// Saves captured image in isolated storage
/// </summary>
/// <param name="imageFileName">image file name</param>
/// <returns>Image path</returns>
private string SaveImageToLocalStorage(WriteableBitmap image, string imageFileName)
{
if (image == 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 (var stream = isoFile.CreateFile(filePath))
{
// resize image if Height and Width defined via options
if (cameraOptions.TargetHeight > 0 && cameraOptions.TargetWidth > 0)
{
image.SaveJpeg(stream, cameraOptions.TargetWidth, cameraOptions.TargetHeight, 0, cameraOptions.Quality);
}
else
{
image.SaveJpeg(stream, image.PixelWidth, image.PixelHeight, 0, cameraOptions.Quality);
}
}
return new Uri(filePath, UriKind.Relative).ToString();
}
catch (Exception)
{
//TODO: log or do something else
throw;
}
}
}
}

1
tests/ios/.gitignore vendored Normal file
View File

@@ -0,0 +1 @@
node_modules

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "container:CDVCameraTest/CDVCameraTest.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>6BE9AD73-1B9F-4362-98D7-DC631BEC6185</string>
<key>IDESourceControlProjectName</key>
<string>CDVCameraTest</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>729B5706E7BAF4E9EE7AEE3C003A08107411AB7C</key>
<string>github.com:shazron/cordova-plugin-camera.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>tests/ios/CDVCameraTest.xcworkspace</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>729B5706E7BAF4E9EE7AEE3C003A08107411AB7C</key>
<string>../../..</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>github.com:shazron/cordova-plugin-camera.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>729B5706E7BAF4E9EE7AEE3C003A08107411AB7C</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>729B5706E7BAF4E9EE7AEE3C003A08107411AB7C</string>
<key>IDESourceControlWCCName</key>
<string>cordova-plugin-camera</string>
</dict>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0610"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D2AAC07D0554694100DB518D"
BuildableName = "libCordova.a"
BlueprintName = "CordovaLib"
ReferencedContainer = "container:node_modules/cordova-ios/CordovaLib/CordovaLib.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D2AAC07D0554694100DB518D"
BuildableName = "libCordova.a"
BlueprintName = "CordovaLib"
ReferencedContainer = "container:node_modules/cordova-ios/CordovaLib/CordovaLib.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "D2AAC07D0554694100DB518D"
BuildableName = "libCordova.a"
BlueprintName = "CordovaLib"
ReferencedContainer = "container:node_modules/cordova-ios/CordovaLib/CordovaLib.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,511 @@
/*
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 <UIKit/UIKit.h>
#import <XCTest/XCTest.h>
#import "CDVCamera.h"
#import "UIImage+CropScaleOrientation.h"
#import <MobileCoreServices/UTCoreTypes.h>
@interface CameraTest : XCTestCase
@property (nonatomic, strong) CDVCamera* plugin;
@end
@interface CDVCamera ()
// expose private interface
- (NSData*)processImage:(UIImage*)image info:(NSDictionary*)info options:(CDVPictureOptions*)options;
- (UIImage*)retrieveImage:(NSDictionary*)info options:(CDVPictureOptions*)options;
- (CDVPluginResult*)resultForImage:(CDVPictureOptions*)options info:(NSDictionary*)info;
- (CDVPluginResult*)resultForVideo:(NSDictionary*)info;
@end
@implementation CameraTest
- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
self.plugin = [[CDVCamera alloc] init];
}
- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}
- (void) testPictureOptionsCreate
{
NSArray* args;
CDVPictureOptions* options;
NSDictionary* popoverOptions;
// No arguments, check whether the defaults are set
args = @[];
CDVInvokedUrlCommand* command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"];
options = [CDVPictureOptions createFromTakePictureArguments:command];
XCTAssertEqual([options.quality intValue], 50);
XCTAssertEqual(options.destinationType, (int)DestinationTypeFileUri);
XCTAssertEqual(options.sourceType, (int)UIImagePickerControllerSourceTypeCamera);
XCTAssertEqual(options.targetSize.width, 0);
XCTAssertEqual(options.targetSize.height, 0);
XCTAssertEqual(options.encodingType, (int)EncodingTypeJPEG);
XCTAssertEqual(options.mediaType, (int)MediaTypePicture);
XCTAssertEqual(options.allowsEditing, NO);
XCTAssertEqual(options.correctOrientation, NO);
XCTAssertEqual(options.saveToPhotoAlbum, NO);
XCTAssertEqualObjects(options.popoverOptions, nil);
XCTAssertEqual(options.cameraDirection, (int)UIImagePickerControllerCameraDeviceRear);
XCTAssertEqual(options.popoverSupported, NO);
XCTAssertEqual(options.usesGeolocation, NO);
// Set each argument, check whether they are set. different from defaults
popoverOptions = @{ @"x" : @1, @"y" : @2, @"width" : @3, @"height" : @4, @"popoverWidth": @200, @"popoverHeight": @300 };
args = @[
@(49),
@(DestinationTypeDataUrl),
@(UIImagePickerControllerSourceTypePhotoLibrary),
@(120),
@(240),
@(EncodingTypePNG),
@(MediaTypeVideo),
@YES,
@YES,
@YES,
popoverOptions,
@(UIImagePickerControllerCameraDeviceFront),
];
command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"];
options = [CDVPictureOptions createFromTakePictureArguments:command];
XCTAssertEqual([options.quality intValue], 49);
XCTAssertEqual(options.destinationType, (int)DestinationTypeDataUrl);
XCTAssertEqual(options.sourceType, (int)UIImagePickerControllerSourceTypePhotoLibrary);
XCTAssertEqual(options.targetSize.width, 120);
XCTAssertEqual(options.targetSize.height, 240);
XCTAssertEqual(options.encodingType, (int)EncodingTypePNG);
XCTAssertEqual(options.mediaType, (int)MediaTypeVideo);
XCTAssertEqual(options.allowsEditing, YES);
XCTAssertEqual(options.correctOrientation, YES);
XCTAssertEqual(options.saveToPhotoAlbum, YES);
XCTAssertEqualObjects(options.popoverOptions, popoverOptions);
XCTAssertEqual(options.cameraDirection, (int)UIImagePickerControllerCameraDeviceFront);
XCTAssertEqual(options.popoverSupported, NO);
XCTAssertEqual(options.usesGeolocation, NO);
}
- (void) testCameraPickerCreate
{
NSDictionary* popoverOptions;
NSArray* args;
CDVPictureOptions* pictureOptions;
CDVCameraPicker* picker;
// Souce is Camera, and image type
popoverOptions = @{ @"x" : @1, @"y" : @2, @"width" : @3, @"height" : @4, @"popoverWidth": @200, @"popoverHeight": @300 };
args = @[
@(49),
@(DestinationTypeDataUrl),
@(UIImagePickerControllerSourceTypeCamera),
@(120),
@(240),
@(EncodingTypePNG),
@(MediaTypeAll),
@YES,
@YES,
@YES,
popoverOptions,
@(UIImagePickerControllerCameraDeviceFront),
];
CDVInvokedUrlCommand* command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"];
pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command];
if ([UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType]) {
picker = [CDVCameraPicker createFromPictureOptions:pictureOptions];
XCTAssertEqualObjects(picker.pictureOptions, pictureOptions);
XCTAssertEqual(picker.sourceType, pictureOptions.sourceType);
XCTAssertEqual(picker.allowsEditing, pictureOptions.allowsEditing);
XCTAssertEqualObjects(picker.mediaTypes, @[(NSString*)kUTTypeImage]);
XCTAssertEqual(picker.cameraDevice, pictureOptions.cameraDirection);
}
// Souce is not Camera, and all media types
args = @[
@(49),
@(DestinationTypeDataUrl),
@(UIImagePickerControllerSourceTypePhotoLibrary),
@(120),
@(240),
@(EncodingTypePNG),
@(MediaTypeAll),
@YES,
@YES,
@YES,
popoverOptions,
@(UIImagePickerControllerCameraDeviceFront),
];
command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"];
pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command];
if ([UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType]) {
picker = [CDVCameraPicker createFromPictureOptions:pictureOptions];
XCTAssertEqualObjects(picker.pictureOptions, pictureOptions);
XCTAssertEqual(picker.sourceType, pictureOptions.sourceType);
XCTAssertEqual(picker.allowsEditing, pictureOptions.allowsEditing);
XCTAssertEqualObjects(picker.mediaTypes, [UIImagePickerController availableMediaTypesForSourceType:picker.sourceType]);
}
// Souce is not Camera, and either Image or Movie media type
args = @[
@(49),
@(DestinationTypeDataUrl),
@(UIImagePickerControllerSourceTypePhotoLibrary),
@(120),
@(240),
@(EncodingTypePNG),
@(MediaTypeVideo),
@YES,
@YES,
@YES,
popoverOptions,
@(UIImagePickerControllerCameraDeviceFront),
];
command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"];
pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command];
if ([UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType]) {
picker = [CDVCameraPicker createFromPictureOptions:pictureOptions];
XCTAssertEqualObjects(picker.pictureOptions, pictureOptions);
XCTAssertEqual(picker.sourceType, pictureOptions.sourceType);
XCTAssertEqual(picker.allowsEditing, pictureOptions.allowsEditing);
XCTAssertEqualObjects(picker.mediaTypes, @[(NSString*)kUTTypeMovie]);
}
}
- (UIImage*) createImage:(CGRect)rect orientation:(UIImageOrientation)imageOrientation {
UIGraphicsBeginImageContext(rect.size);
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextSetFillColorWithColor(context, [[UIColor greenColor] CGColor]);
CGContextFillRect(context, rect);
CGImageRef result = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext());
UIImage* image = [UIImage imageWithCGImage:result scale:1.0f orientation:imageOrientation];
UIGraphicsEndImageContext();
return image;
}
- (void) testImageScaleCropForSize {
UIImage *sourceImagePortrait, *sourceImageLandscape, *targetImage;
CGSize targetSize = CGSizeZero;
sourceImagePortrait = [self createImage:CGRectMake(0, 0, 2448, 3264) orientation:UIImageOrientationUp];
sourceImageLandscape = [self createImage:CGRectMake(0, 0, 3264, 2448) orientation:UIImageOrientationUp];
// test 640x480
targetSize = CGSizeMake(640, 480);
targetImage = [sourceImagePortrait imageByScalingAndCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
targetImage = [sourceImageLandscape imageByScalingAndCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
// test 800x600
targetSize = CGSizeMake(800, 600);
targetImage = [sourceImagePortrait imageByScalingAndCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
targetImage = [sourceImageLandscape imageByScalingAndCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
// test 1024x768
targetSize = CGSizeMake(1024, 768);
targetImage = [sourceImagePortrait imageByScalingAndCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
targetImage = [sourceImageLandscape imageByScalingAndCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
}
- (void) testImageScaleNoCropForSize {
UIImage *sourceImagePortrait, *sourceImageLandscape, *targetImage;
CGSize targetSize = CGSizeZero;
sourceImagePortrait = [self createImage:CGRectMake(0, 0, 2448, 3264) orientation:UIImageOrientationUp];
sourceImageLandscape = [self createImage:CGRectMake(0, 0, 3264, 2448) orientation:UIImageOrientationUp];
// test 640x480
targetSize = CGSizeMake(480, 640);
targetImage = [sourceImagePortrait imageByScalingNotCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
targetSize = CGSizeMake(640, 480);
targetImage = [sourceImageLandscape imageByScalingNotCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
// test 800x600
targetSize = CGSizeMake(600, 800);
targetImage = [sourceImagePortrait imageByScalingNotCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
targetSize = CGSizeMake(800, 600);
targetImage = [sourceImageLandscape imageByScalingNotCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
// test 1024x768
targetSize = CGSizeMake(768, 1024);
targetImage = [sourceImagePortrait imageByScalingNotCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
targetSize = CGSizeMake(1024, 768);
targetImage = [sourceImageLandscape imageByScalingNotCroppingForSize:targetSize];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
}
- (void) testImageCorrectedForOrientation {
UIImage *sourceImagePortrait, *sourceImageLandscape, *targetImage;
CGSize targetSize = CGSizeZero;
sourceImagePortrait = [self createImage:CGRectMake(0, 0, 2448, 3264) orientation:UIImageOrientationDown];
sourceImageLandscape = [self createImage:CGRectMake(0, 0, 3264, 2448) orientation:UIImageOrientationDown];
// PORTRAIT - image size should be unchanged
targetSize = CGSizeMake(2448, 3264);
targetImage = [sourceImagePortrait imageCorrectedForCaptureOrientation:UIImageOrientationUp];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
XCTAssertEqual(targetImage.imageOrientation, UIImageOrientationUp);
targetImage = [sourceImagePortrait imageCorrectedForCaptureOrientation:UIImageOrientationDown];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
XCTAssertEqual(targetImage.imageOrientation, UIImageOrientationUp);
targetImage = [sourceImagePortrait imageCorrectedForCaptureOrientation:UIImageOrientationRight];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
XCTAssertEqual(targetImage.imageOrientation, UIImageOrientationUp);
targetImage = [sourceImagePortrait imageCorrectedForCaptureOrientation:UIImageOrientationLeft];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
XCTAssertEqual(targetImage.imageOrientation, UIImageOrientationUp);
// LANDSCAPE - image size should be unchanged
targetSize = CGSizeMake(3264, 2448);
targetImage = [sourceImageLandscape imageCorrectedForCaptureOrientation:UIImageOrientationUp];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
targetImage = [sourceImageLandscape imageCorrectedForCaptureOrientation:UIImageOrientationDown];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
targetImage = [sourceImageLandscape imageCorrectedForCaptureOrientation:UIImageOrientationRight];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
targetImage = [sourceImageLandscape imageCorrectedForCaptureOrientation:UIImageOrientationLeft];
XCTAssertEqual(targetImage.size.width, targetSize.width);
XCTAssertEqual(targetImage.size.height, targetSize.height);
}
- (void) testRetrieveImage
{
CDVPictureOptions* pictureOptions = [[CDVPictureOptions alloc] init];
NSDictionary *infoDict1, *infoDict2;
UIImage* resultImage;
UIImage* originalImage = [self createImage:CGRectMake(0, 0, 1024, 768) orientation:UIImageOrientationDown];
UIImage* originalCorrectedForOrientation = [originalImage imageCorrectedForCaptureOrientation];
UIImage* editedImage = [self createImage:CGRectMake(0, 0, 800, 600) orientation:UIImageOrientationDown];
UIImage* scaledImageWithCrop = [originalImage imageByScalingAndCroppingForSize:CGSizeMake(640, 480)];
UIImage* scaledImageNoCrop = [originalImage imageByScalingNotCroppingForSize:CGSizeMake(640, 480)];
infoDict1 = @{
UIImagePickerControllerOriginalImage : originalImage
};
infoDict2 = @{
UIImagePickerControllerOriginalImage : originalImage,
UIImagePickerControllerEditedImage : editedImage
};
// Original with no options
pictureOptions.allowsEditing = YES;
pictureOptions.targetSize = CGSizeZero;
pictureOptions.cropToSize = NO;
pictureOptions.correctOrientation = NO;
resultImage = [self.plugin retrieveImage:infoDict1 options:pictureOptions];
XCTAssertEqualObjects(resultImage, originalImage);
// Original with no options
pictureOptions.allowsEditing = YES;
pictureOptions.targetSize = CGSizeZero;
pictureOptions.cropToSize = NO;
pictureOptions.correctOrientation = NO;
resultImage = [self.plugin retrieveImage:infoDict2 options:pictureOptions];
XCTAssertEqualObjects(resultImage, editedImage);
// Original with corrected orientation
pictureOptions.allowsEditing = YES;
pictureOptions.targetSize = CGSizeZero;
pictureOptions.cropToSize = NO;
pictureOptions.correctOrientation = YES;
resultImage = [self.plugin retrieveImage:infoDict1 options:pictureOptions];
XCTAssertNotEqual(resultImage.imageOrientation, originalImage.imageOrientation);
XCTAssertEqual(resultImage.imageOrientation, originalCorrectedForOrientation.imageOrientation);
XCTAssertEqual(resultImage.size.width, originalCorrectedForOrientation.size.width);
XCTAssertEqual(resultImage.size.height, originalCorrectedForOrientation.size.height);
// Original with targetSize, no crop
pictureOptions.allowsEditing = YES;
pictureOptions.targetSize = CGSizeMake(640, 480);
pictureOptions.cropToSize = NO;
pictureOptions.correctOrientation = NO;
resultImage = [self.plugin retrieveImage:infoDict1 options:pictureOptions];
XCTAssertEqual(resultImage.size.width, scaledImageNoCrop.size.width);
XCTAssertEqual(resultImage.size.height, scaledImageNoCrop.size.height);
// Original with targetSize, plus crop
pictureOptions.allowsEditing = YES;
pictureOptions.targetSize = CGSizeMake(640, 480);
pictureOptions.cropToSize = YES;
pictureOptions.correctOrientation = NO;
resultImage = [self.plugin retrieveImage:infoDict1 options:pictureOptions];
XCTAssertEqual(resultImage.size.width, scaledImageWithCrop.size.width);
XCTAssertEqual(resultImage.size.height, scaledImageWithCrop.size.height);
}
- (void) testProcessImage
{
CDVPictureOptions* pictureOptions = [[CDVPictureOptions alloc] init];
NSData* resultData;
UIImage* originalImage = [self createImage:CGRectMake(0, 0, 1024, 768) orientation:UIImageOrientationDown];
NSData* originalImageDataPNG = UIImagePNGRepresentation(originalImage);
NSData* originalImageDataJPEG = UIImageJPEGRepresentation(originalImage, 1.0);
// Original, PNG
pictureOptions.allowsEditing = YES;
pictureOptions.targetSize = CGSizeZero;
pictureOptions.cropToSize = NO;
pictureOptions.correctOrientation = NO;
pictureOptions.encodingType = EncodingTypePNG;
resultData = [self.plugin processImage:originalImage info:@{} options:pictureOptions];
XCTAssertEqualObjects([resultData base64EncodedStringWithOptions:0], [originalImageDataPNG base64EncodedStringWithOptions:0]);
// Original, JPEG, full quality
pictureOptions.allowsEditing = NO;
pictureOptions.targetSize = CGSizeZero;
pictureOptions.cropToSize = NO;
pictureOptions.correctOrientation = NO;
pictureOptions.encodingType = EncodingTypeJPEG;
resultData = [self.plugin processImage:originalImage info:@{} options:pictureOptions];
XCTAssertEqualObjects([resultData base64EncodedStringWithOptions:0], [originalImageDataJPEG base64EncodedStringWithOptions:0]);
// Original, JPEG, with quality value
pictureOptions.allowsEditing = YES;
pictureOptions.targetSize = CGSizeZero;
pictureOptions.cropToSize = NO;
pictureOptions.correctOrientation = NO;
pictureOptions.encodingType = EncodingTypeJPEG;
pictureOptions.quality = @(57);
NSData* originalImageDataJPEGWithQuality = UIImageJPEGRepresentation(originalImage, [pictureOptions.quality floatValue]/ 100.f);
resultData = [self.plugin processImage:originalImage info:@{} options:pictureOptions];
XCTAssertEqualObjects([resultData base64EncodedStringWithOptions:0], [originalImageDataJPEGWithQuality base64EncodedStringWithOptions:0]);
// TODO: usesGeolocation is not tested
}
@end

View File

@@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<!--
#
# 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.
#
-->
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>en</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>org.apache.cordova.$(PRODUCT_NAME:rfc1034identifier)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>????</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

View File

@@ -0,0 +1,561 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
30486FEB1A40DC350065C233 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FEA1A40DC350065C233 /* UIKit.framework */; };
30486FED1A40DC3B0065C233 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FEC1A40DC3A0065C233 /* Foundation.framework */; };
30486FF91A40DCC70065C233 /* CDVCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = 30486FF31A40DCC70065C233 /* CDVCamera.m */; };
30486FFA1A40DCC70065C233 /* CDVJpegHeaderWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 30486FF61A40DCC70065C233 /* CDVJpegHeaderWriter.m */; };
30486FFB1A40DCC70065C233 /* UIImage+CropScaleOrientation.m in Sources */ = {isa = PBXBuildFile; fileRef = 30486FF81A40DCC70065C233 /* UIImage+CropScaleOrientation.m */; };
304870011A40DD620065C233 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FFE1A40DD180065C233 /* CoreGraphics.framework */; };
304870021A40DD860065C233 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FFE1A40DD180065C233 /* CoreGraphics.framework */; };
304870031A40DD8C0065C233 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FEA1A40DC350065C233 /* UIKit.framework */; };
304870051A40DD9A0065C233 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304870041A40DD9A0065C233 /* MobileCoreServices.framework */; };
304870071A40DDAC0065C233 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304870061A40DDAC0065C233 /* AssetsLibrary.framework */; };
304870091A40DDB90065C233 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304870081A40DDB90065C233 /* CoreLocation.framework */; };
3048700B1A40DDF30065C233 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3048700A1A40DDF30065C233 /* ImageIO.framework */; };
308F59B11A4228730031A4D4 /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E9F519019DA0F8300DA31AC /* libCordova.a */; };
7E9F51B119DA114400DA31AC /* CameraTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E9F51B019DA114400DA31AC /* CameraTest.m */; };
7E9F51B919DA1B1600DA31AC /* libCDVCameraLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E9F519519DA102000DA31AC /* libCDVCameraLib.a */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
30486FFC1A40DCE80065C233 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */;
proxyType = 1;
remoteGlobalIDString = D2AAC07D0554694100DB518D;
remoteInfo = CordovaLib;
};
7E9F518F19DA0F8300DA31AC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */;
proxyType = 2;
remoteGlobalIDString = 68A32D7114102E1C006B237C;
remoteInfo = CordovaLib;
};
7E9F51AC19DA10DE00DA31AC /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 7E9F517219DA09CE00DA31AC /* Project object */;
proxyType = 1;
remoteGlobalIDString = 7E9F519419DA102000DA31AC;
remoteInfo = CDVCameraLib;
};
/* End PBXContainerItemProxy section */
/* Begin PBXCopyFilesBuildPhase section */
7E9F519319DA102000DA31AC /* CopyFiles */ = {
isa = PBXCopyFilesBuildPhase;
buildActionMask = 2147483647;
dstPath = "include/$(PRODUCT_NAME)";
dstSubfolderSpec = 16;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
30486FEA1A40DC350065C233 /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/UIKit.framework; sourceTree = DEVELOPER_DIR; };
30486FEC1A40DC3A0065C233 /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/Foundation.framework; sourceTree = DEVELOPER_DIR; };
30486FF21A40DCC70065C233 /* CDVCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCamera.h; sourceTree = "<group>"; };
30486FF31A40DCC70065C233 /* CDVCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVCamera.m; sourceTree = "<group>"; };
30486FF41A40DCC70065C233 /* CDVExif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVExif.h; sourceTree = "<group>"; };
30486FF51A40DCC70065C233 /* CDVJpegHeaderWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVJpegHeaderWriter.h; sourceTree = "<group>"; };
30486FF61A40DCC70065C233 /* CDVJpegHeaderWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVJpegHeaderWriter.m; sourceTree = "<group>"; };
30486FF71A40DCC70065C233 /* UIImage+CropScaleOrientation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+CropScaleOrientation.h"; sourceTree = "<group>"; };
30486FF81A40DCC70065C233 /* UIImage+CropScaleOrientation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+CropScaleOrientation.m"; sourceTree = "<group>"; };
30486FFE1A40DD180065C233 /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/CoreGraphics.framework; sourceTree = DEVELOPER_DIR; };
304870041A40DD9A0065C233 /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/MobileCoreServices.framework; sourceTree = DEVELOPER_DIR; };
304870061A40DDAC0065C233 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/AssetsLibrary.framework; sourceTree = DEVELOPER_DIR; };
304870081A40DDB90065C233 /* CoreLocation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreLocation.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/CoreLocation.framework; sourceTree = DEVELOPER_DIR; };
3048700A1A40DDF30065C233 /* ImageIO.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ImageIO.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/ImageIO.framework; sourceTree = DEVELOPER_DIR; };
7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = "../node_modules/cordova-ios/CordovaLib/CordovaLib.xcodeproj"; sourceTree = "<group>"; };
7E9F519519DA102000DA31AC /* libCDVCameraLib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCDVCameraLib.a; sourceTree = BUILT_PRODUCTS_DIR; };
7E9F519F19DA102000DA31AC /* CDVCameraLibTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CDVCameraLibTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
7E9F51A219DA102000DA31AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
7E9F51B019DA114400DA31AC /* CameraTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraTest.m; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
7E9F519219DA102000DA31AC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
308F59B11A4228730031A4D4 /* libCordova.a in Frameworks */,
304870011A40DD620065C233 /* CoreGraphics.framework in Frameworks */,
30486FED1A40DC3B0065C233 /* Foundation.framework in Frameworks */,
30486FEB1A40DC350065C233 /* UIKit.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
7E9F519C19DA102000DA31AC /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
3048700B1A40DDF30065C233 /* ImageIO.framework in Frameworks */,
304870091A40DDB90065C233 /* CoreLocation.framework in Frameworks */,
304870071A40DDAC0065C233 /* AssetsLibrary.framework in Frameworks */,
304870051A40DD9A0065C233 /* MobileCoreServices.framework in Frameworks */,
304870031A40DD8C0065C233 /* UIKit.framework in Frameworks */,
304870021A40DD860065C233 /* CoreGraphics.framework in Frameworks */,
7E9F51B919DA1B1600DA31AC /* libCDVCameraLib.a in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
30486FF11A40DCC70065C233 /* CDVCameraLib */ = {
isa = PBXGroup;
children = (
30486FF21A40DCC70065C233 /* CDVCamera.h */,
30486FF31A40DCC70065C233 /* CDVCamera.m */,
30486FF41A40DCC70065C233 /* CDVExif.h */,
30486FF51A40DCC70065C233 /* CDVJpegHeaderWriter.h */,
30486FF61A40DCC70065C233 /* CDVJpegHeaderWriter.m */,
30486FF71A40DCC70065C233 /* UIImage+CropScaleOrientation.h */,
30486FF81A40DCC70065C233 /* UIImage+CropScaleOrientation.m */,
);
name = CDVCameraLib;
path = ../../../src/ios;
sourceTree = "<group>";
};
308F59B01A4227A60031A4D4 /* Frameworks */ = {
isa = PBXGroup;
children = (
3048700A1A40DDF30065C233 /* ImageIO.framework */,
304870081A40DDB90065C233 /* CoreLocation.framework */,
304870061A40DDAC0065C233 /* AssetsLibrary.framework */,
304870041A40DD9A0065C233 /* MobileCoreServices.framework */,
30486FFE1A40DD180065C233 /* CoreGraphics.framework */,
30486FEC1A40DC3A0065C233 /* Foundation.framework */,
30486FEA1A40DC350065C233 /* UIKit.framework */,
);
name = Frameworks;
sourceTree = "<group>";
};
7E9F517119DA09CE00DA31AC = {
isa = PBXGroup;
children = (
7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */,
308F59B01A4227A60031A4D4 /* Frameworks */,
30486FF11A40DCC70065C233 /* CDVCameraLib */,
7E9F51A019DA102000DA31AC /* CDVCameraLibTests */,
7E9F517D19DA0A0A00DA31AC /* Products */,
);
sourceTree = "<group>";
};
7E9F517D19DA0A0A00DA31AC /* Products */ = {
isa = PBXGroup;
children = (
7E9F519519DA102000DA31AC /* libCDVCameraLib.a */,
7E9F519F19DA102000DA31AC /* CDVCameraLibTests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
7E9F518C19DA0F8300DA31AC /* Products */ = {
isa = PBXGroup;
children = (
7E9F519019DA0F8300DA31AC /* libCordova.a */,
);
name = Products;
sourceTree = "<group>";
};
7E9F51A019DA102000DA31AC /* CDVCameraLibTests */ = {
isa = PBXGroup;
children = (
7E9F51A119DA102000DA31AC /* Supporting Files */,
7E9F51B019DA114400DA31AC /* CameraTest.m */,
);
path = CDVCameraLibTests;
sourceTree = "<group>";
};
7E9F51A119DA102000DA31AC /* Supporting Files */ = {
isa = PBXGroup;
children = (
7E9F51A219DA102000DA31AC /* Info.plist */,
);
name = "Supporting Files";
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
7E9F519419DA102000DA31AC /* CDVCameraLib */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7E9F51A319DA102000DA31AC /* Build configuration list for PBXNativeTarget "CDVCameraLib" */;
buildPhases = (
7E9F519119DA102000DA31AC /* Sources */,
7E9F519219DA102000DA31AC /* Frameworks */,
7E9F519319DA102000DA31AC /* CopyFiles */,
);
buildRules = (
);
dependencies = (
30486FFD1A40DCE80065C233 /* PBXTargetDependency */,
);
name = CDVCameraLib;
productName = CDVCameraLib;
productReference = 7E9F519519DA102000DA31AC /* libCDVCameraLib.a */;
productType = "com.apple.product-type.library.static";
};
7E9F519E19DA102000DA31AC /* CDVCameraLibTests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 7E9F51A619DA102000DA31AC /* Build configuration list for PBXNativeTarget "CDVCameraLibTests" */;
buildPhases = (
7E9F519B19DA102000DA31AC /* Sources */,
7E9F519C19DA102000DA31AC /* Frameworks */,
7E9F519D19DA102000DA31AC /* Resources */,
);
buildRules = (
);
dependencies = (
7E9F51AD19DA10DE00DA31AC /* PBXTargetDependency */,
);
name = CDVCameraLibTests;
productName = CDVCameraLibTests;
productReference = 7E9F519F19DA102000DA31AC /* CDVCameraLibTests.xctest */;
productType = "com.apple.product-type.bundle.unit-test";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
7E9F517219DA09CE00DA31AC /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0610;
TargetAttributes = {
7E9F519419DA102000DA31AC = {
CreatedOnToolsVersion = 6.0;
};
7E9F519E19DA102000DA31AC = {
CreatedOnToolsVersion = 6.0;
};
};
};
buildConfigurationList = 7E9F517519DA09CE00DA31AC /* Build configuration list for PBXProject "CDVCameraTest" */;
compatibilityVersion = "Xcode 3.2";
developmentRegion = English;
hasScannedForEncodings = 0;
knownRegions = (
en,
);
mainGroup = 7E9F517119DA09CE00DA31AC;
productRefGroup = 7E9F517D19DA0A0A00DA31AC /* Products */;
projectDirPath = "";
projectReferences = (
{
ProductGroup = 7E9F518C19DA0F8300DA31AC /* Products */;
ProjectRef = 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */;
},
);
projectRoot = "";
targets = (
7E9F519419DA102000DA31AC /* CDVCameraLib */,
7E9F519E19DA102000DA31AC /* CDVCameraLibTests */,
);
};
/* End PBXProject section */
/* Begin PBXReferenceProxy section */
7E9F519019DA0F8300DA31AC /* libCordova.a */ = {
isa = PBXReferenceProxy;
fileType = archive.ar;
path = libCordova.a;
remoteRef = 7E9F518F19DA0F8300DA31AC /* PBXContainerItemProxy */;
sourceTree = BUILT_PRODUCTS_DIR;
};
/* End PBXReferenceProxy section */
/* Begin PBXResourcesBuildPhase section */
7E9F519D19DA102000DA31AC /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
7E9F519119DA102000DA31AC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
30486FF91A40DCC70065C233 /* CDVCamera.m in Sources */,
30486FFB1A40DCC70065C233 /* UIImage+CropScaleOrientation.m in Sources */,
30486FFA1A40DCC70065C233 /* CDVJpegHeaderWriter.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
7E9F519B19DA102000DA31AC /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
7E9F51B119DA114400DA31AC /* CameraTest.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin PBXTargetDependency section */
30486FFD1A40DCE80065C233 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
name = CordovaLib;
targetProxy = 30486FFC1A40DCE80065C233 /* PBXContainerItemProxy */;
};
7E9F51AD19DA10DE00DA31AC /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 7E9F519419DA102000DA31AC /* CDVCameraLib */;
targetProxy = 7E9F51AC19DA10DE00DA31AC /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */
/* Begin XCBuildConfiguration section */
7E9F517619DA09CE00DA31AC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ONLY_ACTIVE_ARCH = YES;
};
name = Debug;
};
7E9F517719DA09CE00DA31AC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
};
name = Release;
};
7E9F51A419DA102000DA31AC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"",
"\"$(OBJROOT)/UninstalledProducts/include\"",
"\"$(BUILT_PRODUCTS_DIR)\"",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
};
name = Debug;
};
7E9F51A519DA102000DA31AC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
HEADER_SEARCH_PATHS = (
"$(inherited)",
"\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"",
"\n\"$(OBJROOT)/UninstalledProducts/include\"\n\"$(BUILT_PRODUCTS_DIR)\"",
);
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = "-ObjC";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
SKIP_INSTALL = YES;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
7E9F51A719DA102000DA31AC /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_DYNAMIC_NO_PIC = NO;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_SYMBOLS_PRIVATE_EXTERN = NO;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = CDVCameraLibTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
XCTest,
"-all_load",
"-ObjC",
);
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
};
name = Debug;
};
7E9F51A819DA102000DA31AC /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = YES;
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
);
GCC_C_LANGUAGE_STANDARD = gnu99;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
INFOPLIST_FILE = CDVCameraLibTests/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
MTL_ENABLE_DEBUG_INFO = NO;
OTHER_LDFLAGS = (
"$(inherited)",
"-framework",
XCTest,
"-all_load",
"-ObjC",
);
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
7E9F517519DA09CE00DA31AC /* Build configuration list for PBXProject "CDVCameraTest" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7E9F517619DA09CE00DA31AC /* Debug */,
7E9F517719DA09CE00DA31AC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7E9F51A319DA102000DA31AC /* Build configuration list for PBXNativeTarget "CDVCameraLib" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7E9F51A419DA102000DA31AC /* Debug */,
7E9F51A519DA102000DA31AC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
7E9F51A619DA102000DA31AC /* Build configuration list for PBXNativeTarget "CDVCameraLibTests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
7E9F51A719DA102000DA31AC /* Debug */,
7E9F51A819DA102000DA31AC /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 7E9F517219DA09CE00DA31AC /* Project object */;
}

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:CDVCameraTest.xcodeproj">
</FileRef>
</Workspace>

View File

@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDESourceControlProjectFavoriteDictionaryKey</key>
<false/>
<key>IDESourceControlProjectIdentifier</key>
<string>6BE9AD73-1B9F-4362-98D7-DC631BEC6185</string>
<key>IDESourceControlProjectName</key>
<string>CDVCameraTest</string>
<key>IDESourceControlProjectOriginsDictionary</key>
<dict>
<key>BEF5A5D0FF64801E558286389440357A9233D7DB</key>
<string>https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git</string>
</dict>
<key>IDESourceControlProjectPath</key>
<string>tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj</string>
<key>IDESourceControlProjectRelativeInstallPathDictionary</key>
<dict>
<key>BEF5A5D0FF64801E558286389440357A9233D7DB</key>
<string>../../../../..</string>
</dict>
<key>IDESourceControlProjectURL</key>
<string>https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git</string>
<key>IDESourceControlProjectVersion</key>
<integer>111</integer>
<key>IDESourceControlProjectWCCIdentifier</key>
<string>BEF5A5D0FF64801E558286389440357A9233D7DB</string>
<key>IDESourceControlProjectWCConfigurations</key>
<array>
<dict>
<key>IDESourceControlRepositoryExtensionIdentifierKey</key>
<string>public.vcs.git</string>
<key>IDESourceControlWCCIdentifierKey</key>
<string>BEF5A5D0FF64801E558286389440357A9233D7DB</string>
<key>IDESourceControlWCCName</key>
<string>cordova-plugin-camera</string>
</dict>
</array>
</dict>
</plist>

View File

@@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0610"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7E9F519419DA102000DA31AC"
BuildableName = "libCDVCameraLib.a"
BlueprintName = "CDVCameraLib"
ReferencedContainer = "container:CDVCameraTest.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
</Testables>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7E9F519419DA102000DA31AC"
BuildableName = "libCDVCameraLib.a"
BlueprintName = "CDVCameraLib"
ReferencedContainer = "container:CDVCameraTest.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7E9F519419DA102000DA31AC"
BuildableName = "libCDVCameraLib.a"
BlueprintName = "CDVCameraLib"
ReferencedContainer = "container:CDVCameraTest.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

View File

@@ -0,0 +1,96 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0610"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "NO"
buildForArchiving = "NO"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7E9F519E19DA102000DA31AC"
BuildableName = "CDVCameraLibTests.xctest"
BlueprintName = "CDVCameraLibTests"
ReferencedContainer = "container:CDVCameraTest.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
buildConfiguration = "Debug">
<Testables>
<TestableReference
skipped = "NO">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7E9F519E19DA102000DA31AC"
BuildableName = "CDVCameraLibTests.xctest"
BlueprintName = "CDVCameraLibTests"
ReferencedContainer = "container:CDVCameraTest.xcodeproj">
</BuildableReference>
</TestableReference>
</Testables>
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7E9F519E19DA102000DA31AC"
BuildableName = "CDVCameraLibTests.xctest"
BlueprintName = "CDVCameraLibTests"
ReferencedContainer = "container:CDVCameraTest.xcodeproj">
</BuildableReference>
</MacroExpansion>
</TestAction>
<LaunchAction
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
buildConfiguration = "Debug"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
allowLocationSimulation = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7E9F519E19DA102000DA31AC"
BuildableName = "CDVCameraLibTests.xctest"
BlueprintName = "CDVCameraLibTests"
ReferencedContainer = "container:CDVCameraTest.xcodeproj">
</BuildableReference>
</MacroExpansion>
<AdditionalOptions>
</AdditionalOptions>
</LaunchAction>
<ProfileAction
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
buildConfiguration = "Release"
debugDocumentVersioning = "YES">
<MacroExpansion>
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "7E9F519E19DA102000DA31AC"
BuildableName = "CDVCameraLibTests.xctest"
BlueprintName = "CDVCameraLibTests"
ReferencedContainer = "container:CDVCameraTest.xcodeproj">
</BuildableReference>
</MacroExpansion>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>

40
tests/ios/README.md Normal file
View File

@@ -0,0 +1,40 @@
<!---
license: 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.
-->
# iOS Tests for CDVCamera
You need to install `node.js` to pull in `cordova-ios`.
First install cordova-ios:
npm install
... in the current folder.
# Testing from Xcode
1. Launch the `CDVCameraTest.xcworkspace` file.
2. Choose "CDVCameraLibTests" from the scheme drop-down menu
3. Click and hold on the `Play` button, and choose the `Wrench` icon to run the tests
# Testing from the command line
npm test

13
tests/ios/package.json Normal file
View File

@@ -0,0 +1,13 @@
{
"name": "cordova-plugin-camera-test-ios",
"version": "1.0.0",
"description": "iOS Unit Tests for Camera Plugin",
"author": "Apache Software Foundation",
"license": "Apache Version 2.0",
"dependencies": {
"cordova-ios": "*"
},
"scripts": {
"test": "xcodebuild -scheme CordovaLib && xcodebuild test -scheme CDVCameraLibTests -destination 'platform=iOS Simulator,name=iPhone 5s'"
}
}

14
tests/package.json Normal file
View File

@@ -0,0 +1,14 @@
{
"name": "cordova-plugin-camera-tests",
"version": "4.2.0-dev",
"description": "",
"cordova": {
"id": "cordova-plugin-camera-tests",
"platforms": []
},
"keywords": [
"ecosystem:cordova"
],
"author": "",
"license": "Apache-2.0"
}

33
tests/plugin.xml Normal file
View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
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.
-->
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:rim="http://www.blackberry.com/ns/widgets"
id="cordova-plugin-camera-tests"
version="4.2.0-dev">
<name>Cordova Camera Plugin Tests</name>
<license>Apache 2.0</license>
<dependency id="cordova-plugin-file-transfer" />
<js-module src="tests.js" name="tests">
</js-module>
</plugin>

512
tests/tests.js Normal file
View File

@@ -0,0 +1,512 @@
/*
*
* 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.
*
*/
/* globals Camera, resolveLocalFileSystemURL, FileEntry, CameraPopoverOptions, FileTransfer, FileUploadOptions, LocalFileSystem, MSApp */
/* eslint-env jasmine */
exports.defineAutoTests = function () {
describe('Camera (navigator.camera)', function () {
it('should exist', function () {
expect(navigator.camera).toBeDefined();
});
it('should contain a getPicture function', function () {
expect(navigator.camera.getPicture).toBeDefined();
expect(typeof navigator.camera.getPicture === 'function').toBe(true);
});
});
describe('Camera Constants (window.Camera + navigator.camera)', function () {
it('camera.spec.1 window.Camera should exist', function () {
expect(window.Camera).toBeDefined();
});
it('camera.spec.2 should contain three DestinationType constants', function () {
expect(Camera.DestinationType.DATA_URL).toBe(0);
expect(Camera.DestinationType.FILE_URI).toBe(1);
expect(Camera.DestinationType.NATIVE_URI).toBe(2);
expect(navigator.camera.DestinationType.DATA_URL).toBe(0);
expect(navigator.camera.DestinationType.FILE_URI).toBe(1);
expect(navigator.camera.DestinationType.NATIVE_URI).toBe(2);
});
it('camera.spec.3 should contain two EncodingType constants', function () {
expect(Camera.EncodingType.JPEG).toBe(0);
expect(Camera.EncodingType.PNG).toBe(1);
expect(navigator.camera.EncodingType.JPEG).toBe(0);
expect(navigator.camera.EncodingType.PNG).toBe(1);
});
it('camera.spec.4 should contain three MediaType constants', function () {
expect(Camera.MediaType.PICTURE).toBe(0);
expect(Camera.MediaType.VIDEO).toBe(1);
expect(Camera.MediaType.ALLMEDIA).toBe(2);
expect(navigator.camera.MediaType.PICTURE).toBe(0);
expect(navigator.camera.MediaType.VIDEO).toBe(1);
expect(navigator.camera.MediaType.ALLMEDIA).toBe(2);
});
it('camera.spec.5 should contain three PictureSourceType constants', function () {
expect(Camera.PictureSourceType.PHOTOLIBRARY).toBe(0);
expect(Camera.PictureSourceType.CAMERA).toBe(1);
expect(Camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2);
expect(navigator.camera.PictureSourceType.PHOTOLIBRARY).toBe(0);
expect(navigator.camera.PictureSourceType.CAMERA).toBe(1);
expect(navigator.camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2);
});
});
};
/******************************************************************************/
/******************************************************************************/
/******************************************************************************/
exports.defineManualTests = function (contentEl, createActionButton) {
var pictureUrl = null;
var fileObj = null;
var fileEntry = null;
var pageStartTime = +new Date();
// default camera options
var camQualityDefault = ['50', 50];
var camDestinationTypeDefault = ['FILE_URI', 1];
var camPictureSourceTypeDefault = ['CAMERA', 1];
var camAllowEditDefault = ['allowEdit', false];
var camEncodingTypeDefault = ['JPEG', 0];
var camMediaTypeDefault = ['mediaType', 0];
var camCorrectOrientationDefault = ['correctOrientation', false];
var camSaveToPhotoAlbumDefault = ['saveToPhotoAlbum', true];
function log (value) {
console.log(value);
document.getElementById('camera_status').textContent += (new Date() - pageStartTime) / 1000 + ': ' + value + '\n';
}
function clearStatus () {
document.getElementById('camera_status').innerHTML = '';
document.getElementById('camera_image').src = 'about:blank';
var canvas = document.getElementById('canvas');
canvas.width = canvas.height = 1;
pictureUrl = null;
fileObj = null;
fileEntry = null;
}
function setPicture (url, callback) {
try {
window.atob(url);
// if we got here it is a base64 string (DATA_URL)
url = 'data:image/jpeg;base64,' + url;
} catch (e) {
// not DATA_URL
}
log('URL: "' + url.slice(0, 90) + '"');
pictureUrl = url;
var img = document.getElementById('camera_image');
var startTime = new Date();
img.src = url;
img.onload = function () {
log('Img size: ' + img.naturalWidth + 'x' + img.naturalHeight);
log('Image tag load time: ' + (new Date() - startTime));
if (callback) {
callback();
}
};
}
function onGetPictureError (e) {
log('Error getting picture: ' + (e.code || e));
}
function getPictureWin (data) {
setPicture(data);
// TODO: Fix resolveLocalFileSystemURI to work with native-uri.
if (pictureUrl.indexOf('file:') === 0 || pictureUrl.indexOf('content:') === 0 || pictureUrl.indexOf('ms-appdata:') === 0 || pictureUrl.indexOf('assets-library:') === 0) {
resolveLocalFileSystemURL(data, function (e) {
fileEntry = e;
logCallback('resolveLocalFileSystemURL()', true)(e.toURL());
readFile();
}, logCallback('resolveLocalFileSystemURL()', false));
} else if (pictureUrl.indexOf('data:image/jpeg;base64') === 0) {
// do nothing
} else {
var path = pictureUrl.replace(/^file:\/\/(localhost)?/, '').replace(/%20/g, ' ');
fileEntry = new FileEntry('image_name.png', path);
}
}
function getPicture () {
clearStatus();
var options = extractOptions();
log('Getting picture with options: ' + JSON.stringify(options));
var popoverHandle = navigator.camera.getPicture(getPictureWin, onGetPictureError, options);
// Reposition the popover if the orientation changes.
window.onorientationchange = function () {
var newPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, 0, 300, 400);
popoverHandle.setPosition(newPopoverOptions);
};
}
function uploadImage () {
var ft = new FileTransfer();
var options = new FileUploadOptions();
options.fileKey = 'photo';
options.fileName = 'test.jpg';
options.mimeType = 'image/jpeg';
ft.onprogress = function (progressEvent) {
console.log('progress: ' + progressEvent.loaded + ' of ' + progressEvent.total);
};
var server = 'http://sheltered-retreat-43956.herokuapp.com';
ft.upload(pictureUrl, server + '/upload', win, fail, options);
function win (information_back) {
log('upload complete');
}
function fail (message) {
log('upload failed: ' + JSON.stringify(message));
}
}
function logCallback (apiName, success) {
return function () {
log('Call to ' + apiName + (success ? ' success: ' : ' failed: ') + JSON.stringify([].slice.call(arguments)));
};
}
/**
* Select image from library using a NATIVE_URI destination type
* This calls FileEntry.getMetadata, FileEntry.setMetadata, FileEntry.getParent, FileEntry.file, and FileReader.readAsDataURL.
*/
function readFile () {
function onFileReadAsDataURL (evt) {
var img = document.getElementById('camera_image');
img.style.visibility = 'visible';
img.style.display = 'block';
img.src = evt.target.result;
log('FileReader.readAsDataURL success');
}
function onFileReceived (file) {
log('Got file: ' + JSON.stringify(file));
fileObj = file;
/* eslint-disable no-undef */
var reader = new FileReader();
/* eslint-enable no-undef */
reader.onload = function () {
log('FileReader.readAsDataURL() - length = ' + reader.result.length);
};
reader.onerror = logCallback('FileReader.readAsDataURL', false);
reader.onloadend = onFileReadAsDataURL;
reader.readAsDataURL(file);
}
// Test out onFileReceived when the file object was set via a native <input> elements.
if (fileObj) {
onFileReceived(fileObj);
} else {
fileEntry.file(onFileReceived, logCallback('FileEntry.file', false));
}
}
function getFileInfo () {
// Test FileEntry API here.
fileEntry.getMetadata(logCallback('FileEntry.getMetadata', true), logCallback('FileEntry.getMetadata', false));
fileEntry.setMetadata(logCallback('FileEntry.setMetadata', true), logCallback('FileEntry.setMetadata', false), { 'com.apple.MobileBackup': 1 });
fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false));
fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false));
}
/**
* Copy image from library using a NATIVE_URI destination type
* This calls FileEntry.copyTo and FileEntry.moveTo.
*/
function copyImage () {
var onFileSystemReceived = function (fileSystem) {
var destDirEntry = fileSystem.root;
var origName = fileEntry.name;
// Test FileEntry API here.
fileEntry.copyTo(destDirEntry, 'copied_file.png', logCallback('FileEntry.copyTo', true), logCallback('FileEntry.copyTo', false));
fileEntry.moveTo(destDirEntry, 'moved_file.png', logCallback('FileEntry.moveTo', true), logCallback('FileEntry.moveTo', false));
// cleanup
// rename moved file back to original name so other tests can reference image
resolveLocalFileSystemURL(destDirEntry.nativeURL + 'moved_file.png', function (fileEntry) {
fileEntry.moveTo(destDirEntry, origName, logCallback('FileEntry.moveTo', true), logCallback('FileEntry.moveTo', false));
console.log('Cleanup: successfully renamed file back to original name');
}, function () {
console.log('Cleanup: failed to rename file back to original name');
});
// remove copied file
resolveLocalFileSystemURL(destDirEntry.nativeURL + 'copied_file.png', function (fileEntry) {
fileEntry.remove(logCallback('FileEntry.remove', true), logCallback('FileEntry.remove', false));
console.log('Cleanup: successfully removed copied file');
}, function () {
console.log('Cleanup: failed to remove copied file');
});
};
window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, onFileSystemReceived, null);
}
/**
* Write image to library using a NATIVE_URI destination type
* This calls FileEntry.createWriter, FileWriter.write, and FileWriter.truncate.
*/
function writeImage () {
var onFileWriterReceived = function (fileWriter) {
fileWriter.onwrite = logCallback('FileWriter.write', true);
fileWriter.onerror = logCallback('FileWriter.write', false);
fileWriter.write('some text!');
};
var onFileTruncateWriterReceived = function (fileWriter) {
fileWriter.onwrite = logCallback('FileWriter.truncate', true);
fileWriter.onerror = logCallback('FileWriter.truncate', false);
fileWriter.truncate(10);
};
fileEntry.createWriter(onFileWriterReceived, logCallback('FileEntry.createWriter', false));
fileEntry.createWriter(onFileTruncateWriterReceived, null);
}
function displayImageUsingCanvas () {
var canvas = document.getElementById('canvas');
var img = document.getElementById('camera_image');
var w = img.width;
var h = img.height;
h = 100 / w * h;
w = 100;
canvas.width = w;
canvas.height = h;
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, w, h);
}
/**
* Remove image from library using a NATIVE_URI destination type
* This calls FileEntry.remove.
*/
function removeImage () {
fileEntry.remove(logCallback('FileEntry.remove', true), logCallback('FileEntry.remove', false));
}
function testInputTag (inputEl) {
clearStatus();
// iOS 6 likes to dead-lock in the onchange context if you
// do any alerts or try to remote-debug.
window.setTimeout(function () {
testNativeFile2(inputEl);
}, 0);
}
function testNativeFile2 (inputEl) {
/* eslint-disable no-undef */
if (!inputEl.value) {
alert('No file selected.');
return;
}
fileObj = inputEl.files[0];
if (!fileObj) {
alert('Got value but no file.');
return;
}
/* eslint-enable no-undef */
var URLApi = window.URL || window.webkitURL;
if (URLApi) {
var blobURL = URLApi.createObjectURL(fileObj);
if (blobURL) {
setPicture(blobURL, function () {
URLApi.revokeObjectURL(blobURL);
});
} else {
log('URL.createObjectURL returned null');
}
} else {
log('URL.createObjectURL() not supported.');
}
}
function extractOptions () {
var els = document.querySelectorAll('#image-options select');
var ret = {};
/* eslint-disable no-cond-assign */
for (var i = 0, el; el = els[i]; ++i) {
var value = el.value;
if (value === '') continue;
value = +value;
if (el.isBool) {
ret[el.getAttribute('name')] = !!value;
} else {
ret[el.getAttribute('name')] = value;
}
}
/* eslint-enable no-cond-assign */
return ret;
}
function createOptionsEl (name, values, selectionDefault) {
var openDiv = '<div style="display: inline-block">' + name + ': ';
var select = '<select name=' + name + ' id="' + name + '">';
var defaultOption = '';
if (selectionDefault === undefined) {
defaultOption = '<option value="">default</option>';
}
var options = '';
if (typeof values === 'boolean') {
values = { 'true': 1, 'false': 0 };
}
for (var k in values) {
var isSelected = '';
if (selectionDefault) {
if (selectionDefault[0] === k) {
isSelected = 'selected';
}
}
options += '<option value="' + values[k] + '" ' + isSelected + '>' + k + '</option>';
}
var closeDiv = '</select></div>';
return openDiv + select + defaultOption + options + closeDiv;
}
/******************************************************************************/
var info_div = '<h1>Camera</h1>' +
'<div id="info">' +
'<b>Status:</b> <div id="camera_status"></div>' +
'img: <img width="100" id="camera_image">' +
'canvas: <canvas id="canvas" width="1" height="1"></canvas>' +
'</div>';
var options_div = '<h2>Cordova Camera API Options</h2>' +
'<div id="image-options">' +
createOptionsEl('sourceType', Camera.PictureSourceType, camPictureSourceTypeDefault) +
createOptionsEl('destinationType', Camera.DestinationType, camDestinationTypeDefault) +
createOptionsEl('encodingType', Camera.EncodingType, camEncodingTypeDefault) +
createOptionsEl('mediaType', Camera.MediaType, camMediaTypeDefault) +
createOptionsEl('quality', { '0': 0, '50': 50, '80': 80, '100': 100 }, camQualityDefault) +
createOptionsEl('targetWidth', { '50': 50, '200': 200, '800': 800, '2048': 2048 }) +
createOptionsEl('targetHeight', { '50': 50, '200': 200, '800': 800, '2048': 2048 }) +
createOptionsEl('allowEdit', true, camAllowEditDefault) +
createOptionsEl('correctOrientation', true, camCorrectOrientationDefault) +
createOptionsEl('saveToPhotoAlbum', true, camSaveToPhotoAlbumDefault) +
createOptionsEl('cameraDirection', Camera.Direction) +
'</div>';
var getpicture_div = '<div id="getpicture"></div>';
var test_procedure = '<h4>Recommended Test Procedure</h4>' +
'Options not specified should be the default value' +
'<br>Status box should update with image and info whenever an image is taken or selected from library' +
'</p><div style="background:#B0C4DE;border:1px solid #FFA07A;margin:15px 6px 0px;min-width:295px;max-width:97%;padding:4px 0px 2px 10px;min-height:160px;max-height:200px;overflow:auto">' +
'<ol> <li>All default options. Should be able to edit once picture is taken and will be saved to library.</li>' +
'</p><li>sourceType=PHOTOLIBRARY<br>Should be able to see picture that was just taken in previous test and edit when selected</li>' +
'</p><li>sourceType=Camera<br>allowEdit=false<br>saveToPhotoAlbum=false<br>Should not be able to edit when taken and will not save to library</li>' +
'</p><li>encodingType=PNG<br>allowEdit=true<br>saveToPhotoAlbum=true<br>cameraDirection=FRONT<br>Should bring up front camera. Verify in status box info URL that image is encoded as PNG.</li>' +
'</p><li>sourceType=SAVEDPHOTOALBUM<br>mediaType=VIDEO<br>Should only be able to select a video</li>' +
'</p><li>sourceType=SAVEDPHOTOALBUM<br>mediaType=PICTURE<br>allowEdit=false<br>Should only be able to select a picture and not edit</li>' +
'</p><li>sourceType=PHOTOLIBRARY<br>mediaType=ALLMEDIA<br>allowEdit=true<br>Should be able to select pics and videos and edit picture if selected</li>' +
'</p><li>sourceType=CAMERA<br>targetWidth & targetHeight=50<br>allowEdit=false<br>Do Get File Metadata test below and take note of size<br>Repeat test but with width and height=800. Size should be significantly larger.</li>' +
'</p><li>quality=0<br>targetWidth & targetHeight=default<br>allowEdit=false<br>Do Get File Metadata test below and take note of size<br>Repeat test but with quality=80. Size should be significantly larger.</li>' +
'</ol></div>';
var inputs_div = '<h2>Native File Inputs</h2>' +
'For the following tests, status box should update with file selected' +
'</p><div>input type=file <input type="file" class="testInputTag"></div>' +
'<div>capture=camera <input type="file" accept="image/*;capture=camera" class="testInputTag"></div>' +
'<div>capture=camcorder <input type="file" accept="video/*;capture=camcorder" class="testInputTag"></div>' +
'<div>capture=microphone <input type="file" accept="audio/*;capture=microphone" class="testInputTag"></div>';
var actions_div = '<h2>Actions</h2>' +
'For the following tests, ensure that an image is set in status box' +
'</p><div id="metadata"></div>' +
'Expected result: Get metadata about file selected.<br>Status box will show, along with the metadata, "Call to FileEntry.getMetadata success, Call to FileEntry.setMetadata success, Call to FileEntry.getParent success"' +
'</p><div id="reader"></div>' +
'Expected result: Read contents of file.<br>Status box will show "Got file: {some metadata}, FileReader.readAsDataURL() - length = someNumber"' +
'</p><div id="copy"></div>' +
'Expected result: Copy image to new location and move file to different location.<br>Status box will show "Call to FileEntry.copyTo success:{some metadata}, Call to FileEntry.moveTo success:{some metadata}"' +
'</p><div id="write"></div>' +
'Expected result: Write image to library.<br>Status box will show "Call to FileWriter.write success:{some metadata}, Call to FileWriter.truncate success:{some metadata}"' +
'</p><div id="upload"></div>' +
'Expected result: Upload image to server.<br>Status box may print out progress. Once finished will show "upload complete"' +
'</p><div id="draw_canvas"></div>' +
'Expected result: Display image using canvas.<br>Image will be displayed in status box under "canvas:"' +
'</p><div id="remove"></div>' +
'Expected result: Remove image from library.<br>Status box will show "FileEntry.remove success:["OK"]';
// We need to wrap this code due to Windows security restrictions
// see http://msdn.microsoft.com/en-us/library/windows/apps/hh465380.aspx#differences for details
if (window.MSApp && window.MSApp.execUnsafeLocalFunction) {
MSApp.execUnsafeLocalFunction(function () {
contentEl.innerHTML = info_div + options_div + getpicture_div + test_procedure + inputs_div + actions_div;
});
} else {
contentEl.innerHTML = info_div + options_div + getpicture_div + test_procedure + inputs_div + actions_div;
}
var elements = document.getElementsByClassName('testInputTag');
var listener = function (e) {
testInputTag(e.target);
};
for (var i = 0; i < elements.length; ++i) {
var item = elements[i];
item.addEventListener('change', listener, false);
}
createActionButton('Get picture', function () {
getPicture();
}, 'getpicture');
createActionButton('Clear Status', function () {
clearStatus();
}, 'getpicture');
createActionButton('Get File Metadata', function () {
getFileInfo();
}, 'metadata');
createActionButton('Read with FileReader', function () {
readFile();
}, 'reader');
createActionButton('Copy Image', function () {
copyImage();
}, 'copy');
createActionButton('Write Image', function () {
writeImage();
}, 'write');
createActionButton('Upload Image', function () {
uploadImage();
}, 'upload');
createActionButton('Draw Using Canvas', function () {
displayImageUsingCanvas();
}, 'draw_canvas');
createActionButton('Remove Image', function () {
removeImage();
}, 'remove');
};

180
types/index.d.ts vendored Normal file
View File

@@ -0,0 +1,180 @@
// Type definitions for Apache Cordova Camera plugin
// Project: https://github.com/apache/cordova-plugin-camera
// Definitions by: Microsoft Open Technologies Inc <http://msopentech.com>
// Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped
//
// Copyright (c) Microsoft Open Technologies Inc
// Licensed under the MIT license.
interface Navigator {
/**
* This plugin provides an API for taking pictures and for choosing images from the system's image library.
*/
camera: Camera;
}
/**
* This plugin provides an API for taking pictures and for choosing images from the system's image library.
*/
interface Camera {
/**
* Removes intermediate photos taken by the camera from temporary storage.
* @param onSuccess Success callback, that called when cleanup succeeds.
* @param onError Error callback, that get an error message.
*/
cleanup(
onSuccess: () => void,
onError: (message: string) => void): void;
/**
* Takes a photo using the camera, or retrieves a photo from the device's image gallery.
* @param cameraSuccess Success callback, that get the image
* as a base64-encoded String, or as the URI for the image file.
* @param cameraError Error callback, that get an error message.
* @param cameraOptions Optional parameters to customize the camera settings.
*/
getPicture(
cameraSuccess: (data: string) => void,
cameraError: (message: string) => void,
cameraOptions?: CameraOptions): void;
// Next will work only on iOS
//getPicture(
// cameraSuccess: (data: string) => void,
// cameraError: (message: string) => void,
// cameraOptions?: CameraOptions): CameraPopoverHandle;
}
interface CameraOptions {
/** Picture quality in range 0-100. Default is 50 */
quality?: number;
/**
* Choose the format of the return value.
* Defined in navigator.camera.DestinationType. Default is FILE_URI.
* 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)
*/
destinationType?: number;
/**
* Set the source of the picture.
* Defined in navigator.camera.PictureSourceType. Default is CAMERA.
* PHOTOLIBRARY : 0,
* CAMERA : 1,
* SAVEDPHOTOALBUM : 2
*/
sourceType?: number;
/** Allow simple editing of image before selection. */
allowEdit?: boolean;
/**
* Choose the returned image file's encoding.
* Defined in navigator.camera.EncodingType. Default is JPEG
* JPEG : 0 Return JPEG encoded image
* PNG : 1 Return PNG encoded image
*/
encodingType?: number;
/**
* Width in pixels to scale image. Must be used with targetHeight.
* Aspect ratio remains constant.
*/
targetWidth?: number;
/**
* Height in pixels to scale image. Must be used with targetWidth.
* Aspect ratio remains constant.
*/
targetHeight?: number;
/**
* Set the type of media to select from. Only works when PictureSourceType
* is PHOTOLIBRARY or SAVEDPHOTOALBUM. Defined in nagivator.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
*/
mediaType?: number;
/** Rotate the image to correct for the orientation of the device during capture. */
correctOrientation?: boolean;
/** Save the image to the photo album on the device after capture. */
saveToPhotoAlbum?: boolean;
/**
* Choose the camera to use (front- or back-facing).
* Defined in navigator.camera.Direction. Default is BACK.
* FRONT: 0
* BACK: 1
*/
cameraDirection?: number;
/** iOS-only options that specify popover location in iPad. Defined in CameraPopoverOptions. */
popoverOptions?: CameraPopoverOptions;
}
/**
* A handle to the popover dialog created by navigator.camera.getPicture. Used on iOS only.
*/
interface CameraPopoverHandle {
/**
* Set the position of the popover.
* @param popoverOptions the CameraPopoverOptions that specify the new position.
*/
setPosition(popoverOptions: CameraPopoverOptions): void;
}
/**
* 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.
*/
interface CameraPopoverOptions {
x: number;
y: number;
width: number;
height: number;
/**
* Direction the arrow on the popover should point. Defined in Camera.PopoverArrowDirection
* Matches iOS UIPopoverArrowDirection constants.
* ARROW_UP : 1,
* ARROW_DOWN : 2,
* ARROW_LEFT : 4,
* ARROW_RIGHT : 8,
* ARROW_ANY : 15
*/
arrowDir : number;
popoverWidth: number;
popoverHeight: number;
}
declare class CameraPopoverOptions implements CameraPopoverOptions {
constructor(x?: number, y?: number, width?: number, height?: number, arrowDir?: number);
}
declare var Camera: {
// Camera constants, defined in Camera plugin
DestinationType: {
DATA_URL: number;
FILE_URI: number;
NATIVE_URI: number
}
Direction: {
BACK: number;
FRONT: number;
}
EncodingType: {
JPEG: number;
PNG: number;
}
MediaType: {
PICTURE: number;
VIDEO: number;
ALLMEDIA: number;
}
PictureSourceType: {
PHOTOLIBRARY: number;
CAMERA: number;
SAVEDPHOTOALBUM: number;
}
// Used only on iOS
PopoverArrowDirection: {
ARROW_UP: number;
ARROW_DOWN: number;
ARROW_LEFT: number;
ARROW_RIGHT: number;
ARROW_ANY: number;
}
};

View File

@@ -19,12 +19,19 @@
*
*/
var argscheck = require('cordova/argscheck'),
exec = require('cordova/exec'),
Camera = require('./Camera');
// XXX: commented out
//CameraPopoverHandle = require('./CameraPopoverHandle');
var argscheck = require('cordova/argscheck');
var exec = require('cordova/exec');
var Camera = require('./Camera');
// XXX: commented out
// CameraPopoverHandle = require('./CameraPopoverHandle');
/**
* @namespace navigator
*/
/**
* @exports camera
*/
var cameraExport = {};
// Tack on the Camera Constants to the base camera plugin.
@@ -33,21 +40,103 @@ for (var key in Camera) {
}
/**
* 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
* Callback function that provides an error message.
* @callback module:camera.onError
* @param {string} message - The message is provided by the device's native code.
*/
cameraExport.getPicture = function(successCallback, errorCallback, options) {
/**
* Callback function that provides the image data.
* @callback module:camera.onSuccess
* @param {string} imageData - Base64 encoding of the image data, _or_ the image file URI, depending on [`cameraOptions`]{@link module:camera.CameraOptions} in effect.
* @example
* // Show image
* //
* function cameraCallback(imageData) {
* var image = document.getElementById('myImage');
* image.src = "data:image/jpeg;base64," + imageData;
* }
*/
/**
* Optional parameters to customize the camera settings.
* * [Quirks](#CameraOptions-quirks)
* @typedef module:camera.CameraOptions
* @type {Object}
* @property {number} [quality=50] - Quality of the saved image, expressed as a range of 0-100, where 100 is typically full resolution with no loss from file compression. (Note that information about the camera's resolution is unavailable.)
* @property {module:Camera.DestinationType} [destinationType=FILE_URI] - Choose the format of the return value.
* @property {module:Camera.PictureSourceType} [sourceType=CAMERA] - Set the source of the picture.
* @property {Boolean} [allowEdit=false] - Allow simple editing of image before selection.
* @property {module:Camera.EncodingType} [encodingType=JPEG] - Choose the returned image file's encoding.
* @property {number} [targetWidth] - Width in pixels to scale image. Must be used with `targetHeight`. Aspect ratio remains constant.
* @property {number} [targetHeight] - Height in pixels to scale image. Must be used with `targetWidth`. Aspect ratio remains constant.
* @property {module:Camera.MediaType} [mediaType=PICTURE] - Set the type of media to select from. Only works when `PictureSourceType` is `PHOTOLIBRARY` or `SAVEDPHOTOALBUM`.
* @property {Boolean} [correctOrientation] - Rotate the image to correct for the orientation of the device during capture.
* @property {Boolean} [saveToPhotoAlbum] - Save the image to the photo album on the device after capture.
* @property {module:CameraPopoverOptions} [popoverOptions] - iOS-only options that specify popover location in iPad.
* @property {module:Camera.Direction} [cameraDirection=BACK] - Choose the camera to use (front- or back-facing).
*/
/**
* @description 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 `camera.getPicture` function opens the device's default camera
* application that allows users to snap pictures by default - this behavior occurs,
* when `Camera.sourceType` equals [`Camera.PictureSourceType.CAMERA`]{@link module:Camera.PictureSourceType}.
* 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 return value is sent to the [`cameraSuccess`]{@link module:camera.onSuccess} 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 `<img>` 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__
*
* - Android
* - BlackBerry
* - Browser
* - Firefox
* - FireOS
* - iOS
* - Windows
* - WP8
* - Ubuntu
*
* More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPicture-quirks).
*
* @example
* navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions);
* @param {module:camera.onSuccess} successCallback
* @param {module:camera.onError} errorCallback
* @param {module:camera.CameraOptions} options CameraOptions
*/
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 quality = getValue(options.quality, 100);
var destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
var targetWidth = getValue(options.targetWidth, -1);
@@ -61,15 +150,36 @@ cameraExport.getPicture = function(successCallback, errorCallback, options) {
var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
exec(successCallback, errorCallback, "Camera", "takePicture", args);
exec(successCallback, errorCallback, 'Camera', 'takePicture', args);
// XXX: commented out
//return new CameraPopoverHandle();
// return new CameraPopoverHandle();
};
cameraExport.cleanup = function(successCallback, errorCallback) {
exec(successCallback, errorCallback, "Camera", "cleanup", []);
/**
* Removes intermediate image files that are kept in temporary storage
* after calling [`camera.getPicture`]{@link module: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);
* }
*/
cameraExport.cleanup = function (successCallback, errorCallback) {
exec(successCallback, errorCallback, 'Camera', 'cleanup', []);
};
module.exports = cameraExport;

View File

@@ -19,35 +19,83 @@
*
*/
/**
* @module Camera
*/
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
}
/**
* @description
* Defines the output format of `Camera.getPicture` call.
* _Note:_ On iOS passing `DestinationType.NATIVE_URI` along with
* `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM` will
* disable any image modifications (resize, quality change, cropping, etc.) due
* to implementation specific.
*
* @enum {number}
*/
DestinationType: {
/** Return base64 encoded string. DATA_URL can be very memory intensive and cause app crashes or out of memory errors. Use FILE_URI or NATIVE_URI if possible */
DATA_URL: 0,
/** Return file uri (content://media/external/images/media/2 for Android) */
FILE_URI: 1,
/** Return native uri (eg. asset-library://... for iOS) */
NATIVE_URI: 2
},
/**
* @enum {number}
*/
EncodingType: {
/** Return JPEG encoded image */
JPEG: 0,
/** Return PNG encoded image */
PNG: 1
},
/**
* @enum {number}
*/
MediaType: {
/** Allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType */
PICTURE: 0,
/** Allow selection of video only, ONLY RETURNS URL */
VIDEO: 1,
/** Allow selection from all media types */
ALLMEDIA: 2
},
/**
* @description
* Defines the output format of `Camera.getPicture` call.
* _Note:_ On iOS passing `PictureSourceType.PHOTOLIBRARY` or `PictureSourceType.SAVEDPHOTOALBUM`
* along with `DestinationType.NATIVE_URI` will disable any image modifications (resize, quality
* change, cropping, etc.) due to implementation specific.
*
* @enum {number}
*/
PictureSourceType: {
/** Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android) */
PHOTOLIBRARY: 0,
/** Take picture from camera */
CAMERA: 1,
/** Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android) */
SAVEDPHOTOALBUM: 2
},
/**
* Matches iOS UIPopoverArrowDirection constants to specify arrow location on popover.
* @enum {number}
*/
PopoverArrowDirection: {
ARROW_UP: 1,
ARROW_DOWN: 2,
ARROW_LEFT: 4,
ARROW_RIGHT: 8,
ARROW_ANY: 15
},
/**
* @enum {number}
*/
Direction: {
/** Use the back-facing camera */
BACK: 0,
/** Use the front-facing camera */
FRONT: 1
}
};

View File

@@ -19,13 +19,12 @@
*
*/
var exec = require('cordova/exec');
/**
* @ignore in favour of iOS' one
* A handle to an image picker popover.
*/
var CameraPopoverHandle = function() {
this.setPosition = function(popoverOptions) {
var CameraPopoverHandle = function () {
this.setPosition = function (popoverOptions) {
console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
};
};

View File

@@ -22,16 +22,35 @@
var Camera = require('./Camera');
/**
* Encapsulates options for iOS Popover image picker
* @namespace navigator
*/
var CameraPopoverOptions = function(x,y,width,height,arrowDir){
/**
* 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.
* 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.
* @module CameraPopoverOptions
* @param {Number} [x=0] - x pixel coordinate of screen element onto which to anchor the popover.
* @param {Number} [y=32] - y pixel coordinate of screen element onto which to anchor the popover.
* @param {Number} [width=320] - width, in pixels, of the screen element onto which to anchor the popover.
* @param {Number} [height=480] - height, in pixels, of the screen element onto which to anchor the popover.
* @param {module:Camera.PopoverArrowDirection} [arrowDir=ARROW_ANY] - Direction the arrow on the popover should point.
* @param {Number} [popoverWidth=0] - width of the popover (0 or not specified will use apple's default width).
* @param {Number} [popoverHeight=0] - height of the popover (0 or not specified will use apple's default height).
*/
var CameraPopoverOptions = function (x, y, width, height, arrowDir, popoverWidth, popoverHeight) {
// 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;
this.popoverWidth = popoverWidth || 0;
this.popoverHeight = popoverHeight || 0;
};
module.exports = CameraPopoverOptions;

View File

@@ -22,12 +22,44 @@
var exec = require('cordova/exec');
/**
* A handle to an image picker popover.
* @namespace navigator
*/
var CameraPopoverHandle = function() {
this.setPosition = function(popoverOptions) {
/**
* A handle to an image picker popover.
*
* __Supported Platforms__
*
* - iOS
*
* @example
* 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, 300, 600)
* });
*
* // Reposition the popover if the orientation changes.
* window.onorientationchange = function() {
* var cameraPopoverHandle = new CameraPopoverHandle();
* var cameraPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, Camera.PopoverArrowDirection.ARROW_ANY, 400, 500);
* cameraPopoverHandle.setPosition(cameraPopoverOptions);
* }
* @module CameraPopoverHandle
*/
var CameraPopoverHandle = function () {
/**
* Can be used to reposition the image selection dialog,
* for example, when the device orientation changes.
* @memberof CameraPopoverHandle
* @instance
* @method setPosition
* @param {module:CameraPopoverOptions} popoverOptions
*/
this.setPosition = function (popoverOptions) {
var args = [ popoverOptions ];
exec(null, null, "Camera", "repositionPopover", args);
exec(null, null, 'Camera', 'repositionPopover', args);
};
};