mirror of
https://github.com/apache/cordova-plugin-camera.git
synced 2026-02-03 00:06:46 +08:00
Compare commits
519 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d13b71d33 | ||
|
|
8975171d7a | ||
|
|
2d1ee66a2b | ||
|
|
ebe0517a24 | ||
|
|
43d6591d9e | ||
|
|
64d8c5108a | ||
|
|
11769962bd | ||
|
|
140e8861e3 | ||
|
|
5ae56cf8f0 | ||
|
|
e2e04ba3d8 | ||
|
|
4584f15d9f | ||
|
|
0111e93448 | ||
|
|
0333d001c7 | ||
|
|
45496213b3 | ||
|
|
3f42591363 | ||
|
|
e2ecd7fe91 | ||
|
|
eb7fc333ee | ||
|
|
fd155d9705 | ||
|
|
2bf5b9347e | ||
|
|
efb633969e | ||
|
|
973bbbbac7 | ||
|
|
358522c0b5 | ||
|
|
8766956abb | ||
|
|
d89c25cd82 | ||
|
|
ba4f77468f | ||
|
|
adf15799d9 | ||
|
|
e9aba07926 | ||
|
|
df14414203 | ||
|
|
2a750f0fa1 | ||
|
|
06ac9b3dc9 | ||
|
|
bfa38fed2c | ||
|
|
7611960ef2 | ||
|
|
f4067e22d9 | ||
|
|
f33ade83e4 | ||
|
|
6f25420ce7 | ||
|
|
6feaa95559 | ||
|
|
c887c229f0 | ||
|
|
6900fbaefa | ||
|
|
a9436b1a18 | ||
|
|
db4b4b947d | ||
|
|
ae3531acfa | ||
|
|
5b4d9ba5c7 | ||
|
|
06dc38f9ab | ||
|
|
5dc952724f | ||
|
|
cad8bd1442 | ||
|
|
19d8e2f6ff | ||
|
|
cffd0ac825 | ||
|
|
295e928784 | ||
|
|
fae190ead2 | ||
|
|
a13665d530 | ||
|
|
81b878da59 | ||
|
|
b261d3174f | ||
|
|
24c8b6c43d | ||
|
|
7ddb3dfbbe | ||
|
|
60e779559e | ||
|
|
ce77aab010 | ||
|
|
cd72047dfc | ||
|
|
bfbe4a1e52 | ||
|
|
86b0bf2534 | ||
|
|
a5a3d88152 | ||
|
|
eed44330a4 | ||
|
|
07e85742aa | ||
|
|
c0d78ad644 | ||
|
|
7ee91a927d | ||
|
|
bcb26fbbd2 | ||
|
|
dc73954108 | ||
|
|
c1b9772dca | ||
|
|
a346212e90 | ||
|
|
eb57b02ba8 | ||
|
|
dca4b9c82b | ||
|
|
403682b9d4 | ||
|
|
5c23b65af9 | ||
|
|
6899c5ece9 | ||
|
|
5163d38465 | ||
|
|
36343a8e07 | ||
|
|
ead7d5e6c2 | ||
|
|
e334656933 | ||
|
|
5ec121bf98 | ||
|
|
d9d80e40c1 | ||
|
|
6ce1443622 | ||
|
|
37e12e85fb | ||
|
|
9d05a1e58f | ||
|
|
c8581ba2c9 | ||
|
|
e36482c7ba | ||
|
|
7c90555bd4 | ||
|
|
e25aed97c5 | ||
|
|
bf935dfbd2 | ||
|
|
ad8788a5e6 | ||
|
|
4b276ee534 | ||
|
|
4b99623eda | ||
|
|
36ea63a60f | ||
|
|
e6a4738031 | ||
|
|
c46fe3b31d | ||
|
|
67718544a8 | ||
|
|
b00cf97a04 | ||
|
|
fb02f48745 | ||
|
|
6bf45f005a | ||
|
|
96b7f55ec2 | ||
|
|
82f1c83a76 | ||
|
|
4ae0de1c5e | ||
|
|
b79c659c92 | ||
|
|
7fad5d5786 | ||
|
|
1f86358156 | ||
|
|
d456eeb711 | ||
|
|
f761934814 | ||
|
|
43b3a911c2 | ||
|
|
8f033f53db | ||
|
|
51d665a7a1 | ||
|
|
9f480b10cb | ||
|
|
a6706aef5f | ||
|
|
fb213b2b38 | ||
|
|
3e24b15934 | ||
|
|
2acda2d2f9 | ||
|
|
97d2014d62 | ||
|
|
b2107e0818 | ||
|
|
16c4325fef | ||
|
|
80342b0ddd | ||
|
|
55d419a36e | ||
|
|
5574490bc3 | ||
|
|
f1b0ccec56 | ||
|
|
e69240f251 | ||
|
|
5b3a99a6db | ||
|
|
3b8f64e330 | ||
|
|
f667ba6179 | ||
|
|
cfefa53272 | ||
|
|
77539558e6 | ||
|
|
cba99940a7 | ||
|
|
7155b636d5 | ||
|
|
160ed2d03f | ||
|
|
c3d7e55ad4 | ||
|
|
1b218cd8a0 | ||
|
|
51e5c02dcb | ||
|
|
26d13b0245 | ||
|
|
ef617cc943 | ||
|
|
1422b0a4f2 | ||
|
|
ba9a803b69 | ||
|
|
9615620843 | ||
|
|
a33c35152e | ||
|
|
eb98015e8a | ||
|
|
3c48ea9c9c | ||
|
|
2286bb3bb2 | ||
|
|
9badea4c95 | ||
|
|
180f7b5510 | ||
|
|
d0b381aad8 | ||
|
|
926fbf0e8c | ||
|
|
e4ff41c07c | ||
|
|
4fc25154f3 | ||
|
|
7f616d16f1 | ||
|
|
dfbca19a7a | ||
|
|
86e546f868 | ||
|
|
f2ca5ed79f | ||
|
|
ab7e02f0b8 | ||
|
|
899f6d8059 | ||
|
|
aa8a5945dd | ||
|
|
c06480f4e3 | ||
|
|
5ca4d8b082 | ||
|
|
bba8283d98 | ||
|
|
c27725ce66 | ||
|
|
415412cfef | ||
|
|
5ebda25164 | ||
|
|
d29c767f07 | ||
|
|
0ad5bdd9ff | ||
|
|
d6bd9ae3b3 | ||
|
|
81f9433606 | ||
|
|
05594c4646 | ||
|
|
a364e79482 | ||
|
|
42fc8e0bcd | ||
|
|
ee5537694a | ||
|
|
9eba35e2f6 | ||
|
|
8b83171ee2 | ||
|
|
a201722f6d | ||
|
|
c9e6a9a38a | ||
|
|
cc48945f37 | ||
|
|
8b3410bcc6 | ||
|
|
485a11e0f4 | ||
|
|
2d47a26271 | ||
|
|
2d2352f695 | ||
|
|
2f003d2b49 | ||
|
|
3a90bb7d55 | ||
|
|
b13cbdeb16 | ||
|
|
ee192d94b4 | ||
|
|
d9eb83bcb9 | ||
|
|
84f96c1067 | ||
|
|
61064ae3ed | ||
|
|
9ec8aea073 | ||
|
|
9db952e161 | ||
|
|
06d609cfa4 | ||
|
|
cc1076d3cb | ||
|
|
48d4213b2d | ||
|
|
9b566d3f0b | ||
|
|
b63a0d83e0 | ||
|
|
9fe94479e2 | ||
|
|
2f89666db7 | ||
|
|
f8682b9162 | ||
|
|
0ed6406864 | ||
|
|
fa58e83fca | ||
|
|
a3af38ad5b | ||
|
|
c98607c613 | ||
|
|
b89645c749 | ||
|
|
1beeafb6e8 | ||
|
|
7813ad9bef | ||
|
|
6e19147b09 | ||
|
|
9f159d757a | ||
|
|
62d1b01e81 | ||
|
|
92d67d990d | ||
|
|
0accbf560b | ||
|
|
e588907ac7 | ||
|
|
3ed3d887ca | ||
|
|
f010394af8 | ||
|
|
00e0a7dc46 | ||
|
|
fee72c7c04 | ||
|
|
5807458a1d | ||
|
|
c13e9f327b | ||
|
|
7e8fe0bae9 | ||
|
|
3f8c53f7f3 | ||
|
|
4e439d85c3 | ||
|
|
b62fdf50f7 | ||
|
|
744d72a33b | ||
|
|
3d26986bfd | ||
|
|
fed798e6c7 | ||
|
|
2027d69606 | ||
|
|
7129fb2c12 | ||
|
|
b695717240 | ||
|
|
acff98058f | ||
|
|
8a7326969f | ||
|
|
a05f169984 | ||
|
|
dcc81bfbe1 | ||
|
|
278b527702 | ||
|
|
d7ca7edf88 | ||
|
|
f283502545 | ||
|
|
a831e15a91 | ||
|
|
3586ea58a2 | ||
|
|
cc840b6cef | ||
|
|
0115458ce8 | ||
|
|
2eef096861 | ||
|
|
cf35b1bb2a | ||
|
|
39bff2f41d | ||
|
|
7551778e13 | ||
|
|
e3a431cbeb | ||
|
|
832d6e3bea | ||
|
|
2a7469e065 | ||
|
|
af98d57417 | ||
|
|
57b177f3fb | ||
|
|
f2b4eeded0 | ||
|
|
d4a55f20ec | ||
|
|
68e18a97d1 | ||
|
|
bfaef0ff25 | ||
|
|
0ba547cd3c | ||
|
|
6d058fe9e7 | ||
|
|
daf5fa48dd | ||
|
|
d124e03cb9 | ||
|
|
4202fff7ac | ||
|
|
def399fe51 | ||
|
|
82c9f4524a | ||
|
|
a9c18710f2 | ||
|
|
624ddd5ced | ||
|
|
fb871d40e2 | ||
|
|
0cd962466d | ||
|
|
c12206ebc8 | ||
|
|
826aca3524 | ||
|
|
76c129c95e | ||
|
|
fac7a53383 | ||
|
|
1348d2e138 | ||
|
|
c5f5a46e3e | ||
|
|
37dd471d0e | ||
|
|
a19c75253a | ||
|
|
c20e031d42 | ||
|
|
68a1150939 | ||
|
|
9c906b2ab7 | ||
|
|
56b9469313 | ||
|
|
d51e23ad7b | ||
|
|
2cd2528d1c | ||
|
|
5f7f4f3e55 | ||
|
|
20dcaf2cb3 | ||
|
|
b16c5234d5 | ||
|
|
c1948fc0d4 | ||
|
|
f792aaacc3 | ||
|
|
16636d18f2 | ||
|
|
019346d188 | ||
|
|
61b77951e1 | ||
|
|
a060fb36f3 | ||
|
|
77653183dd | ||
|
|
df734a522c | ||
|
|
654286d373 | ||
|
|
76ad059c9c | ||
|
|
5b38453262 | ||
|
|
e48a7e5c5c | ||
|
|
06fcbf05a2 | ||
|
|
9a9081b0d4 | ||
|
|
6f7ce333cc | ||
|
|
0f32b78c82 | ||
|
|
eb009471ab | ||
|
|
1d32ea46f0 | ||
|
|
e2193631d5 | ||
|
|
e8fa1695c4 | ||
|
|
e1911a3c78 | ||
|
|
ef5484a2aa | ||
|
|
b3376e2389 | ||
|
|
ee9884e97b | ||
|
|
1cf4feee60 | ||
|
|
847add6870 | ||
|
|
63ac782b32 | ||
|
|
7f3a0a5483 | ||
|
|
036cdfdeb8 | ||
|
|
2bb134bf6b | ||
|
|
88592575fe | ||
|
|
f5217bf02b | ||
|
|
9b444c39ba | ||
|
|
5ff225d8df | ||
|
|
3a8880d0c3 | ||
|
|
d0ad2f5065 | ||
|
|
44475d9df9 | ||
|
|
2714060b09 | ||
|
|
cbe17eec21 | ||
|
|
8024c5de49 | ||
|
|
933b35b0d2 | ||
|
|
dbe3e3d2ca | ||
|
|
a030c52f7f | ||
|
|
b8a68af63f | ||
|
|
837d6721f2 | ||
|
|
f20dfae735 | ||
|
|
454a6f518c | ||
|
|
dca8bd1943 | ||
|
|
cad9ab0419 | ||
|
|
ee5cfe89a5 | ||
|
|
813d143667 | ||
|
|
110b3b3388 | ||
|
|
eeb5880580 | ||
|
|
9dfd37cd66 | ||
|
|
c50757c245 | ||
|
|
0264e56162 | ||
|
|
8ebaaa62bd | ||
|
|
11eaaa8b9f | ||
|
|
899802a202 | ||
|
|
1e607ddcc8 | ||
|
|
63110ea54c | ||
|
|
b683315be6 | ||
|
|
2e147ba9ca | ||
|
|
11498404fc | ||
|
|
363dd02584 | ||
|
|
437cf3d93a | ||
|
|
e8d52ef256 | ||
|
|
647dac284b | ||
|
|
92c039e465 | ||
|
|
b6a8a24b88 | ||
|
|
0d37267eb4 | ||
|
|
88ee99011c | ||
|
|
a6cc9271a0 | ||
|
|
b3430e6f80 | ||
|
|
888a9661fb | ||
|
|
15f66bf5cd | ||
|
|
33ffb17c97 | ||
|
|
a830b3e08b | ||
|
|
706a3aa73e | ||
|
|
9f9e5ef4a9 | ||
|
|
b8b53c6254 | ||
|
|
0436928275 | ||
|
|
19feee9cb0 | ||
|
|
69c687e0cf | ||
|
|
b0ee9dd905 | ||
|
|
c2e0db2b86 | ||
|
|
8f07f562a2 | ||
|
|
1e8c836844 | ||
|
|
b131021303 | ||
|
|
0dabe94416 | ||
|
|
fb8ce21711 | ||
|
|
b67e4a09ed | ||
|
|
d10bf50c61 | ||
|
|
b7af490a3e | ||
|
|
c2e4d1f36d | ||
|
|
d0fe66e1d5 | ||
|
|
af36e74d05 | ||
|
|
629dbcb712 | ||
|
|
bc7c4278ef | ||
|
|
302aacb214 | ||
|
|
3927735d09 | ||
|
|
9e11ab4dfb | ||
|
|
d1dfc1e8ee | ||
|
|
ee4ac0d7b2 | ||
|
|
d52b936bd8 | ||
|
|
9fe5b430aa | ||
|
|
23dbb8889a | ||
|
|
ac4af88f55 | ||
|
|
f1ae0e9ccf | ||
|
|
563f0038fd | ||
|
|
ccbbdccc4c | ||
|
|
04ed502d92 | ||
|
|
7209d38fa2 | ||
|
|
8062a006c0 | ||
|
|
29c9ea387d | ||
|
|
5ef04e552c | ||
|
|
b8a700215a | ||
|
|
081aec5602 | ||
|
|
9e4174caff | ||
|
|
7b2f453c25 | ||
|
|
00cd249dd7 | ||
|
|
b698e10386 | ||
|
|
2a93a48956 | ||
|
|
929733b891 | ||
|
|
f39a08ba29 | ||
|
|
bca73e6ee9 | ||
|
|
2c597a389b | ||
|
|
b780331389 | ||
|
|
57aa707c6a | ||
|
|
97514fb01e | ||
|
|
799ed580d3 | ||
|
|
d7e708db09 | ||
|
|
80b0048384 | ||
|
|
2ead6335c9 | ||
|
|
2a0735d551 | ||
|
|
4f056f0a73 | ||
|
|
376bec2b96 | ||
|
|
482f2ac2cc | ||
|
|
35c653d24d | ||
|
|
3ab650bdc9 | ||
|
|
2045e0a644 | ||
|
|
032531ae77 | ||
|
|
fb4cff9cc0 | ||
|
|
0d389857cf | ||
|
|
8b8db828f6 | ||
|
|
03fade661e | ||
|
|
c06ae46485 | ||
|
|
dbe33a44ff | ||
|
|
021743f20e | ||
|
|
53e42fc97b | ||
|
|
7413c1bcb2 | ||
|
|
860fedece4 | ||
|
|
9adc39ca2c | ||
|
|
af18483d69 | ||
|
|
3581c595d7 | ||
|
|
513bfde49e | ||
|
|
43cb385f0e | ||
|
|
45da410662 | ||
|
|
fcfe642147 | ||
|
|
05da230c2a | ||
|
|
986bf6fd3c | ||
|
|
d84b875c44 | ||
|
|
1ffb14d764 | ||
|
|
e851960910 | ||
|
|
ae22820046 | ||
|
|
fa30a56760 | ||
|
|
5c1394058c | ||
|
|
6dcfa9cf9b | ||
|
|
f3cfadb19e | ||
|
|
e9a834955c | ||
|
|
5b84c38a43 | ||
|
|
af566264ef | ||
|
|
a423e57c8a | ||
|
|
481ff27727 | ||
|
|
599ab31090 | ||
|
|
b3b43b1f3c | ||
|
|
b2403c6076 | ||
|
|
c8c3bf0782 | ||
|
|
f3bc296da8 | ||
|
|
938543c203 | ||
|
|
e316e32808 | ||
|
|
8e1e5c8550 | ||
|
|
d53a7770d9 | ||
|
|
42bf5d2983 | ||
|
|
9064130fce | ||
|
|
6366aeba47 | ||
|
|
823eb5d27a | ||
|
|
0d63ac27ca | ||
|
|
dbaa458b7f | ||
|
|
f2eebeed0a | ||
|
|
c696f6e0b3 | ||
|
|
45a50c448e | ||
|
|
e8cbb106ae | ||
|
|
10e0efc503 | ||
|
|
cb7e19311a | ||
|
|
9a26e97ac8 | ||
|
|
f8d5ef643e | ||
|
|
98749a611b | ||
|
|
08acf7bc49 | ||
|
|
e4ab155fd0 | ||
|
|
7305c64db0 | ||
|
|
f20703de20 | ||
|
|
543c4198d8 | ||
|
|
1650dce693 | ||
|
|
5b8324e984 | ||
|
|
4aa85de064 | ||
|
|
fa93b534d1 | ||
|
|
c1683000d2 | ||
|
|
1a495492c6 | ||
|
|
a07c85e8b4 | ||
|
|
06ecc91fd1 | ||
|
|
05e3eed60e | ||
|
|
ffd46c4ef5 | ||
|
|
1cf38cd775 | ||
|
|
4fa934e06f | ||
|
|
1f51a3b61d | ||
|
|
4bdb990b77 | ||
|
|
d00464e9d3 | ||
|
|
7b60a0b6d1 | ||
|
|
4c901d56be | ||
|
|
5af2653f18 | ||
|
|
9de98fcc0d | ||
|
|
68453f2492 | ||
|
|
61325f4620 | ||
|
|
8ff4d3f16e | ||
|
|
6e93ebbf90 | ||
|
|
8719cb7342 | ||
|
|
d5405ba2e0 | ||
|
|
8760c99b31 | ||
|
|
2eb71f648f | ||
|
|
199732845e | ||
|
|
707426ece2 | ||
|
|
10e5455356 | ||
|
|
30a75e3fa7 | ||
|
|
7e9f099301 | ||
|
|
9e0d943971 | ||
|
|
87a5030771 | ||
|
|
0c9de56da5 | ||
|
|
e8596fbc8e | ||
|
|
d899d7a4b8 | ||
|
|
c7d88e8b34 | ||
|
|
2d3f10ea3f | ||
|
|
80205f41e3 | ||
|
|
92dd3eeee3 |
32
.appveyor.yml
Normal file
32
.appveyor.yml
Normal 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
22
.asf.yaml
Normal 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
|
||||
23
.eslintrc.yml
Normal file
23
.eslintrc.yml
Normal file
@@ -0,0 +1,23 @@
|
||||
# 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.
|
||||
|
||||
root: true
|
||||
extends: '@cordova/eslint-config/browser'
|
||||
|
||||
overrides:
|
||||
- files: [tests/**/*.js]
|
||||
extends: '@cordova/eslint-config/node-tests'
|
||||
94
.gitattributes
vendored
Normal file
94
.gitattributes
vendored
Normal 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
42
.github/ISSUE_TEMPLATE.md
vendored
Normal 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
50
.github/ISSUE_TEMPLATE/BUG_REPORT.md
vendored
Normal 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
|
||||
29
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal file
29
.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md
vendored
Normal 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?
|
||||
-->
|
||||
|
||||
|
||||
27
.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md
vendored
Normal file
27
.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md
vendored
Normal 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
35
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal 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
10
.gitignore
vendored
@@ -12,12 +12,4 @@ Thumbs.db
|
||||
*.swp
|
||||
*.user
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/node_modules/**
|
||||
|
||||
3
.npmignore
Normal file
3
.npmignore
Normal file
@@ -0,0 +1,3 @@
|
||||
.*
|
||||
appveyor.yml
|
||||
tests
|
||||
118
.travis.yml
Normal file
118
.travis.yml
Normal file
@@ -0,0 +1,118 @@
|
||||
# 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=29
|
||||
- ANDROID_BUILD_TOOLS_VERSION=29.0.2
|
||||
|
||||
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: xcode11.6
|
||||
|
||||
_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
|
||||
os: osx
|
||||
osx_image: xcode11.5
|
||||
|
||||
# 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
37
CONTRIBUTING.md
Normal 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!
|
||||
|
||||
202
LICENSE
Normal file
202
LICENSE
Normal file
@@ -0,0 +1,202 @@
|
||||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
5
NOTICE
Normal file
5
NOTICE
Normal file
@@ -0,0 +1,5 @@
|
||||
Apache Cordova
|
||||
Copyright 2012 The Apache Software Foundation
|
||||
|
||||
This product includes software developed at
|
||||
The Apache Software Foundation (http://www.apache.org/).
|
||||
717
README.md
717
README.md
@@ -1,24 +1,703 @@
|
||||
---
|
||||
title: Camera
|
||||
description: Take pictures with the device camera.
|
||||
---
|
||||
<!---
|
||||
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.
|
||||
# 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.
|
||||
-->
|
||||
|
||||
# org.apache.cordova.camera
|
||||
|AppVeyor|Travis CI|
|
||||
|:-:|:-:|
|
||||
|[](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-plugin-camera)|[](https://travis-ci.org/apache/cordova-plugin-camera)|
|
||||
|
||||
Plugin documentation: [doc/index.md](doc/index.md)
|
||||
# cordova-plugin-camera
|
||||
|
||||
This is `dev` - the deprecated development branch of this plugin; development of this plugin has moved to the `master` branch
|
||||
This plugin defines a global `navigator.camera` object, which provides an API for taking pictures and for choosing images from
|
||||
the system's image library.
|
||||
|
||||
Although the object is attached to the global scoped `navigator`, it is not available until after the `deviceready` event.
|
||||
|
||||
document.addEventListener("deviceready", onDeviceReady, false);
|
||||
function onDeviceReady() {
|
||||
console.log(navigator.camera);
|
||||
}
|
||||
|
||||
|
||||
## Installation
|
||||
|
||||
This requires cordova 5.0+
|
||||
|
||||
cordova plugin add cordova-plugin-camera
|
||||
Older versions of cordova can still install via the __deprecated__ id
|
||||
|
||||
cordova plugin add org.apache.cordova.camera
|
||||
It is also possible to install via repo url directly ( unstable )
|
||||
|
||||
cordova plugin add https://github.com/apache/cordova-plugin-camera.git
|
||||
|
||||
|
||||
## How to Contribute
|
||||
|
||||
Contributors are welcome! And we need your contributions to keep the project moving forward. You can[report bugs, improve the documentation, or [contribute code](https://github.com/apache/cordova-plugin-camera/pulls).
|
||||
|
||||
There is a specific [contributor workflow](http://wiki.apache.org/cordova/ContributorWorkflow) we recommend. Start reading there. More information is available on [our wiki](http://wiki.apache.org/cordova).
|
||||
|
||||
**Have a solution?** Send a [Pull Request](https://github.com/apache/cordova-plugin-camera/pulls).
|
||||
|
||||
In order for your changes to be accepted, you need to sign and submit an Apache [ICLA](http://www.apache.org/licenses/#clas) (Individual Contributor License Agreement). Then your name will appear on the list of CLAs signed by [non-committers](https://people.apache.org/committer-index.html#unlistedclas) or [Cordova committers](http://people.apache.org/committers-by-project.html#cordova).
|
||||
|
||||
**And don't forget to test and document your code.**
|
||||
|
||||
### iOS Quirks
|
||||
|
||||
Since iOS 10 it's mandatory to provide an usage description in the `info.plist` if trying to access privacy-sensitive data. When the system prompts the user to allow access, this usage description string will displayed as part of the permission dialog box, but if you didn't provide the usage description, the app will crash before showing the dialog. Also, Apple will reject apps that access private data but don't provide an usage description.
|
||||
|
||||
This plugins requires the following usage descriptions:
|
||||
|
||||
- `NSCameraUsageDescription` specifies the reason for your app to access the device's camera.
|
||||
- `NSPhotoLibraryUsageDescription` specifies the reason for your app to access the user's photo library.
|
||||
- `NSLocationWhenInUseUsageDescription` specifies the reason for your app to access the user's location information while your app is in use. (Set it if you have `CameraUsesGeolocation` preference set to `true`)
|
||||
- `NSPhotoLibraryAddUsageDescription` specifies the reason for your app to get write-only access to the user's photo library
|
||||
|
||||
To add these entries into the `info.plist`, you can use the `edit-config` tag in the `config.xml` like this:
|
||||
|
||||
```
|
||||
<edit-config target="NSCameraUsageDescription" file="*-Info.plist" mode="merge">
|
||||
<string>need camera access to take pictures</string>
|
||||
</edit-config>
|
||||
```
|
||||
|
||||
```
|
||||
<edit-config target="NSPhotoLibraryUsageDescription" file="*-Info.plist" mode="merge">
|
||||
<string>need photo library access to get pictures from there</string>
|
||||
</edit-config>
|
||||
```
|
||||
|
||||
```
|
||||
<edit-config target="NSLocationWhenInUseUsageDescription" file="*-Info.plist" mode="merge">
|
||||
<string>need location access to find things nearby</string>
|
||||
</edit-config>
|
||||
```
|
||||
|
||||
```
|
||||
<edit-config target="NSPhotoLibraryAddUsageDescription" file="*-Info.plist" mode="merge">
|
||||
<string>need photo library access to save pictures there</string>
|
||||
</edit-config>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# API Reference <a name="reference"></a>
|
||||
|
||||
|
||||
* [camera](#module_camera)
|
||||
* [.getPicture(successCallback, errorCallback, options)](#module_camera.getPicture)
|
||||
* [.cleanup()](#module_camera.cleanup)
|
||||
* [.onError](#module_camera.onError) : <code>function</code>
|
||||
* [.onSuccess](#module_camera.onSuccess) : <code>function</code>
|
||||
* [.CameraOptions](#module_camera.CameraOptions) : <code>Object</code>
|
||||
|
||||
|
||||
* [Camera](#module_Camera)
|
||||
* [.DestinationType](#module_Camera.DestinationType) : <code>enum</code>
|
||||
* [.EncodingType](#module_Camera.EncodingType) : <code>enum</code>
|
||||
* [.MediaType](#module_Camera.MediaType) : <code>enum</code>
|
||||
* [.PictureSourceType](#module_Camera.PictureSourceType) : <code>enum</code>
|
||||
* [.PopoverArrowDirection](#module_Camera.PopoverArrowDirection) : <code>enum</code>
|
||||
* [.Direction](#module_Camera.Direction) : <code>enum</code>
|
||||
|
||||
* [CameraPopoverHandle](#module_CameraPopoverHandle)
|
||||
* [CameraPopoverOptions](#module_CameraPopoverOptions)
|
||||
|
||||
---
|
||||
|
||||
<a name="module_camera"></a>
|
||||
|
||||
## camera
|
||||
<a name="module_camera.getPicture"></a>
|
||||
|
||||
### camera.getPicture(successCallback, errorCallback, options)
|
||||
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`](#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`](#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
|
||||
- Browser
|
||||
- iOS
|
||||
- Windows
|
||||
- OSX
|
||||
|
||||
More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPicture-quirks).
|
||||
|
||||
**Kind**: static method of <code>[camera](#module_camera)</code>
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| successCallback | <code>[onSuccess](#module_camera.onSuccess)</code> | |
|
||||
| errorCallback | <code>[onError](#module_camera.onError)</code> | |
|
||||
| options | <code>[CameraOptions](#module_camera.CameraOptions)</code> | CameraOptions |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions);
|
||||
```
|
||||
<a name="module_camera.cleanup"></a>
|
||||
|
||||
### camera.cleanup()
|
||||
Removes intermediate image files that are kept in temporary storage
|
||||
after calling [`camera.getPicture`](#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
|
||||
|
||||
**Kind**: static method of <code>[camera](#module_camera)</code>
|
||||
**Example**
|
||||
```js
|
||||
navigator.camera.cleanup(onSuccess, onFail);
|
||||
|
||||
function onSuccess() {
|
||||
console.log("Camera cleanup success.")
|
||||
}
|
||||
|
||||
function onFail(message) {
|
||||
alert('Failed because: ' + message);
|
||||
}
|
||||
```
|
||||
<a name="module_camera.onError"></a>
|
||||
|
||||
### camera.onError : <code>function</code>
|
||||
Callback function that provides an error message.
|
||||
|
||||
**Kind**: static typedef of <code>[camera](#module_camera)</code>
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| message | <code>string</code> | The message is provided by the device's native code. |
|
||||
|
||||
<a name="module_camera.onSuccess"></a>
|
||||
|
||||
### camera.onSuccess : <code>function</code>
|
||||
Callback function that provides the image data.
|
||||
|
||||
**Kind**: static typedef of <code>[camera](#module_camera)</code>
|
||||
|
||||
| Param | Type | Description |
|
||||
| --- | --- | --- |
|
||||
| imageData | <code>string</code> | Base64 encoding of the image data, _or_ the image file URI, depending on [`cameraOptions`](#module_camera.CameraOptions) in effect. |
|
||||
|
||||
**Example**
|
||||
```js
|
||||
// Show image
|
||||
//
|
||||
function cameraCallback(imageData) {
|
||||
var image = document.getElementById('myImage');
|
||||
image.src = "data:image/jpeg;base64," + imageData;
|
||||
}
|
||||
```
|
||||
<a name="module_camera.CameraOptions"></a>
|
||||
|
||||
### camera.CameraOptions : <code>Object</code>
|
||||
Optional parameters to customize the camera settings.
|
||||
* [Quirks](#CameraOptions-quirks)
|
||||
|
||||
**Kind**: static typedef of <code>[camera](#module_camera)</code>
|
||||
**Properties**
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| quality | <code>number</code> | <code>50</code> | 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.) |
|
||||
| destinationType | <code>[DestinationType](#module_Camera.DestinationType)</code> | <code>FILE_URI</code> | Choose the format of the return value. |
|
||||
| sourceType | <code>[PictureSourceType](#module_Camera.PictureSourceType)</code> | <code>CAMERA</code> | Set the source of the picture. |
|
||||
| allowEdit | <code>Boolean</code> | <code>false</code> | Allow simple editing of image before selection. |
|
||||
| encodingType | <code>[EncodingType](#module_Camera.EncodingType)</code> | <code>JPEG</code> | Choose the returned image file's encoding. |
|
||||
| targetWidth | <code>number</code> | | Width in pixels to scale image. Must be used with `targetHeight`. Aspect ratio remains constant. |
|
||||
| targetHeight | <code>number</code> | | Height in pixels to scale image. Must be used with `targetWidth`. Aspect ratio remains constant. |
|
||||
| mediaType | <code>[MediaType](#module_Camera.MediaType)</code> | <code>PICTURE</code> | Set the type of media to select from. Only works when `PictureSourceType` is `PHOTOLIBRARY` or `SAVEDPHOTOALBUM`. |
|
||||
| correctOrientation | <code>Boolean</code> | | Rotate the image to correct for the orientation of the device during capture. |
|
||||
| saveToPhotoAlbum | <code>Boolean</code> | | Save the image to the photo album on the device after capture. |
|
||||
| popoverOptions | <code>[CameraPopoverOptions](#module_CameraPopoverOptions)</code> | | iOS-only options that specify popover location in iPad. |
|
||||
| cameraDirection | <code>[Direction](#module_Camera.Direction)</code> | <code>BACK</code> | Choose the camera to use (front- or back-facing). |
|
||||
|
||||
---
|
||||
|
||||
<a name="module_Camera"></a>
|
||||
|
||||
## Camera
|
||||
<a name="module_Camera.DestinationType"></a>
|
||||
|
||||
### Camera.DestinationType : <code>enum</code>
|
||||
Defines the output format of `Camera.getPicture` call.
|
||||
|
||||
**Kind**: static enum property of <code>[Camera](#module_Camera)</code>
|
||||
**Properties**
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| DATA_URL | <code>number</code> | <code>0</code> | Return base64 encoded string. DATA_URL can be very memory intensive and cause app crashes or out of memory errors. Use FILE_URI if possible |
|
||||
| FILE_URI | <code>number</code> | <code>1</code> | Return file uri (content://media/external/images/media/2 for Android) |
|
||||
|
||||
<a name="module_Camera.EncodingType"></a>
|
||||
|
||||
### Camera.EncodingType : <code>enum</code>
|
||||
**Kind**: static enum property of <code>[Camera](#module_Camera)</code>
|
||||
**Properties**
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| JPEG | <code>number</code> | <code>0</code> | Return JPEG encoded image |
|
||||
| PNG | <code>number</code> | <code>1</code> | Return PNG encoded image |
|
||||
|
||||
<a name="module_Camera.MediaType"></a>
|
||||
|
||||
### Camera.MediaType : <code>enum</code>
|
||||
**Kind**: static enum property of <code>[Camera](#module_Camera)</code>
|
||||
**Properties**
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| PICTURE | <code>number</code> | <code>0</code> | Allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType |
|
||||
| VIDEO | <code>number</code> | <code>1</code> | Allow selection of video only, ONLY RETURNS URL |
|
||||
| ALLMEDIA | <code>number</code> | <code>2</code> | Allow selection from all media types |
|
||||
|
||||
<a name="module_Camera.PictureSourceType"></a>
|
||||
|
||||
### Camera.PictureSourceType : <code>enum</code>
|
||||
Defines the output format of `Camera.getPicture` call.
|
||||
|
||||
**Kind**: static enum property of <code>[Camera](#module_Camera)</code>
|
||||
**Properties**
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| PHOTOLIBRARY | <code>number</code> | <code>0</code> | Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android) |
|
||||
| CAMERA | <code>number</code> | <code>1</code> | Take picture from camera |
|
||||
| SAVEDPHOTOALBUM | <code>number</code> | <code>2</code> | Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android) |
|
||||
|
||||
<a name="module_Camera.PopoverArrowDirection"></a>
|
||||
|
||||
### Camera.PopoverArrowDirection : <code>enum</code>
|
||||
Matches iOS UIPopoverArrowDirection constants to specify arrow location on popover.
|
||||
|
||||
**Kind**: static enum property of <code>[Camera](#module_Camera)</code>
|
||||
**Properties**
|
||||
|
||||
| Name | Type | Default |
|
||||
| --- | --- | --- |
|
||||
| ARROW_UP | <code>number</code> | <code>1</code> |
|
||||
| ARROW_DOWN | <code>number</code> | <code>2</code> |
|
||||
| ARROW_LEFT | <code>number</code> | <code>4</code> |
|
||||
| ARROW_RIGHT | <code>number</code> | <code>8</code> |
|
||||
| ARROW_ANY | <code>number</code> | <code>15</code> |
|
||||
|
||||
<a name="module_Camera.Direction"></a>
|
||||
|
||||
### Camera.Direction : <code>enum</code>
|
||||
**Kind**: static enum property of <code>[Camera](#module_Camera)</code>
|
||||
**Properties**
|
||||
|
||||
| Name | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| BACK | <code>number</code> | <code>0</code> | Use the back-facing camera |
|
||||
| FRONT | <code>number</code> | <code>1</code> | Use the front-facing camera |
|
||||
|
||||
---
|
||||
|
||||
<a name="module_CameraPopoverOptions"></a>
|
||||
|
||||
## 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.
|
||||
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.
|
||||
|
||||
|
||||
| Param | Type | Default | Description |
|
||||
| --- | --- | --- | --- |
|
||||
| [x] | <code>Number</code> | <code>0</code> | x pixel coordinate of screen element onto which to anchor the popover. |
|
||||
| [y] | <code>Number</code> | <code>32</code> | y pixel coordinate of screen element onto which to anchor the popover. |
|
||||
| [width] | <code>Number</code> | <code>320</code> | width, in pixels, of the screen element onto which to anchor the popover. |
|
||||
| [height] | <code>Number</code> | <code>480</code> | height, in pixels, of the screen element onto which to anchor the popover. |
|
||||
| [arrowDir] | <code>[PopoverArrowDirection](#module_Camera.PopoverArrowDirection)</code> | <code>ARROW_ANY</code> | Direction the arrow on the popover should point. |
|
||||
| [popoverWidth] | <code>Number</code> | <code>0</code> | width of the popover (0 or not specified will use apple's default width). |
|
||||
| [popoverHeight] | <code>Number</code> | <code>0</code> | height of the popover (0 or not specified will use apple's default height). |
|
||||
|
||||
---
|
||||
|
||||
<a name="module_CameraPopoverHandle"></a>
|
||||
|
||||
## CameraPopoverHandle
|
||||
A handle to an image picker popover.
|
||||
|
||||
__Supported Platforms__
|
||||
|
||||
- iOS
|
||||
|
||||
**Example**
|
||||
```js
|
||||
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);
|
||||
}
|
||||
```
|
||||
---
|
||||
|
||||
|
||||
## `camera.getPicture` Errata
|
||||
|
||||
#### Example <a name="camera-getPicture-examples"></a>
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
Take a photo and retrieve it as a Base64-encoded image:
|
||||
|
||||
/**
|
||||
* Warning: Using DATA_URL is not recommended! The DATA_URL destination
|
||||
* type is very memory intensive, even with a low quality setting. Using it
|
||||
* can result in out of memory errors and application crashes. Use FILE_URI
|
||||
* instead.
|
||||
*/
|
||||
navigator.camera.getPicture(onSuccess, onFail, { quality: 25,
|
||||
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);
|
||||
}
|
||||
|
||||
#### Preferences (iOS)
|
||||
|
||||
- __CameraUsesGeolocation__ (boolean, defaults to false). For capturing JPEGs, set to true to get geolocation data in the EXIF header. This will trigger a request for geolocation permissions if set to true.
|
||||
|
||||
<preference name="CameraUsesGeolocation" value="false" />
|
||||
|
||||
#### Android Quirks
|
||||
|
||||
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 result from the plugin call will be delivered via the resume event.
|
||||
See [the Android Lifecycle guide][android_lifecycle]
|
||||
for more information. The `pendingResult.result` value will contain the value that
|
||||
would be passed to the callbacks (either the URI/URL or an error message). Check
|
||||
the `pendingResult.pluginStatus` to determine whether or not the call was
|
||||
successful.
|
||||
|
||||
#### Browser Quirks
|
||||
|
||||
Can only return photos as Base64-encoded image.
|
||||
|
||||
#### 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 quirks
|
||||
|
||||
On Windows Phone 8.1 using `SAVEDPHOTOALBUM` or `PHOTOLIBRARY` as a source type causes application to suspend until file picker returns the selected image and
|
||||
then restore with start page as defined in app's `config.xml`. In case when `camera.getPicture` was called from different page, this will lead to reloading
|
||||
start page from scratch and success and error callbacks will never be called.
|
||||
|
||||
To avoid this we suggest using SPA pattern or call `camera.getPicture` only from your app's start page.
|
||||
|
||||
More information about Windows Phone 8.1 picker APIs is here: [How to continue your Windows Phone app after calling a file picker](https://msdn.microsoft.com/en-us/library/windows/apps/dn720490.aspx)
|
||||
|
||||
## `CameraOptions` Errata <a name="CameraOptions-quirks"></a>
|
||||
|
||||
#### Android Quirks
|
||||
|
||||
- Any `cameraDirection` value results in a back-facing photo. (= You can only use the back camera)
|
||||
|
||||
- **`allowEdit` is unpredictable on Android and it should not be used!** The Android implementation of this plugin tries to find and use an application on the user's device to do image cropping. The plugin has no control over what application the user selects to perform the image cropping and it is very possible that the user could choose an incompatible option and cause the plugin to fail. This sometimes works because most devices come with an application that handles cropping in a way that is compatible with this plugin (Google Photos), but it is unwise to rely on that being the case. If image editing is essential to your application, consider seeking a third party library or plugin that provides its own image editing utility for a more robust solution.
|
||||
|
||||
- `Camera.PictureSourceType.PHOTOLIBRARY` and `Camera.PictureSourceType.SAVEDPHOTOALBUM` both display the same photo album.
|
||||
|
||||
- Ignores the `encodingType` parameter if the image is unedited (i.e. `quality` is 100, `correctOrientation` is false, and no `targetHeight` or `targetWidth` are specified). The `CAMERA` source will always return the JPEG file given by the native camera and the `PHOTOLIBRARY` and `SAVEDPHOTOALBUM` sources will return the selected file in its existing encoding.
|
||||
|
||||
#### iOS Quirks
|
||||
|
||||
- When using `destinationType.FILE_URI`, photos are saved in the application's temporary directory. The contents of the application's temporary directory is deleted when the application ends.
|
||||
|
||||
|
||||
[android_lifecycle]: http://cordova.apache.org/docs/en/dev/guide/platforms/android/lifecycle.html
|
||||
|
||||
## Sample: Take Pictures, Select Pictures from the Picture Library, and Get Thumbnails <a name="sample"></a>
|
||||
|
||||
The Camera plugin allows you to do things like open the device's Camera app and take a picture, or open the file picker and select one. The code snippets in this section demonstrate different tasks including:
|
||||
|
||||
* Open the Camera app and [take a Picture](#takePicture)
|
||||
* Take a picture and [return thumbnails](#getThumbnails) (resized picture)
|
||||
* Take a picture and [generate a FileEntry object](#convert)
|
||||
* [Select a file](#selectFile) from the picture library
|
||||
* Select a JPEG image and [return thumbnails](#getFileThumbnails) (resized image)
|
||||
* Select an image and [generate a FileEntry object](#convert)
|
||||
|
||||
## Take a Picture <a name="takePicture"></a>
|
||||
|
||||
Before you can take a picture, you need to set some Camera plugin options to pass into the Camera plugin's `getPicture` function. Here is a common set of recommendations. In this example, you create the object that you will use for the Camera options, and set the `sourceType` dynamically to support both the Camera app and the file picker.
|
||||
|
||||
```js
|
||||
function setOptions(srcType) {
|
||||
var options = {
|
||||
// Some common settings are 20, 50, and 100
|
||||
quality: 50,
|
||||
destinationType: Camera.DestinationType.FILE_URI,
|
||||
// In this app, dynamically set the picture source, Camera or photo gallery
|
||||
sourceType: srcType,
|
||||
encodingType: Camera.EncodingType.JPEG,
|
||||
mediaType: Camera.MediaType.PICTURE,
|
||||
allowEdit: true,
|
||||
correctOrientation: true
|
||||
}
|
||||
return options;
|
||||
}
|
||||
```
|
||||
|
||||
Typically, you want to use a FILE_URI instead of a DATA_URL to avoid most memory issues. JPEG is the recommended encoding type for Android.
|
||||
|
||||
You take a picture by passing in the options object to `getPicture`, which takes a CameraOptions object as the third argument. When you call `setOptions`, pass `Camera.PictureSourceType.CAMERA` as the picture source.
|
||||
|
||||
```js
|
||||
function openCamera(selection) {
|
||||
|
||||
var srcType = Camera.PictureSourceType.CAMERA;
|
||||
var options = setOptions(srcType);
|
||||
var func = createNewFileEntry;
|
||||
|
||||
navigator.camera.getPicture(function cameraSuccess(imageUri) {
|
||||
|
||||
displayImage(imageUri);
|
||||
// You may choose to copy the picture, save it somewhere, or upload.
|
||||
func(imageUri);
|
||||
|
||||
}, function cameraError(error) {
|
||||
console.debug("Unable to obtain picture: " + error, "app");
|
||||
|
||||
}, options);
|
||||
}
|
||||
```
|
||||
|
||||
Once you take the picture, you can display it or do something else. In this example, call the app's `displayImage` function from the preceding code.
|
||||
|
||||
```js
|
||||
function displayImage(imgUri) {
|
||||
|
||||
var elem = document.getElementById('imageFile');
|
||||
elem.src = imgUri;
|
||||
}
|
||||
```
|
||||
|
||||
To display the image on some platforms, you might need to include the main part of the URI in the Content-Security-Policy `<meta>` element in index.html. For example, on Windows 10, you can include `ms-appdata:` in your `<meta>` element. Here is an example.
|
||||
|
||||
```html
|
||||
<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: ms-appdata: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *">
|
||||
```
|
||||
|
||||
## Take a Picture and Return Thumbnails (Resize the Picture) <a name="getThumbnails"></a>
|
||||
|
||||
To get smaller images, you can return a resized image by passing both `targetHeight` and `targetWidth` values with your CameraOptions object. In this example, you resize the returned image to fit in a 100px by 100px box (the aspect ratio is maintained, so 100px is either the height or width, whichever is greater in the source).
|
||||
|
||||
```js
|
||||
function openCamera(selection) {
|
||||
|
||||
var srcType = Camera.PictureSourceType.CAMERA;
|
||||
var options = setOptions(srcType);
|
||||
var func = createNewFileEntry;
|
||||
|
||||
if (selection == "camera-thmb") {
|
||||
options.targetHeight = 100;
|
||||
options.targetWidth = 100;
|
||||
}
|
||||
|
||||
navigator.camera.getPicture(function cameraSuccess(imageUri) {
|
||||
|
||||
// Do something
|
||||
|
||||
}, function cameraError(error) {
|
||||
console.debug("Unable to obtain picture: " + error, "app");
|
||||
|
||||
}, options);
|
||||
}
|
||||
```
|
||||
|
||||
## Select a File from the Picture Library <a name="selectFile"></a>
|
||||
|
||||
When selecting a file using the file picker, you also need to set the CameraOptions object. In this example, set the `sourceType` to `Camera.PictureSourceType.SAVEDPHOTOALBUM`. To open the file picker, call `getPicture` just as you did in the previous example, passing in the success and error callbacks along with CameraOptions object.
|
||||
|
||||
```js
|
||||
function openFilePicker(selection) {
|
||||
|
||||
var srcType = Camera.PictureSourceType.SAVEDPHOTOALBUM;
|
||||
var options = setOptions(srcType);
|
||||
var func = createNewFileEntry;
|
||||
|
||||
navigator.camera.getPicture(function cameraSuccess(imageUri) {
|
||||
|
||||
// Do something
|
||||
|
||||
}, function cameraError(error) {
|
||||
console.debug("Unable to obtain picture: " + error, "app");
|
||||
|
||||
}, options);
|
||||
}
|
||||
```
|
||||
|
||||
## Select an Image and Return Thumbnails (resized images) <a name="getFileThumbnails"></a>
|
||||
|
||||
Resizing a file selected with the file picker works just like resizing using the Camera app; set the `targetHeight` and `targetWidth` options.
|
||||
|
||||
```js
|
||||
function openFilePicker(selection) {
|
||||
|
||||
var srcType = Camera.PictureSourceType.SAVEDPHOTOALBUM;
|
||||
var options = setOptions(srcType);
|
||||
var func = createNewFileEntry;
|
||||
|
||||
if (selection == "picker-thmb") {
|
||||
// To downscale a selected image,
|
||||
// Camera.EncodingType (e.g., JPEG) must match the selected image type.
|
||||
options.targetHeight = 100;
|
||||
options.targetWidth = 100;
|
||||
}
|
||||
|
||||
navigator.camera.getPicture(function cameraSuccess(imageUri) {
|
||||
|
||||
// Do something with image
|
||||
|
||||
}, function cameraError(error) {
|
||||
console.debug("Unable to obtain picture: " + error, "app");
|
||||
|
||||
}, options);
|
||||
}
|
||||
```
|
||||
|
||||
## Take a picture and get a FileEntry Object <a name="convert"></a>
|
||||
|
||||
If you want to do something like copy the image to another location, or upload it somewhere using the FileTransfer plugin, you need to get a FileEntry object for the returned picture. To do that, call `window.resolveLocalFileSystemURL` on the file URI returned by the Camera app. If you need to use a FileEntry object, set the `destinationType` to `Camera.DestinationType.FILE_URI` in your CameraOptions object (this is also the default value).
|
||||
|
||||
>*Note* You need the [File plugin](https://www.npmjs.com/package/cordova-plugin-file) to call `window.resolveLocalFileSystemURL`.
|
||||
|
||||
Here is the call to `window.resolveLocalFileSystemURL`. The image URI is passed to this function from the success callback of `getPicture`. The success handler of `resolveLocalFileSystemURL` receives the FileEntry object.
|
||||
|
||||
```js
|
||||
function getFileEntry(imgUri) {
|
||||
window.resolveLocalFileSystemURL(imgUri, function success(fileEntry) {
|
||||
|
||||
// Do something with the FileEntry object, like write to it, upload it, etc.
|
||||
// writeFile(fileEntry, imgUri);
|
||||
console.log("got file: " + fileEntry.fullPath);
|
||||
// displayFileData(fileEntry.nativeURL, "Native URL");
|
||||
|
||||
}, function () {
|
||||
// If don't get the FileEntry (which may happen when testing
|
||||
// on some emulators), copy to a new FileEntry.
|
||||
createNewFileEntry(imgUri);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
In the example shown in the preceding code, you call the app's `createNewFileEntry` function if you don't get a valid FileEntry object. The image URI returned from the Camera app should result in a valid FileEntry, but platform behavior on some emulators may be different for files returned from the file picker.
|
||||
|
||||
>*Note* To see an example of writing to a FileEntry, see the [File plugin README](https://www.npmjs.com/package/cordova-plugin-file).
|
||||
|
||||
The code shown here creates a file in your app's cache (in sandboxed storage) named `tempFile.jpeg`. With the new FileEntry object, you can copy the image to the file or do something else like upload it.
|
||||
|
||||
```js
|
||||
function createNewFileEntry(imgUri) {
|
||||
window.resolveLocalFileSystemURL(cordova.file.cacheDirectory, function success(dirEntry) {
|
||||
|
||||
// JPEG file
|
||||
dirEntry.getFile("tempFile.jpeg", { create: true, exclusive: false }, function (fileEntry) {
|
||||
|
||||
// Do something with it, like write to it, upload it, etc.
|
||||
// writeFile(fileEntry, imgUri);
|
||||
console.log("got file: " + fileEntry.fullPath);
|
||||
// displayFileData(fileEntry.fullPath, "File copied to");
|
||||
|
||||
}, onErrorCreateFile);
|
||||
|
||||
}, onErrorResolveUrl);
|
||||
}
|
||||
```
|
||||
|
||||
472
RELEASENOTES.md
Normal file
472
RELEASENOTES.md
Normal file
@@ -0,0 +1,472 @@
|
||||
<!--
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
-->
|
||||
# Release Notes
|
||||
|
||||
### 5.0.1 (Nov 04, 2020)
|
||||
|
||||
* [GH-686](https://github.com/apache/cordova-plugin-camera/pull/686) chore(android): add missing apache license header
|
||||
* [GH-685](https://github.com/apache/cordova-plugin-camera/pull/685) fix(ios): correctly append exif on **iOS** 14
|
||||
* [GH-669](https://github.com/apache/cordova-plugin-camera/pull/669) fix(android): save to photo gallery - fixes issues [#341](https://github.com/apache/cordova-plugin-camera/pull/341) & [#577](https://github.com/apache/cordova-plugin-camera/pull/577)
|
||||
* [GH-672](https://github.com/apache/cordova-plugin-camera/pull/672) chore: Fix JIRA links in RELEASENOTES.md
|
||||
* [GH-664](https://github.com/apache/cordova-plugin-camera/pull/664) chore: Update RELEASENOTES
|
||||
|
||||
### 5.0.0 (Sep 14, 2020)
|
||||
|
||||
* [GH-648](https://github.com/apache/cordova-plugin-camera/pull/648) ci(travis): update osx xcode image
|
||||
* [GH-637](https://github.com/apache/cordova-plugin-camera/pull/637) breaking: remove `NATIVE_URI` DestinationType
|
||||
* [GH-628](https://github.com/apache/cordova-plugin-camera/pull/628) breaking: bump project requirements
|
||||
* [GH-634](https://github.com/apache/cordova-plugin-camera/pull/634) chore: remove deprecated `file-transfer` plugin
|
||||
* [GH-632](https://github.com/apache/cordova-plugin-camera/pull/632) fix(android): return error if file url is null
|
||||
* [GH-510](https://github.com/apache/cordova-plugin-camera/pull/510) fix(android): use provider prefix to avoid conflicts other plugin providers
|
||||
* [GH-617](https://github.com/apache/cordova-plugin-camera/pull/617) breaking(android): stop using `CordovaUri` helper class
|
||||
* [GH-630](https://github.com/apache/cordova-plugin-camera/pull/630) chore: add `package-lock.json`
|
||||
* [GH-631](https://github.com/apache/cordova-plugin-camera/pull/631) chore(package): use short notation
|
||||
* [GH-629](https://github.com/apache/cordova-plugin-camera/pull/629) feat: migrate to `@cordova/eslint-config@3.x`
|
||||
* [GH-626](https://github.com/apache/cordova-plugin-camera/pull/626) ci: fix additional tests
|
||||
* [GH-627](https://github.com/apache/cordova-plugin-camera/pull/627) breaking: bump version 5.0.0-dev
|
||||
* [GH-612](https://github.com/apache/cordova-plugin-camera/pull/612) fix(ios): `tempFilePath` called twice if using `CameraUsesGeolocation`
|
||||
* [GH-588](https://github.com/apache/cordova-plugin-camera/pull/588) Cache images in device storage, devices have enough space now.
|
||||
* [GH-508](https://github.com/apache/cordova-plugin-camera/pull/508) docs(readme): app renamed to Google Photos
|
||||
* chore(asf): update git notification settings
|
||||
* [GH-580](https://github.com/apache/cordova-plugin-camera/pull/580) fix(ios): return copy of video when picking from gallery on **iOS** 13
|
||||
* Update CONTRIBUTING.md
|
||||
* [GH-551](https://github.com/apache/cordova-plugin-camera/pull/551) Fix UI API called on a background thread
|
||||
* [GH-576](https://github.com/apache/cordova-plugin-camera/pull/576) ci: updates Node.js versions
|
||||
* [GH-575](https://github.com/apache/cordova-plugin-camera/pull/575) chore(npm): adds ignore list
|
||||
* [GH-513](https://github.com/apache/cordova-plugin-camera/pull/513) docs(README): remove confusing comment
|
||||
* [GH-512](https://github.com/apache/cordova-plugin-camera/pull/512) docs(README): remove orphan **Windows** phone 7 note
|
||||
* [GH-306](https://github.com/apache/cordova-plugin-camera/pull/306) ImagePicker returning same image
|
||||
|
||||
### 4.1.0 (Jun 27, 2019)
|
||||
|
||||
- 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/CB-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/CB-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/CB-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/CB-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/CB-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/CB-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/CB-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/CB-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
|
||||
* getPicture via web activities
|
||||
* [ubuntu] specify policy_group
|
||||
* add ubuntu platform
|
||||
* 1. User Agent detection now detects AmazonWebView. 2. Change to use amazon-fireos as the platform if user agent string contains 'cordova-amazon-fireos'
|
||||
* Added amazon-fireos platform.
|
||||
|
||||
### 0.2.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.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.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
|
||||
1724
package-lock.json
generated
Normal file
1724
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
56
package.json
Normal file
56
package.json
Normal file
@@ -0,0 +1,56 @@
|
||||
{
|
||||
"name": "cordova-plugin-camera",
|
||||
"version": "5.0.1",
|
||||
"description": "Cordova Camera Plugin",
|
||||
"types": "./types/index.d.ts",
|
||||
"cordova": {
|
||||
"id": "cordova-plugin-camera",
|
||||
"platforms": [
|
||||
"android",
|
||||
"ios",
|
||||
"browser",
|
||||
"windows",
|
||||
"osx"
|
||||
]
|
||||
},
|
||||
"repository": "github:apache/cordova-plugin-camera",
|
||||
"bugs": "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 lint",
|
||||
"lint": "eslint ."
|
||||
},
|
||||
"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-android": ">=9.0.0",
|
||||
"cordova-ios": ">=5.1.0",
|
||||
"cordova": ">=9.0.0"
|
||||
},
|
||||
"6.0.0": {
|
||||
"cordova": ">100"
|
||||
}
|
||||
}
|
||||
},
|
||||
"devDependencies": {
|
||||
"@cordova/eslint-config": "^3.0.0"
|
||||
}
|
||||
}
|
||||
163
plugin.xml
Normal file
163
plugin.xml
Normal file
@@ -0,0 +1,163 @@
|
||||
<?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="cordova-plugin-camera"
|
||||
version="5.0.1">
|
||||
<name>Camera</name>
|
||||
<description>Cordova Camera Plugin</description>
|
||||
<license>Apache 2.0</license>
|
||||
<keywords>cordova,camera</keywords>
|
||||
<repo>https://github.com/apache/cordova-plugin-camera</repo>
|
||||
<issue>https://github.com/apache/cordova-plugin-camera/issues</issue>
|
||||
|
||||
<engines>
|
||||
<engine name="cordova" version=">=9.0.0"/>
|
||||
<engine name="cordova-android" version=">=9.0.0" />
|
||||
<engine name="cordova-ios" version=">=5.1.0" />
|
||||
</engines>
|
||||
|
||||
<js-module src="www/CameraConstants.js" name="Camera">
|
||||
<clobbers target="Camera" />
|
||||
</js-module>
|
||||
|
||||
<js-module src="www/CameraPopoverOptions.js" name="CameraPopoverOptions">
|
||||
<clobbers target="CameraPopoverOptions" />
|
||||
</js-module>
|
||||
|
||||
<js-module src="www/Camera.js" name="camera">
|
||||
<clobbers target="navigator.camera" />
|
||||
</js-module>
|
||||
|
||||
<!-- android -->
|
||||
<platform name="android">
|
||||
<config-file target="res/xml/config.xml" parent="/*">
|
||||
<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>
|
||||
<config-file target="AndroidManifest.xml" parent="application">
|
||||
<provider
|
||||
android:name="org.apache.cordova.camera.FileProvider"
|
||||
android:authorities="${applicationId}.cordova.plugin.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/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/GalleryPathVO.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>
|
||||
|
||||
<preference name="ANDROID_SUPPORT_V4_VERSION" default="27.+"/>
|
||||
<framework src="com.android.support:support-v4:$ANDROID_SUPPORT_V4_VERSION"/>
|
||||
|
||||
</platform>
|
||||
|
||||
<!-- 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" />
|
||||
<framework src="MobileCoreServices.framework" />
|
||||
<framework src="CoreGraphics.framework" />
|
||||
<framework src="AVFoundation.framework" />
|
||||
|
||||
</platform>
|
||||
|
||||
<!-- browser -->
|
||||
<platform name="browser">
|
||||
<config-file target="config.xml" parent="/*">
|
||||
<feature name="Camera">
|
||||
<param name="browser-package" value="Camera" />
|
||||
</feature>
|
||||
</config-file>
|
||||
|
||||
<js-module src="src/browser/CameraProxy.js" name="CameraProxy">
|
||||
<runs />
|
||||
</js-module>
|
||||
</platform>
|
||||
|
||||
<!-- windows -->
|
||||
<platform name="windows">
|
||||
<config-file target="package.appxmanifest" parent="/Package/Capabilities">
|
||||
<DeviceCapability Name="webcam" />
|
||||
</config-file>
|
||||
<js-module src="www/CameraPopoverHandle.js" name="CameraPopoverHandle">
|
||||
<clobbers target="CameraPopoverHandle" />
|
||||
</js-module>
|
||||
<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>
|
||||
1380
src/android/CameraLauncher.java
Normal file
1380
src/android/CameraLauncher.java
Normal file
File diff suppressed because it is too large
Load Diff
185
src/android/ExifHelper.java
Normal file
185
src/android/ExifHelper.java
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package org.apache.cordova.camera;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import android.media.ExifInterface;
|
||||
|
||||
public class ExifHelper {
|
||||
private String aperture = null;
|
||||
private String datetime = null;
|
||||
private String exposureTime = null;
|
||||
private String flash = null;
|
||||
private String focalLength = null;
|
||||
private String gpsAltitude = null;
|
||||
private String gpsAltitudeRef = null;
|
||||
private String gpsDateStamp = null;
|
||||
private String gpsLatitude = null;
|
||||
private String gpsLatitudeRef = null;
|
||||
private String gpsLongitude = null;
|
||||
private String gpsLongitudeRef = null;
|
||||
private String gpsProcessingMethod = null;
|
||||
private String gpsTimestamp = null;
|
||||
private String iso = null;
|
||||
private String make = null;
|
||||
private String model = null;
|
||||
private String orientation = null;
|
||||
private String whiteBalance = null;
|
||||
|
||||
private ExifInterface inFile = null;
|
||||
private ExifInterface outFile = null;
|
||||
|
||||
/**
|
||||
* The file before it is compressed
|
||||
*
|
||||
* @param filePath
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createInFile(String filePath) throws IOException {
|
||||
this.inFile = new ExifInterface(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* The file after it has been compressed
|
||||
*
|
||||
* @param filePath
|
||||
* @throws IOException
|
||||
*/
|
||||
public void createOutFile(String filePath) throws IOException {
|
||||
this.outFile = new ExifInterface(filePath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads all the EXIF data from the input file.
|
||||
*/
|
||||
public void readExifData() {
|
||||
this.aperture = inFile.getAttribute(ExifInterface.TAG_APERTURE);
|
||||
this.datetime = inFile.getAttribute(ExifInterface.TAG_DATETIME);
|
||||
this.exposureTime = inFile.getAttribute(ExifInterface.TAG_EXPOSURE_TIME);
|
||||
this.flash = inFile.getAttribute(ExifInterface.TAG_FLASH);
|
||||
this.focalLength = inFile.getAttribute(ExifInterface.TAG_FOCAL_LENGTH);
|
||||
this.gpsAltitude = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE);
|
||||
this.gpsAltitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF);
|
||||
this.gpsDateStamp = inFile.getAttribute(ExifInterface.TAG_GPS_DATESTAMP);
|
||||
this.gpsLatitude = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE);
|
||||
this.gpsLatitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF);
|
||||
this.gpsLongitude = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE);
|
||||
this.gpsLongitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF);
|
||||
this.gpsProcessingMethod = inFile.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD);
|
||||
this.gpsTimestamp = inFile.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP);
|
||||
this.iso = inFile.getAttribute(ExifInterface.TAG_ISO);
|
||||
this.make = inFile.getAttribute(ExifInterface.TAG_MAKE);
|
||||
this.model = inFile.getAttribute(ExifInterface.TAG_MODEL);
|
||||
this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION);
|
||||
this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the previously stored EXIF data to the output file.
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
public void writeExifData() throws IOException {
|
||||
// Don't try to write to a null file
|
||||
if (this.outFile == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.aperture != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperture);
|
||||
}
|
||||
if (this.datetime != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_DATETIME, this.datetime);
|
||||
}
|
||||
if (this.exposureTime != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, this.exposureTime);
|
||||
}
|
||||
if (this.flash != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_FLASH, this.flash);
|
||||
}
|
||||
if (this.focalLength != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, this.focalLength);
|
||||
}
|
||||
if (this.gpsAltitude != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, this.gpsAltitude);
|
||||
}
|
||||
if (this.gpsAltitudeRef != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, this.gpsAltitudeRef);
|
||||
}
|
||||
if (this.gpsDateStamp != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, this.gpsDateStamp);
|
||||
}
|
||||
if (this.gpsLatitude != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE, this.gpsLatitude);
|
||||
}
|
||||
if (this.gpsLatitudeRef != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, this.gpsLatitudeRef);
|
||||
}
|
||||
if (this.gpsLongitude != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, this.gpsLongitude);
|
||||
}
|
||||
if (this.gpsLongitudeRef != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, this.gpsLongitudeRef);
|
||||
}
|
||||
if (this.gpsProcessingMethod != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, this.gpsProcessingMethod);
|
||||
}
|
||||
if (this.gpsTimestamp != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, this.gpsTimestamp);
|
||||
}
|
||||
if (this.iso != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_ISO, this.iso);
|
||||
}
|
||||
if (this.make != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_MAKE, this.make);
|
||||
}
|
||||
if (this.model != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_MODEL, this.model);
|
||||
}
|
||||
if (this.orientation != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_ORIENTATION, this.orientation);
|
||||
}
|
||||
if (this.whiteBalance != null) {
|
||||
this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance);
|
||||
}
|
||||
|
||||
this.outFile.saveAttributes();
|
||||
}
|
||||
|
||||
public int getOrientation() {
|
||||
int o = Integer.parseInt(this.orientation);
|
||||
|
||||
if (o == ExifInterface.ORIENTATION_NORMAL) {
|
||||
return 0;
|
||||
} else if (o == ExifInterface.ORIENTATION_ROTATE_90) {
|
||||
return 90;
|
||||
} else if (o == ExifInterface.ORIENTATION_ROTATE_180) {
|
||||
return 180;
|
||||
} else if (o == ExifInterface.ORIENTATION_ROTATE_270) {
|
||||
return 270;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void resetOrientation() {
|
||||
this.orientation = "" + ExifInterface.ORIENTATION_NORMAL;
|
||||
}
|
||||
}
|
||||
319
src/android/FileHelper.java
Normal file
319
src/android/FileHelper.java
Normal file
@@ -0,0 +1,319 @@
|
||||
/*
|
||||
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.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;
|
||||
import org.apache.cordova.LOG;
|
||||
|
||||
import java.io.FileInputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Locale;
|
||||
|
||||
public class FileHelper {
|
||||
private static final String LOG_TAG = "FileUtils";
|
||||
private static final String _DATA = "_data";
|
||||
|
||||
/**
|
||||
* Returns the real path of the given URI string.
|
||||
* If the given URI string represents a content:// URI, the real path is retrieved from the media store.
|
||||
*
|
||||
* @param uriString the URI string of the audio/image/video
|
||||
* @param cordova the current application context
|
||||
* @return the full path to the file
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
public static String getRealPath(Uri uri, CordovaInterface cordova) {
|
||||
return FileHelper.getRealPathFromURI(cordova.getActivity(), uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the real path of the given URI.
|
||||
* If the given URI is a content:// URI, the real path is retrieved from the media store.
|
||||
*
|
||||
* @param uri the URI of the audio/image/video
|
||||
* @param cordova the current application context
|
||||
* @return the full path to the file
|
||||
*/
|
||||
public static String getRealPath(String uriString, CordovaInterface cordova) {
|
||||
return FileHelper.getRealPath(Uri.parse(uriString), cordova);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
public static String getRealPathFromURI(final Context context, final Uri uri) {
|
||||
// DocumentProvider
|
||||
if (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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an input stream based on given URI string.
|
||||
*
|
||||
* @param uriString the URI string from which to obtain the input stream
|
||||
* @param cordova the current application context
|
||||
* @return an input stream into the data at the given URI or null if given an invalid URI string
|
||||
* @throws IOException
|
||||
*/
|
||||
public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova)
|
||||
throws IOException {
|
||||
InputStream returnValue = null;
|
||||
if (uriString.startsWith("content")) {
|
||||
Uri uri = Uri.parse(uriString);
|
||||
returnValue = cordova.getActivity().getContentResolver().openInputStream(uri);
|
||||
} else if (uriString.startsWith("file://")) {
|
||||
int question = uriString.indexOf("?");
|
||||
if (question > -1) {
|
||||
uriString = uriString.substring(0, question);
|
||||
}
|
||||
if (uriString.startsWith("file:///android_asset/")) {
|
||||
Uri uri = Uri.parse(uriString);
|
||||
String relativePath = uri.getPath().substring(15);
|
||||
returnValue = cordova.getActivity().getAssets().open(relativePath);
|
||||
} else {
|
||||
// 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 {
|
||||
returnValue = new FileInputStream(uriString);
|
||||
}
|
||||
return returnValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the "file://" prefix from the given URI string, if applicable.
|
||||
* If the given URI string doesn't have a "file://" prefix, it is returned unchanged.
|
||||
*
|
||||
* @param uriString the URI string to operate on
|
||||
* @return a path without the "file://" prefix
|
||||
*/
|
||||
public static String stripFileProtocol(String uriString) {
|
||||
if (uriString.startsWith("file://")) {
|
||||
uriString = uriString.substring(7);
|
||||
}
|
||||
return uriString;
|
||||
}
|
||||
|
||||
public static String getMimeTypeForExtension(String path) {
|
||||
String extension = path;
|
||||
int lastDot = extension.lastIndexOf('.');
|
||||
if (lastDot != -1) {
|
||||
extension = extension.substring(lastDot + 1);
|
||||
}
|
||||
// Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185).
|
||||
extension = extension.toLowerCase(Locale.getDefault());
|
||||
if (extension.equals("3ga")) {
|
||||
return "audio/3gpp";
|
||||
}
|
||||
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the mime type of the data specified by the given URI string.
|
||||
*
|
||||
* @param uriString the URI string of the data
|
||||
* @return the mime type of the specified data
|
||||
*/
|
||||
public static String getMimeType(String uriString, CordovaInterface cordova) {
|
||||
String mimeType = null;
|
||||
|
||||
Uri uri = Uri.parse(uriString);
|
||||
if (uriString.startsWith("content://")) {
|
||||
mimeType = cordova.getActivity().getContentResolver().getType(uri);
|
||||
} else {
|
||||
mimeType = getMimeTypeForExtension(uri.getPath());
|
||||
}
|
||||
|
||||
return mimeType;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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());
|
||||
}
|
||||
}
|
||||
21
src/android/FileProvider.java
Normal file
21
src/android/FileProvider.java
Normal 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 {}
|
||||
43
src/android/GalleryPathVO.java
Normal file
43
src/android/GalleryPathVO.java
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
package org.apache.cordova.camera;
|
||||
|
||||
public class GalleryPathVO {
|
||||
private final String galleryPath;
|
||||
private String picturesDirectory;
|
||||
private String galleryFileName;
|
||||
|
||||
public GalleryPathVO(String picturesDirectory, String galleryFileName) {
|
||||
this.picturesDirectory = picturesDirectory;
|
||||
this.galleryFileName = galleryFileName;
|
||||
this.galleryPath = this.picturesDirectory + "/" + this.galleryFileName;
|
||||
}
|
||||
|
||||
public String getGalleryPath() {
|
||||
return galleryPath;
|
||||
}
|
||||
|
||||
public String getPicturesDirectory() {
|
||||
return picturesDirectory;
|
||||
}
|
||||
|
||||
public String getGalleryFileName() {
|
||||
return galleryFileName;
|
||||
}
|
||||
}
|
||||
21
src/android/xml/camera_provider_paths.xml
Normal file
21
src/android/xml/camera_provider_paths.xml
Normal 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="cache_files" path="." />
|
||||
</paths>
|
||||
126
src/browser/CameraProxy.js
Normal file
126
src/browser/CameraProxy.js
Normal 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);
|
||||
115
src/ios/CDVCamera.h
Normal file
115
src/ios/CDVCamera.h
Normal file
@@ -0,0 +1,115 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <CoreLocation/CoreLocation.h>
|
||||
#import <CoreLocation/CLLocationManager.h>
|
||||
#import <Cordova/CDVPlugin.h>
|
||||
|
||||
enum CDVDestinationType {
|
||||
DestinationTypeDataUrl = 0,
|
||||
DestinationTypeFileUri
|
||||
};
|
||||
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 CDVCamera : CDVPlugin <UIImagePickerControllerDelegate,
|
||||
UINavigationControllerDelegate,
|
||||
UIPopoverControllerDelegate,
|
||||
CLLocationManagerDelegate>
|
||||
{}
|
||||
|
||||
@property (strong) CDVCameraPicker* pickerController;
|
||||
@property (strong) NSMutableDictionary *metadata;
|
||||
@property (strong, nonatomic) CLLocationManager *locationManager;
|
||||
@property (strong) NSData* data;
|
||||
|
||||
/*
|
||||
* getPicture
|
||||
*
|
||||
* arguments:
|
||||
* 1: this is the javascript function that will be called with the results, the first parameter passed to the
|
||||
* javascript function is the picture as a Base64 encoded string
|
||||
* 2: this is the javascript function to be called if there was an error
|
||||
* options:
|
||||
* quality: integer between 1 and 100
|
||||
*/
|
||||
- (void)takePicture:(CDVInvokedUrlCommand*)command;
|
||||
- (void)cleanup:(CDVInvokedUrlCommand*)command;
|
||||
- (void)repositionPopover:(CDVInvokedUrlCommand*)command;
|
||||
|
||||
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info;
|
||||
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo;
|
||||
- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker;
|
||||
- (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated;
|
||||
|
||||
- (void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation;
|
||||
- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error;
|
||||
|
||||
@end
|
||||
750
src/ios/CDVCamera.m
Normal file
750
src/ios/CDVCamera.m
Normal file
@@ -0,0 +1,750 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVCamera.h"
|
||||
#import "CDVJpegHeaderWriter.h"
|
||||
#import "UIImage+CropScaleOrientation.h"
|
||||
#import <ImageIO/CGImageProperties.h>
|
||||
#import <AssetsLibrary/ALAssetRepresentation.h>
|
||||
#import <AssetsLibrary/AssetsLibrary.h>
|
||||
#import <AVFoundation/AVFoundation.h>
|
||||
#import <ImageIO/CGImageSource.h>
|
||||
#import <ImageIO/CGImageProperties.h>
|
||||
#import <ImageIO/CGImageDestination.h>
|
||||
#import <MobileCoreServices/UTCoreTypes.h>
|
||||
#import <objc/message.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:@(50)];
|
||||
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
|
||||
|
||||
|
||||
@interface CDVCamera ()
|
||||
|
||||
@property (readwrite, assign) BOOL hasPendingOperation;
|
||||
|
||||
@end
|
||||
|
||||
@implementation CDVCamera
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
org_apache_cordova_validArrowDirections = [[NSSet alloc] initWithObjects:[NSNumber numberWithInt:UIPopoverArrowDirectionUp], [NSNumber numberWithInt:UIPopoverArrowDirectionDown], [NSNumber numberWithInt:UIPopoverArrowDirectionLeft], [NSNumber numberWithInt:UIPopoverArrowDirectionRight], [NSNumber numberWithInt:UIPopoverArrowDirectionAny], nil];
|
||||
}
|
||||
|
||||
@synthesize hasPendingOperation, pickerController, locationManager;
|
||||
|
||||
- (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;
|
||||
}
|
||||
|
||||
- (BOOL)usesGeolocation
|
||||
{
|
||||
id useGeo = [self.commandDelegate.settings objectForKey:[@"CameraUsesGeolocation" lowercaseString]];
|
||||
return [(NSNumber*)useGeo boolValue];
|
||||
}
|
||||
|
||||
- (BOOL)popoverSupported
|
||||
{
|
||||
return (NSClassFromString(@"UIPopoverController") != nil) &&
|
||||
(UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad);
|
||||
}
|
||||
|
||||
- (void)takePicture:(CDVInvokedUrlCommand*)command
|
||||
{
|
||||
self.hasPendingOperation = YES;
|
||||
__weak CDVCamera* weakSelf = self;
|
||||
|
||||
[self.commandDelegate runInBackground:^{
|
||||
CDVPictureOptions* pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command];
|
||||
pictureOptions.popoverSupported = [weakSelf popoverSupported];
|
||||
pictureOptions.usesGeolocation = [weakSelf usesGeolocation];
|
||||
pictureOptions.cropToSize = NO;
|
||||
|
||||
BOOL hasCamera = [UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType];
|
||||
if (!hasCamera) {
|
||||
NSLog(@"Camera.getPicture: source type %lu not available.", (unsigned long)pictureOptions.sourceType);
|
||||
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"No camera available"];
|
||||
[weakSelf.commandDelegate sendPluginResult:result callbackId:command.callbackId];
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate the app has permission to access the camera
|
||||
if (pictureOptions.sourceType == UIImagePickerControllerSourceTypeCamera) {
|
||||
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted)
|
||||
{
|
||||
if(!granted)
|
||||
{
|
||||
// Denied; show an alert
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:[[NSBundle mainBundle] objectForInfoDictionaryKey:@"CFBundleDisplayName"] message:NSLocalizedString(@"Access to the camera has been prohibited; please enable it in the Settings app to continue.", nil) preferredStyle:UIAlertControllerStyleAlert];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"OK", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||||
[weakSelf sendNoPermissionResult:command.callbackId];
|
||||
}]];
|
||||
[alertController addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"Settings", nil) style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
|
||||
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString] options:@{} completionHandler:nil];
|
||||
[weakSelf sendNoPermissionResult:command.callbackId];
|
||||
}]];
|
||||
[weakSelf.viewController presentViewController:alertController animated:YES completion:nil];
|
||||
});
|
||||
} else {
|
||||
[weakSelf showCameraPicker:command.callbackId withOptions:pictureOptions];
|
||||
}
|
||||
}];
|
||||
} else {
|
||||
[weakSelf showCameraPicker:command.callbackId withOptions:pictureOptions];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
- (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;
|
||||
}];
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)sendNoPermissionResult:(NSString*)callbackId
|
||||
{
|
||||
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"has no access to camera"]; // error callback expects string ATM
|
||||
|
||||
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
|
||||
|
||||
self.hasPendingOperation = NO;
|
||||
self.pickerController = nil;
|
||||
}
|
||||
|
||||
- (void)repositionPopover:(CDVInvokedUrlCommand*)command
|
||||
{
|
||||
if (([[self pickerController] pickerPopoverController] != nil) && [[[self pickerController] pickerPopoverController] isPopoverVisible]) {
|
||||
|
||||
[[[self pickerController] pickerPopoverController] dismissPopoverAnimated:NO];
|
||||
|
||||
NSDictionary* options = [command argumentAtIndex:0 withDefault:nil];
|
||||
[self displayPopover:options];
|
||||
}
|
||||
}
|
||||
|
||||
- (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)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated
|
||||
{
|
||||
if([navigationController isKindOfClass:[UIImagePickerController class]]){
|
||||
|
||||
// If popoverWidth and popoverHeight are specified and are greater than 0, then set popover size, else use apple's default popoverSize
|
||||
NSDictionary* options = self.pickerController.pictureOptions.popoverOptions;
|
||||
if(options) {
|
||||
NSInteger popoverWidth = [self integerValueForKey:options key:@"popoverWidth" defaultValue:0];
|
||||
NSInteger popoverHeight = [self integerValueForKey:options key:@"popoverHeight" defaultValue:0];
|
||||
if(popoverWidth > 0 && popoverHeight > 0)
|
||||
{
|
||||
[viewController setPreferredContentSize:CGSizeMake(popoverWidth,popoverHeight)];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
UIImagePickerController* cameraPicker = (UIImagePickerController*)navigationController;
|
||||
|
||||
if(![cameraPicker.mediaTypes containsObject:(NSString*)kUTTypeImage]){
|
||||
[viewController.navigationItem setTitle:NSLocalizedString(@"Videos", nil)];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)cleanup:(CDVInvokedUrlCommand*)command
|
||||
{
|
||||
// empty the tmp directory
|
||||
NSFileManager* fileMgr = [[NSFileManager alloc] init];
|
||||
NSError* err = nil;
|
||||
BOOL hasErrors = NO;
|
||||
|
||||
// clear contents of NSTemporaryDirectory
|
||||
NSString* tempDirectoryPath = NSTemporaryDirectory();
|
||||
NSDirectoryEnumerator* directoryEnumerator = [fileMgr enumeratorAtPath:tempDirectoryPath];
|
||||
NSString* fileName = nil;
|
||||
BOOL result;
|
||||
|
||||
while ((fileName = [directoryEnumerator nextObject])) {
|
||||
// only delete the files we created
|
||||
if (![fileName hasPrefix:CDV_PHOTO_PREFIX]) {
|
||||
continue;
|
||||
}
|
||||
NSString* filePath = [tempDirectoryPath stringByAppendingPathComponent:fileName];
|
||||
result = [fileMgr removeItemAtPath:filePath error:&err];
|
||||
if (!result && err) {
|
||||
NSLog(@"Failed to delete: %@ (error: %@)", filePath, err);
|
||||
hasErrors = YES;
|
||||
}
|
||||
}
|
||||
|
||||
CDVPluginResult* pluginResult;
|
||||
if (hasErrors) {
|
||||
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:@"One or more files failed to be deleted."];
|
||||
} else {
|
||||
pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
|
||||
}
|
||||
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
|
||||
}
|
||||
|
||||
- (void)popoverControllerDidDismissPopover:(id)popoverController
|
||||
{
|
||||
UIPopoverController* pc = (UIPopoverController*)popoverController;
|
||||
|
||||
[pc dismissPopoverAnimated:YES];
|
||||
pc.delegate = nil;
|
||||
if (self.pickerController && self.pickerController.callbackId && self.pickerController.pickerPopoverController) {
|
||||
self.pickerController.pickerPopoverController = nil;
|
||||
NSString* callbackId = self.pickerController.callbackId;
|
||||
CDVPluginResult* result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"no image selected"]; // error callback expects string ATM
|
||||
[self.commandDelegate sendPluginResult:result callbackId:callbackId];
|
||||
}
|
||||
self.hasPendingOperation = NO;
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
data = nil;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
};
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
- (NSString*)tempFilePath:(NSString*)extension
|
||||
{
|
||||
NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
|
||||
// unique file name
|
||||
NSTimeInterval timeStamp = [[NSDate date] timeIntervalSince1970];
|
||||
NSNumber *timeStampObj = [NSNumber numberWithDouble: timeStamp];
|
||||
NSString* filePath = [NSString stringWithFormat:@"%@/%@%ld.%@", docsPath, CDV_PHOTO_PREFIX, [timeStampObj longValue], extension];
|
||||
|
||||
return filePath;
|
||||
}
|
||||
|
||||
- (UIImage*)retrieveImage:(NSDictionary*)info options:(CDVPictureOptions*)options
|
||||
{
|
||||
// get the image
|
||||
UIImage* image = nil;
|
||||
if (options.allowsEditing && [info objectForKey:UIImagePickerControllerEditedImage]) {
|
||||
image = [info objectForKey:UIImagePickerControllerEditedImage];
|
||||
} else {
|
||||
image = [info objectForKey:UIImagePickerControllerOriginalImage];
|
||||
}
|
||||
|
||||
if (options.correctOrientation) {
|
||||
image = [image imageCorrectedForCaptureOrientation];
|
||||
}
|
||||
|
||||
UIImage* scaledImage = nil;
|
||||
|
||||
if ((options.targetSize.width > 0) && (options.targetSize.height > 0)) {
|
||||
// if cropToSize, resize image and crop to target size, otherwise resize to fit target without cropping
|
||||
if (options.cropToSize) {
|
||||
scaledImage = [image imageByScalingAndCroppingForSize:options.targetSize];
|
||||
} else {
|
||||
scaledImage = [image imageByScalingNotCroppingForSize:options.targetSize];
|
||||
}
|
||||
}
|
||||
|
||||
return (scaledImage == nil ? image : scaledImage);
|
||||
}
|
||||
|
||||
- (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 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: // 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;
|
||||
};
|
||||
|
||||
if (saveToPhotoAlbum && image) {
|
||||
UIImageWriteToSavedPhotosAlbum(image, nil, nil, nil);
|
||||
}
|
||||
|
||||
completion(result);
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
- (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];
|
||||
}
|
||||
|
||||
- (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info
|
||||
{
|
||||
__weak CDVCameraPicker* cameraPicker = (CDVCameraPicker*)picker;
|
||||
__weak CDVCamera* weakSelf = self;
|
||||
|
||||
dispatch_block_t invoke = ^(void) {
|
||||
__block CDVPluginResult* result = nil;
|
||||
|
||||
NSString* mediaType = [info objectForKey:UIImagePickerControllerMediaType];
|
||||
if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {
|
||||
[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 CDVCamera* weakSelf = self;
|
||||
|
||||
dispatch_block_t invoke = ^ (void) {
|
||||
CDVPluginResult* result;
|
||||
if (picker.sourceType == UIImagePickerControllerSourceTypeCamera && [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo] != AVAuthorizationStatusAuthorized) {
|
||||
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_ERROR messageAsString:@"has no access to camera"];
|
||||
} 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];
|
||||
}
|
||||
|
||||
- (CLLocationManager*)locationManager
|
||||
{
|
||||
if (locationManager != nil) {
|
||||
return locationManager;
|
||||
}
|
||||
|
||||
locationManager = [[CLLocationManager alloc] init];
|
||||
[locationManager setDesiredAccuracy:kCLLocationAccuracyNearestTenMeters];
|
||||
[locationManager setDelegate:self];
|
||||
|
||||
return locationManager;
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation
|
||||
{
|
||||
if (locationManager == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.locationManager stopUpdatingLocation];
|
||||
self.locationManager = nil;
|
||||
|
||||
NSMutableDictionary *GPSDictionary = [[NSMutableDictionary dictionary] init];
|
||||
|
||||
CLLocationDegrees latitude = newLocation.coordinate.latitude;
|
||||
CLLocationDegrees longitude = newLocation.coordinate.longitude;
|
||||
|
||||
// latitude
|
||||
if (latitude < 0.0) {
|
||||
latitude = latitude * -1.0f;
|
||||
[GPSDictionary setObject:@"S" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
|
||||
} else {
|
||||
[GPSDictionary setObject:@"N" forKey:(NSString*)kCGImagePropertyGPSLatitudeRef];
|
||||
}
|
||||
[GPSDictionary setObject:[NSNumber numberWithFloat:latitude] forKey:(NSString*)kCGImagePropertyGPSLatitude];
|
||||
|
||||
// longitude
|
||||
if (longitude < 0.0) {
|
||||
longitude = longitude * -1.0f;
|
||||
[GPSDictionary setObject:@"W" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
|
||||
}
|
||||
else {
|
||||
[GPSDictionary setObject:@"E" forKey:(NSString*)kCGImagePropertyGPSLongitudeRef];
|
||||
}
|
||||
[GPSDictionary setObject:[NSNumber numberWithFloat:longitude] forKey:(NSString*)kCGImagePropertyGPSLongitude];
|
||||
|
||||
// altitude
|
||||
CGFloat altitude = newLocation.altitude;
|
||||
if (!isnan(altitude)){
|
||||
if (altitude < 0) {
|
||||
altitude = -altitude;
|
||||
[GPSDictionary setObject:@"1" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef];
|
||||
} else {
|
||||
[GPSDictionary setObject:@"0" forKey:(NSString *)kCGImagePropertyGPSAltitudeRef];
|
||||
}
|
||||
[GPSDictionary setObject:[NSNumber numberWithFloat:altitude] forKey:(NSString *)kCGImagePropertyGPSAltitude];
|
||||
}
|
||||
|
||||
// Time and date
|
||||
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
|
||||
[formatter setDateFormat:@"HH:mm:ss.SSSSSS"];
|
||||
[formatter setTimeZone:[NSTimeZone timeZoneWithAbbreviation:@"UTC"]];
|
||||
[GPSDictionary setObject:[formatter stringFromDate:newLocation.timestamp] forKey:(NSString *)kCGImagePropertyGPSTimeStamp];
|
||||
[formatter setDateFormat:@"yyyy:MM:dd"];
|
||||
[GPSDictionary setObject:[formatter stringFromDate:newLocation.timestamp] forKey:(NSString *)kCGImagePropertyGPSDateStamp];
|
||||
|
||||
[self.metadata setObject:GPSDictionary forKey:(NSString *)kCGImagePropertyGPSDictionary];
|
||||
[self imagePickerControllerReturnImageResult];
|
||||
}
|
||||
|
||||
- (void)locationManager:(CLLocationManager*)manager didFailWithError:(NSError*)error
|
||||
{
|
||||
if (locationManager == nil) {
|
||||
return;
|
||||
}
|
||||
|
||||
[self.locationManager stopUpdatingLocation];
|
||||
self.locationManager = nil;
|
||||
|
||||
[self imagePickerControllerReturnImageResult];
|
||||
}
|
||||
|
||||
- (void)imagePickerControllerReturnImageResult
|
||||
{
|
||||
CDVPictureOptions* options = self.pickerController.pictureOptions;
|
||||
CDVPluginResult* result = nil;
|
||||
|
||||
if (self.metadata) {
|
||||
NSData* dataCopy = [self.data mutableCopy];
|
||||
CGImageSourceRef sourceImage = CGImageSourceCreateWithData((__bridge CFDataRef)dataCopy, NULL);
|
||||
CFStringRef sourceType = CGImageSourceGetType(sourceImage);
|
||||
|
||||
CGImageDestinationRef destinationImage = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)self.data, sourceType, 1, NULL);
|
||||
CGImageDestinationAddImageFromSource(destinationImage, sourceImage, 0, (__bridge CFDictionaryRef)self.metadata);
|
||||
CGImageDestinationFinalize(destinationImage);
|
||||
|
||||
dataCopy = nil;
|
||||
CFRelease(sourceImage);
|
||||
CFRelease(destinationImage);
|
||||
}
|
||||
|
||||
switch (options.destinationType) {
|
||||
case DestinationTypeDataUrl:
|
||||
{
|
||||
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:toBase64(self.data)];
|
||||
}
|
||||
break;
|
||||
default: // DestinationTypeFileUri
|
||||
{
|
||||
NSError* err = nil;
|
||||
NSString* extension = self.pickerController.pictureOptions.encodingType == EncodingTypePNG ? @"png":@"jpg";
|
||||
NSString* filePath = [self tempFilePath:extension];
|
||||
|
||||
// save file
|
||||
if (![self.data writeToFile:filePath options:NSAtomicWrite error:&err]) {
|
||||
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_IO_EXCEPTION messageAsString:[err localizedDescription]];
|
||||
}
|
||||
else {
|
||||
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:[[self urlTransformer:[NSURL fileURLWithPath:filePath]] absoluteString]];
|
||||
}
|
||||
}
|
||||
break;
|
||||
};
|
||||
|
||||
if (result) {
|
||||
[self.commandDelegate sendPluginResult:result callbackId:self.pickerController.callbackId];
|
||||
}
|
||||
|
||||
self.hasPendingOperation = NO;
|
||||
self.pickerController = nil;
|
||||
self.data = nil;
|
||||
self.metadata = nil;
|
||||
|
||||
if (options.saveToPhotoAlbum) {
|
||||
UIImageWriteToSavedPhotosAlbum([[UIImage alloc] initWithData:self.data], nil, nil, nil);
|
||||
}
|
||||
}
|
||||
|
||||
@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
|
||||
43
src/ios/CDVExif.h
Normal file
43
src/ios/CDVExif.h
Normal file
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#ifndef CordovaLib_ExifData_h
|
||||
#define CordovaLib_ExifData_h
|
||||
|
||||
// exif data types
|
||||
typedef enum exifDataTypes {
|
||||
EDT_UBYTE = 1, // 8 bit unsigned integer
|
||||
EDT_ASCII_STRING, // 8 bits containing 7 bit ASCII code, null terminated
|
||||
EDT_USHORT, // 16 bit unsigned integer
|
||||
EDT_ULONG, // 32 bit unsigned integer
|
||||
EDT_URATIONAL, // 2 longs, first is numerator and second is denominator
|
||||
EDT_SBYTE,
|
||||
EDT_UNDEFINED, // 8 bits
|
||||
EDT_SSHORT,
|
||||
EDT_SLONG, // 32bit signed integer (2's complement)
|
||||
EDT_SRATIONAL, // 2 SLONGS, first long is numerator, second is denominator
|
||||
EDT_SINGLEFLOAT,
|
||||
EDT_DOUBLEFLOAT
|
||||
} ExifDataTypes;
|
||||
|
||||
// maps integer code for exif data types to width in bytes
|
||||
static const int DataTypeToWidth[] = {1,1,2,4,8,1,1,2,4,8,4,8};
|
||||
|
||||
static const int RECURSE_HORIZON = 8;
|
||||
#endif
|
||||
62
src/ios/CDVJpegHeaderWriter.h
Normal file
62
src/ios/CDVJpegHeaderWriter.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@interface CDVJpegHeaderWriter : NSObject {
|
||||
NSDictionary * SubIFDTagFormatDict;
|
||||
NSDictionary * IFD0TagFormatDict;
|
||||
}
|
||||
|
||||
- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata
|
||||
withExifBlock: (NSString*) exifstr;
|
||||
- (NSString*) createExifAPP1 : (NSDictionary*) datadict;
|
||||
- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb
|
||||
withPlaces: (NSNumber*) width;
|
||||
- (NSString*) formatNumberWithLeadingZeroes: (NSNumber*) numb
|
||||
withPlaces: (NSNumber*) places;
|
||||
- (NSString*) decimalToUnsignedRational: (NSNumber*) numb
|
||||
withResultNumerator: (NSNumber**) numerator
|
||||
withResultDenominator: (NSNumber**) denominator;
|
||||
- (void) continuedFraction: (double) val
|
||||
withFractionList: (NSMutableArray*) fractionlist
|
||||
withHorizon: (int) horizon;
|
||||
//- (void) expandContinuedFraction: (NSArray*) fractionlist;
|
||||
- (void) splitDouble: (double) val
|
||||
withIntComponent: (int*) rightside
|
||||
withFloatRemainder: (double*) leftside;
|
||||
- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator
|
||||
withDenominator: (NSNumber*) denominator
|
||||
asSigned: (Boolean) signedFlag;
|
||||
- (NSString*) hexStringFromData : (NSData*) data;
|
||||
- (NSNumber*) numericFromHexString : (NSString *) hexstring;
|
||||
|
||||
/*
|
||||
- (void) readExifMetaData : (NSData*) imgdata;
|
||||
- (void) spliceImageData : (NSData*) imgdata withExifData: (NSDictionary*) exifdata;
|
||||
- (void) locateExifMetaData : (NSData*) imgdata;
|
||||
- (NSString*) createExifAPP1 : (NSDictionary*) datadict;
|
||||
- (void) createExifDataString : (NSDictionary*) datadict;
|
||||
- (NSString*) createDataElement : (NSString*) element
|
||||
withElementData: (NSString*) data
|
||||
withExternalDataBlock: (NSDictionary*) memblock;
|
||||
- (NSString*) hexStringFromData : (NSData*) data;
|
||||
- (NSNumber*) numericFromHexString : (NSString *) hexstring;
|
||||
*/
|
||||
@end
|
||||
547
src/ios/CDVJpegHeaderWriter.m
Normal file
547
src/ios/CDVJpegHeaderWriter.m
Normal file
@@ -0,0 +1,547 @@
|
||||
/*
|
||||
Licensed to the Apache Software Foundation (ASF) under one
|
||||
or more contributor license agreements. See the NOTICE file
|
||||
distributed with this work for additional information
|
||||
regarding copyright ownership. The ASF licenses this file
|
||||
to you under the Apache License, Version 2.0 (the
|
||||
"License"); you may not use this file except in compliance
|
||||
with the License. You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing,
|
||||
software distributed under the License is distributed on an
|
||||
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
KIND, either express or implied. See the License for the
|
||||
specific language governing permissions and limitations
|
||||
under the License.
|
||||
*/
|
||||
|
||||
#import "CDVJpegHeaderWriter.h"
|
||||
#include "CDVExif.h"
|
||||
|
||||
/* macros for tag info shorthand:
|
||||
tagno : tag number
|
||||
typecode : data type
|
||||
components : number of components
|
||||
appendString (TAGINF_W_APPEND only) : string to append to data
|
||||
Exif date data format include an extra 0x00 to the end of the data
|
||||
*/
|
||||
#define TAGINF(tagno, typecode, components) [NSArray arrayWithObjects: tagno, typecode, components, nil]
|
||||
#define TAGINF_W_APPEND(tagno, typecode, components, appendString) [NSArray arrayWithObjects: tagno, typecode, components, appendString, nil]
|
||||
|
||||
const uint mJpegId = 0xffd8; // JPEG format marker
|
||||
const uint mExifMarker = 0xffe1; // APP1 jpeg header marker
|
||||
const uint mExif = 0x45786966; // ASCII 'Exif', first characters of valid exif header after size
|
||||
const uint mMotorallaByteAlign = 0x4d4d; // 'MM', motorola byte align, msb first or 'sane'
|
||||
const uint mIntelByteAlgin = 0x4949; // 'II', Intel byte align, lsb first or 'batshit crazy reverso world'
|
||||
const uint mTiffLength = 0x2a; // after byte align bits, next to bits are 0x002a(MM) or 0x2a00(II), tiff version number
|
||||
|
||||
|
||||
@implementation CDVJpegHeaderWriter
|
||||
|
||||
- (id) init {
|
||||
self = [super init];
|
||||
// supported tags for exif IFD
|
||||
IFD0TagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
// TAGINF(@"010e", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"ImageDescription",
|
||||
TAGINF_W_APPEND(@"0132", [NSNumber numberWithInt:EDT_ASCII_STRING], @20, @"00"), @"DateTime",
|
||||
TAGINF(@"010f", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Make",
|
||||
TAGINF(@"0110", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Model",
|
||||
TAGINF(@"0131", [NSNumber numberWithInt:EDT_ASCII_STRING], @0), @"Software",
|
||||
TAGINF(@"011a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"XResolution",
|
||||
TAGINF(@"011b", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"YResolution",
|
||||
// currently supplied outside of Exif data block by UIImagePickerControllerMediaMetadata, this is set manually in CDVCamera.m
|
||||
/* TAGINF(@"0112", [NSNumber numberWithInt:EDT_USHORT], @1), @"Orientation",
|
||||
|
||||
// rest of the tags are supported by exif spec, but are not specified by UIImagePickerControllerMediaMedadata
|
||||
// should camera hardware supply these values in future versions, or if they can be derived, ImageHeaderWriter will include them gracefully
|
||||
TAGINF(@"0128", [NSNumber numberWithInt:EDT_USHORT], @1), @"ResolutionUnit",
|
||||
TAGINF(@"013e", [NSNumber numberWithInt:EDT_URATIONAL], @2), @"WhitePoint",
|
||||
TAGINF(@"013f", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"PrimaryChromaticities",
|
||||
TAGINF(@"0211", [NSNumber numberWithInt:EDT_URATIONAL], @3), @"YCbCrCoefficients",
|
||||
TAGINF(@"0213", [NSNumber numberWithInt:EDT_USHORT], @1), @"YCbCrPositioning",
|
||||
TAGINF(@"0214", [NSNumber numberWithInt:EDT_URATIONAL], @6), @"ReferenceBlackWhite",
|
||||
TAGINF(@"8298", [NSNumber numberWithInt:EDT_URATIONAL], @0), @"Copyright",
|
||||
|
||||
// offset to exif subifd, we determine this dynamically based on the size of the main exif IFD
|
||||
TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",*/
|
||||
nil];
|
||||
|
||||
|
||||
// supported tages for exif subIFD
|
||||
SubIFDTagFormatDict = [[NSDictionary alloc] initWithObjectsAndKeys:
|
||||
//TAGINF(@"9000", [NSNumber numberWithInt:], @), @"ExifVersion",
|
||||
//TAGINF(@"9202",[NSNumber numberWithInt:EDT_URATIONAL],@1), @"ApertureValue",
|
||||
//TAGINF(@"9203",[NSNumber numberWithInt:EDT_SRATIONAL],@1), @"BrightnessValue",
|
||||
TAGINF(@"a001",[NSNumber numberWithInt:EDT_USHORT],@1), @"ColorSpace",
|
||||
TAGINF_W_APPEND(@"9004",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeDigitized",
|
||||
TAGINF_W_APPEND(@"9003",[NSNumber numberWithInt:EDT_ASCII_STRING],@20,@"00"), @"DateTimeOriginal",
|
||||
TAGINF(@"a402", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureMode",
|
||||
TAGINF(@"8822", [NSNumber numberWithInt:EDT_USHORT], @1), @"ExposureProgram",
|
||||
//TAGINF(@"829a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"ExposureTime",
|
||||
//TAGINF(@"829d", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FNumber",
|
||||
TAGINF(@"9209", [NSNumber numberWithInt:EDT_USHORT], @1), @"Flash",
|
||||
// FocalLengthIn35mmFilm
|
||||
TAGINF(@"a405", [NSNumber numberWithInt:EDT_USHORT], @1), @"FocalLenIn35mmFilm",
|
||||
//TAGINF(@"920a", [NSNumber numberWithInt:EDT_URATIONAL], @1), @"FocalLength",
|
||||
//TAGINF(@"8827", [NSNumber numberWithInt:EDT_USHORT], @2), @"ISOSpeedRatings",
|
||||
TAGINF(@"9207", [NSNumber numberWithInt:EDT_USHORT],@1), @"MeteringMode",
|
||||
// specific to compressed data
|
||||
TAGINF(@"a002", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelXDimension",
|
||||
TAGINF(@"a003", [NSNumber numberWithInt:EDT_ULONG],@1), @"PixelYDimension",
|
||||
// data type undefined, but this is a DSC camera, so value is always 1, treat as ushort
|
||||
TAGINF(@"a301", [NSNumber numberWithInt:EDT_USHORT],@1), @"SceneType",
|
||||
TAGINF(@"a217",[NSNumber numberWithInt:EDT_USHORT],@1), @"SensingMethod",
|
||||
//TAGINF(@"9201", [NSNumber numberWithInt:EDT_SRATIONAL], @1), @"ShutterSpeedValue",
|
||||
// specifies location of main subject in scene (x,y,wdith,height) expressed before rotation processing
|
||||
//TAGINF(@"9214", [NSNumber numberWithInt:EDT_USHORT], @4), @"SubjectArea",
|
||||
TAGINF(@"a403", [NSNumber numberWithInt:EDT_USHORT], @1), @"WhiteBalance",
|
||||
nil];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata withExifBlock: (NSString*) exifstr {
|
||||
|
||||
CDVJpegHeaderWriter * exifWriter = [[CDVJpegHeaderWriter alloc] init];
|
||||
|
||||
NSMutableData * exifdata = [NSMutableData dataWithCapacity: [exifstr length]/2];
|
||||
int idx;
|
||||
for (idx = 0; idx+1 < [exifstr length]; idx+=2) {
|
||||
NSRange range = NSMakeRange(idx, 2);
|
||||
NSString* hexStr = [exifstr substringWithRange:range];
|
||||
NSScanner* scanner = [NSScanner scannerWithString:hexStr];
|
||||
unsigned int intValue;
|
||||
[scanner scanHexInt:&intValue];
|
||||
[exifdata appendBytes:&intValue length:1];
|
||||
}
|
||||
|
||||
NSMutableData * ddata = [NSMutableData dataWithCapacity: [jpegdata length]];
|
||||
NSMakeRange(0,4);
|
||||
int loc = 0;
|
||||
bool done = false;
|
||||
// read the jpeg data until we encounter the app1==0xFFE1 marker
|
||||
while (loc+1 < [jpegdata length]) {
|
||||
NSData * blag = [jpegdata subdataWithRange: NSMakeRange(loc,2)];
|
||||
if( [[blag description] isEqualToString : @"<ffe1>"]) {
|
||||
// read the APP1 block size bits
|
||||
NSString * the = [exifWriter hexStringFromData:[jpegdata subdataWithRange: NSMakeRange(loc+2,2)]];
|
||||
NSNumber * app1width = [exifWriter numericFromHexString:the];
|
||||
//consume the original app1 block
|
||||
[ddata appendData:exifdata];
|
||||
// advance our loc marker past app1
|
||||
loc += [app1width intValue] + 2;
|
||||
done = true;
|
||||
} else {
|
||||
if(!done) {
|
||||
[ddata appendData:blag];
|
||||
loc += 2;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
// copy the remaining data
|
||||
[ddata appendData:[jpegdata subdataWithRange: NSMakeRange(loc,[jpegdata length]-loc)]];
|
||||
return ddata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Create the Exif data block as a hex string
|
||||
* jpeg uses Application Markers (APP's) as markers for application data
|
||||
* APP1 is the application marker reserved for exif data
|
||||
*
|
||||
* (NSDictionary*) datadict - with subdictionaries marked '{TIFF}' and '{EXIF}' as returned by imagePickerController with a valid
|
||||
* didFinishPickingMediaWithInfo data dict, under key @"UIImagePickerControllerMediaMetadata"
|
||||
*
|
||||
* the following constructs a hex string to Exif specifications, and is therefore brittle
|
||||
* altering the order of arguments to the string constructors, modifying field sizes or formats,
|
||||
* and any other minor change will likely prevent the exif data from being read
|
||||
*/
|
||||
- (NSString*) createExifAPP1 : (NSDictionary*) datadict {
|
||||
NSMutableString * app1; // holds finalized product
|
||||
NSString * exifIFD; // exif information file directory
|
||||
NSString * subExifIFD; // subexif information file directory
|
||||
|
||||
// FFE1 is the hex APP1 marker code, and will allow client apps to read the data
|
||||
NSString * app1marker = @"ffe1";
|
||||
// SSSS size, to be determined
|
||||
// EXIF ascii characters followed by 2bytes of zeros
|
||||
NSString * exifmarker = @"457869660000";
|
||||
// Tiff header: 4d4d is motorolla byte align (big endian), 002a is hex for 42
|
||||
NSString * tiffheader = @"4d4d002a";
|
||||
//first IFD offset from the Tiff header to IFD0. Since we are writing it, we know it's address 0x08
|
||||
NSString * ifd0offset = @"00000008";
|
||||
// current offset to next data area
|
||||
int currentDataOffset = 0;
|
||||
|
||||
//data labeled as TIFF in UIImagePickerControllerMediaMetaData is part of the EXIF IFD0 portion of APP1
|
||||
exifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{TIFF}"] withFormatDict: IFD0TagFormatDict isIFD0:YES currentDataOffset:¤tDataOffset];
|
||||
|
||||
//data labeled as EXIF in UIImagePickerControllerMediaMetaData is part of the EXIF Sub IFD portion of APP1
|
||||
subExifIFD = [self createExifIFDFromDict: [datadict objectForKey:@"{Exif}"] withFormatDict: SubIFDTagFormatDict isIFD0:NO currentDataOffset:¤tDataOffset];
|
||||
/*
|
||||
NSLog(@"SUB EXIF IFD %@ WITH SIZE: %d",exifIFD,[exifIFD length]);
|
||||
|
||||
NSLog(@"SUB EXIF IFD %@ WITH SIZE: %d",subExifIFD,[subExifIFD length]);
|
||||
*/
|
||||
// construct the complete app1 data block
|
||||
app1 = [[NSMutableString alloc] initWithFormat: @"%@%04x%@%@%@%@%@",
|
||||
app1marker,
|
||||
(unsigned int)(16 + ([exifIFD length]/2) + ([subExifIFD length]/2)) /*16+[exifIFD length]/2*/,
|
||||
exifmarker,
|
||||
tiffheader,
|
||||
ifd0offset,
|
||||
exifIFD,
|
||||
subExifIFD];
|
||||
|
||||
return app1;
|
||||
}
|
||||
|
||||
// returns hex string representing a valid exif information file directory constructed from the datadict and formatdict
|
||||
- (NSString*) createExifIFDFromDict : (NSDictionary*) datadict
|
||||
withFormatDict : (NSDictionary*) formatdict
|
||||
isIFD0 : (BOOL) ifd0flag
|
||||
currentDataOffset : (int*) dataoffset {
|
||||
NSArray * datakeys = [datadict allKeys]; // all known data keys
|
||||
NSArray * knownkeys = [formatdict allKeys]; // only keys in knowkeys are considered for entry in this IFD
|
||||
NSMutableArray * ifdblock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // all ifd entries
|
||||
NSMutableArray * ifddatablock = [[NSMutableArray alloc] initWithCapacity: [datadict count]]; // data block entries
|
||||
// ifd0flag = NO; // ifd0 requires a special flag and has offset to next ifd appended to end
|
||||
|
||||
// iterate through known provided data keys
|
||||
for (int i = 0; i < [datakeys count]; i++) {
|
||||
NSString * key = [datakeys objectAtIndex:i];
|
||||
// don't muck about with unknown keys
|
||||
if ([knownkeys indexOfObject: key] != NSNotFound) {
|
||||
// create new IFD entry
|
||||
NSString * entry = [self createIFDElement: key
|
||||
withFormat: [formatdict objectForKey:key]
|
||||
withElementData: [datadict objectForKey:key]];
|
||||
// create the IFD entry's data block
|
||||
NSString * data = [self createIFDElementDataWithFormat: [formatdict objectForKey:key]
|
||||
withData: [datadict objectForKey:key]];
|
||||
if (entry) {
|
||||
[ifdblock addObject:entry];
|
||||
if(!data) {
|
||||
[ifdblock addObject:@""];
|
||||
} else {
|
||||
[ifddatablock addObject:data];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
NSMutableString * exifstr = [[NSMutableString alloc] initWithCapacity: [ifdblock count] * 24];
|
||||
NSMutableString * dbstr = [[NSMutableString alloc] initWithCapacity: 100];
|
||||
|
||||
int addr=*dataoffset; // current offset/address in datablock
|
||||
if (ifd0flag) {
|
||||
// calculate offset to datablock based on ifd file entry count
|
||||
addr += 14+(12*([ifddatablock count]+1)); // +1 for tag 0x8769, exifsubifd offset
|
||||
} else {
|
||||
// current offset + numSubIFDs (2-bytes) + 12*numSubIFDs + endMarker (4-bytes)
|
||||
addr += 2+(12*[ifddatablock count])+4;
|
||||
}
|
||||
|
||||
for (int i = 0; i < [ifdblock count]; i++) {
|
||||
NSString * entry = [ifdblock objectAtIndex:i];
|
||||
NSString * data = [ifddatablock objectAtIndex:i];
|
||||
|
||||
// check if the data fits into 4 bytes
|
||||
if( [data length] <= 8) {
|
||||
// concatenate the entry and the (4byte) data entry into the final IFD entry and append to exif ifd string
|
||||
[exifstr appendFormat : @"%@%@", entry, data];
|
||||
} else {
|
||||
[exifstr appendFormat : @"%@%08x", entry, addr];
|
||||
[dbstr appendFormat: @"%@", data];
|
||||
addr+= [data length] / 2;
|
||||
/*
|
||||
NSLog(@"=====data-length[%i]=======",[data length]);
|
||||
NSLog(@"addr-offset[%i]",addr);
|
||||
NSLog(@"entry[%@]",entry);
|
||||
NSLog(@"data[%@]",data);
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
// calculate IFD0 terminal offset tags, currently ExifSubIFD
|
||||
unsigned int entrycount = (unsigned int)[ifdblock count];
|
||||
if (ifd0flag) {
|
||||
// 18 accounts for 8769's width + offset to next ifd, 8 accounts for start of header
|
||||
NSNumber * offset = [NSNumber numberWithUnsignedInteger:[exifstr length] / 2 + [dbstr length] / 2 + 18+8];
|
||||
|
||||
[self appendExifOffsetTagTo: exifstr
|
||||
withOffset : offset];
|
||||
entrycount++;
|
||||
}
|
||||
*dataoffset = addr;
|
||||
return [[NSString alloc] initWithFormat: @"%04x%@%@%@",
|
||||
entrycount,
|
||||
exifstr,
|
||||
@"00000000", // offset to next IFD, 0 since there is none
|
||||
dbstr]; // lastly, the datablock
|
||||
}
|
||||
|
||||
// Creates an exif formatted exif information file directory entry
|
||||
- (NSString*) createIFDElement: (NSString*) elementName withFormat: (NSArray*) formtemplate withElementData: (NSString*) data {
|
||||
//NSArray * fielddata = [formatdict objectForKey: elementName];// format data of desired field
|
||||
if (formtemplate) {
|
||||
// format string @"%@%@%@%@", tag number, data format, components, value
|
||||
NSNumber * dataformat = [formtemplate objectAtIndex:1];
|
||||
NSNumber * components = [formtemplate objectAtIndex:2];
|
||||
if([components intValue] == 0) {
|
||||
components = [NSNumber numberWithUnsignedInteger:[data length] * DataTypeToWidth[[dataformat intValue]-1]];
|
||||
}
|
||||
|
||||
return [[NSString alloc] initWithFormat: @"%@%@%08x",
|
||||
[formtemplate objectAtIndex:0], // the field code
|
||||
[self formatNumberWithLeadingZeroes: dataformat withPlaces: @4], // the data type code
|
||||
[components intValue]]; // number of components
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* appends exif IFD0 tag 8769 "ExifOffset" to the string provided
|
||||
* (NSMutableString*) str - string you wish to append the 8769 tag to: APP1 or IFD0 hex data string
|
||||
* // TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1), @"ExifOffset",
|
||||
*/
|
||||
- (void) appendExifOffsetTagTo: (NSMutableString*) str withOffset : (NSNumber*) offset {
|
||||
NSArray * format = TAGINF(@"8769", [NSNumber numberWithInt:EDT_ULONG], @1);
|
||||
|
||||
NSString * entry = [self createIFDElement: @"ExifOffset"
|
||||
withFormat: format
|
||||
withElementData: [offset stringValue]];
|
||||
|
||||
NSString * data = [self createIFDElementDataWithFormat: format
|
||||
withData: [offset stringValue]];
|
||||
[str appendFormat:@"%@%@", entry, data];
|
||||
}
|
||||
|
||||
// formats the Information File Directory Data to exif format
|
||||
- (NSString*) createIFDElementDataWithFormat: (NSArray*) dataformat withData: (NSString*) data {
|
||||
NSMutableString * datastr = nil;
|
||||
NSNumber * tmp = nil;
|
||||
NSNumber * formatcode = [dataformat objectAtIndex:1];
|
||||
NSUInteger formatItemsCount = [dataformat count];
|
||||
NSNumber * num = @0;
|
||||
NSNumber * denom = @0;
|
||||
|
||||
switch ([formatcode intValue]) {
|
||||
case EDT_UBYTE:
|
||||
break;
|
||||
case EDT_ASCII_STRING:
|
||||
datastr = [[NSMutableString alloc] init];
|
||||
for (int i = 0; i < [data length]; i++) {
|
||||
[datastr appendFormat:@"%02x",[data characterAtIndex:i]];
|
||||
}
|
||||
if (formatItemsCount > 3) {
|
||||
// We have additional data to append.
|
||||
// currently used by Date format to append final 0x00 but can be used by other data types as well in the future
|
||||
[datastr appendString:[dataformat objectAtIndex:3]];
|
||||
}
|
||||
if ([datastr length] < 8) {
|
||||
NSString * format = [NSString stringWithFormat:@"%%0%dd", (int)(8 - [datastr length])];
|
||||
[datastr appendFormat:format,0];
|
||||
}
|
||||
return datastr;
|
||||
case EDT_USHORT:
|
||||
return [[NSString alloc] initWithFormat : @"%@%@",
|
||||
[self formattedHexStringFromDecimalNumber: [NSNumber numberWithInt: [data intValue]] withPlaces: @4],
|
||||
@"0000"];
|
||||
case EDT_ULONG:
|
||||
tmp = [NSNumber numberWithUnsignedLong:[data intValue]];
|
||||
return [NSString stringWithFormat : @"%@",
|
||||
[self formattedHexStringFromDecimalNumber: tmp withPlaces: @8]];
|
||||
case EDT_URATIONAL:
|
||||
return [self decimalToUnsignedRational: [NSNumber numberWithDouble:[data doubleValue]]
|
||||
withResultNumerator: &num
|
||||
withResultDenominator: &denom];
|
||||
case EDT_SBYTE:
|
||||
|
||||
break;
|
||||
case EDT_UNDEFINED:
|
||||
break; // 8 bits
|
||||
case EDT_SSHORT:
|
||||
break;
|
||||
case EDT_SLONG:
|
||||
break; // 32bit signed integer (2's complement)
|
||||
case EDT_SRATIONAL:
|
||||
break; // 2 SLONGS, first long is numerator, second is denominator
|
||||
case EDT_SINGLEFLOAT:
|
||||
break;
|
||||
case EDT_DOUBLEFLOAT:
|
||||
break;
|
||||
}
|
||||
return datastr;
|
||||
}
|
||||
|
||||
//======================================================================================================================
|
||||
// Utility Methods
|
||||
//======================================================================================================================
|
||||
|
||||
// creates a formatted little endian hex string from a number and width specifier
|
||||
- (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb withPlaces: (NSNumber*) width {
|
||||
NSMutableString * str = [[NSMutableString alloc] initWithCapacity:[width intValue]];
|
||||
NSString * formatstr = [[NSString alloc] initWithFormat: @"%%%@%dx", @"0", [width intValue]];
|
||||
[str appendFormat:formatstr, [numb intValue]];
|
||||
return str;
|
||||
}
|
||||
|
||||
// format number as string with leading 0's
|
||||
- (NSString*) formatNumberWithLeadingZeroes: (NSNumber *) numb withPlaces: (NSNumber *) places {
|
||||
NSNumberFormatter * formatter = [[NSNumberFormatter alloc] init];
|
||||
NSString *formatstr = [@"" stringByPaddingToLength:[places unsignedIntegerValue] withString:@"0" startingAtIndex:0];
|
||||
[formatter setPositiveFormat:formatstr];
|
||||
return [formatter stringFromNumber:numb];
|
||||
}
|
||||
|
||||
// approximate a decimal with a rational by method of continued fraction
|
||||
// can be collasped into decimalToUnsignedRational after testing
|
||||
- (void) decimalToRational: (NSNumber *) numb
|
||||
withResultNumerator: (NSNumber**) numerator
|
||||
withResultDenominator: (NSNumber**) denominator {
|
||||
NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8];
|
||||
|
||||
[self continuedFraction: [numb doubleValue]
|
||||
withFractionList: fractionlist
|
||||
withHorizon: 8];
|
||||
|
||||
// simplify complex fraction represented by partial fraction list
|
||||
[self expandContinuedFraction: fractionlist
|
||||
withResultNumerator: numerator
|
||||
withResultDenominator: denominator];
|
||||
|
||||
}
|
||||
|
||||
// approximate a decimal with an unsigned rational by method of continued fraction
|
||||
- (NSString*) decimalToUnsignedRational: (NSNumber *) numb
|
||||
withResultNumerator: (NSNumber**) numerator
|
||||
withResultDenominator: (NSNumber**) denominator {
|
||||
NSMutableArray * fractionlist = [[NSMutableArray alloc] initWithCapacity:8];
|
||||
|
||||
// generate partial fraction list
|
||||
[self continuedFraction: [numb doubleValue]
|
||||
withFractionList: fractionlist
|
||||
withHorizon: 8];
|
||||
|
||||
// simplify complex fraction represented by partial fraction list
|
||||
[self expandContinuedFraction: fractionlist
|
||||
withResultNumerator: numerator
|
||||
withResultDenominator: denominator];
|
||||
|
||||
return [self formatFractionList: fractionlist];
|
||||
}
|
||||
|
||||
// recursive implementation of decimal approximation by continued fraction
|
||||
- (void) continuedFraction: (double) val
|
||||
withFractionList: (NSMutableArray*) fractionlist
|
||||
withHorizon: (int) horizon {
|
||||
int whole;
|
||||
double remainder;
|
||||
// 1. split term
|
||||
[self splitDouble: val withIntComponent: &whole withFloatRemainder: &remainder];
|
||||
[fractionlist addObject: [NSNumber numberWithInt:whole]];
|
||||
|
||||
// 2. calculate reciprocal of remainder
|
||||
if (!remainder) return; // early exit, exact fraction found, avoids recip/0
|
||||
double recip = 1 / remainder;
|
||||
|
||||
// 3. exit condition
|
||||
if ([fractionlist count] > horizon) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 4. recurse
|
||||
[self continuedFraction:recip withFractionList: fractionlist withHorizon: horizon];
|
||||
|
||||
}
|
||||
|
||||
// expand continued fraction list, creating a single level rational approximation
|
||||
-(void) expandContinuedFraction: (NSArray*) fractionlist
|
||||
withResultNumerator: (NSNumber**) numerator
|
||||
withResultDenominator: (NSNumber**) denominator {
|
||||
NSUInteger i = 0;
|
||||
int den = 0;
|
||||
int num = 0;
|
||||
if ([fractionlist count] == 1) {
|
||||
*numerator = [NSNumber numberWithInt:[[fractionlist objectAtIndex:0] intValue]];
|
||||
*denominator = @1;
|
||||
return;
|
||||
}
|
||||
|
||||
//begin at the end of the list
|
||||
i = [fractionlist count] - 1;
|
||||
num = 1;
|
||||
den = [[fractionlist objectAtIndex:i] intValue];
|
||||
|
||||
while (i > 0) {
|
||||
int t = [[fractionlist objectAtIndex: i-1] intValue];
|
||||
num = t * den + num;
|
||||
if (i==1) {
|
||||
break;
|
||||
} else {
|
||||
t = num;
|
||||
num = den;
|
||||
den = t;
|
||||
}
|
||||
i--;
|
||||
}
|
||||
// set result parameters values
|
||||
*numerator = [NSNumber numberWithInt: num];
|
||||
*denominator = [NSNumber numberWithInt: den];
|
||||
}
|
||||
|
||||
// formats expanded fraction list to string matching exif specification
|
||||
- (NSString*) formatFractionList: (NSArray *) fractionlist {
|
||||
NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16];
|
||||
|
||||
if ([fractionlist count] == 1){
|
||||
[str appendFormat: @"%08x00000001", [[fractionlist objectAtIndex:0] intValue]];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// format rational as
|
||||
- (NSString*) formatRationalWithNumerator: (NSNumber*) numerator withDenominator: (NSNumber*) denominator asSigned: (Boolean) signedFlag {
|
||||
NSMutableString * str = [[NSMutableString alloc] initWithCapacity:16];
|
||||
if (signedFlag) {
|
||||
long num = [numerator longValue];
|
||||
long den = [denominator longValue];
|
||||
[str appendFormat: @"%08lx%08lx", num >= 0 ? num : ~ABS(num) + 1, num >= 0 ? den : ~ABS(den) + 1];
|
||||
} else {
|
||||
[str appendFormat: @"%08lx%08lx", [numerator unsignedLongValue], [denominator unsignedLongValue]];
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
// split a floating point number into two integer values representing the left and right side of the decimal
|
||||
- (void) splitDouble: (double) val withIntComponent: (int*) rightside withFloatRemainder: (double*) leftside {
|
||||
*rightside = val; // convert numb to int representation, which truncates the decimal portion
|
||||
*leftside = val - *rightside;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
- (NSString*) hexStringFromData : (NSData*) data {
|
||||
//overflow detection
|
||||
const unsigned char *dataBuffer = [data bytes];
|
||||
return [[NSString alloc] initWithFormat: @"%02x%02x",
|
||||
(unsigned char)dataBuffer[0],
|
||||
(unsigned char)dataBuffer[1]];
|
||||
}
|
||||
|
||||
// convert a hex string to a number
|
||||
- (NSNumber*) numericFromHexString : (NSString *) hexstring {
|
||||
NSScanner * scan = NULL;
|
||||
unsigned int numbuf= 0;
|
||||
|
||||
scan = [NSScanner scannerWithString:hexstring];
|
||||
[scan scanHexInt:&numbuf];
|
||||
return [NSNumber numberWithInt:numbuf];
|
||||
}
|
||||
|
||||
@end
|
||||
29
src/ios/UIImage+CropScaleOrientation.h
Normal file
29
src/ios/UIImage+CropScaleOrientation.h
Normal 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
|
||||
175
src/ios/UIImage+CropScaleOrientation.m
Normal file
175
src/ios/UIImage+CropScaleOrientation.m
Normal 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
|
||||
80
src/osx/CDVCamera.h
Normal file
80
src/osx/CDVCamera.h
Normal file
@@ -0,0 +1,80 @@
|
||||
/*
|
||||
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
|
||||
};
|
||||
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
258
src/osx/CDVCamera.m
Normal 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.
|
||||
*/
|
||||
- (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
|
||||
861
src/windows/CameraProxy.js
Normal file
861
src/windows/CameraProxy.js
Normal file
@@ -0,0 +1,861 @@
|
||||
/*
|
||||
*
|
||||
* 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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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) {
|
||||
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);
|
||||
1
tests/ios/.gitignore
vendored
Normal file
1
tests/ios/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
node_modules
|
||||
7
tests/ios/CDVCameraTest.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
tests/ios/CDVCameraTest.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "container:CDVCameraTest/CDVCameraTest.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
511
tests/ios/CDVCameraTest/CDVCameraLibTests/CameraTest.m
Normal file
511
tests/ios/CDVCameraTest/CDVCameraLibTests/CameraTest.m
Normal 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
|
||||
44
tests/ios/CDVCameraTest/CDVCameraLibTests/Info.plist
Normal file
44
tests/ios/CDVCameraTest/CDVCameraLibTests/Info.plist
Normal 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>
|
||||
561
tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj/project.pbxproj
Normal file
561
tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj/project.pbxproj
Normal 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 */;
|
||||
}
|
||||
7
tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
7
tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata
generated
Normal file
@@ -0,0 +1,7 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<Workspace
|
||||
version = "1.0">
|
||||
<FileRef
|
||||
location = "self:CDVCameraTest.xcodeproj">
|
||||
</FileRef>
|
||||
</Workspace>
|
||||
@@ -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>
|
||||
@@ -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>
|
||||
@@ -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
40
tests/ios/README.md
Normal 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
13
tests/ios/package.json
Normal 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
14
tests/package.json
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "cordova-plugin-camera-tests",
|
||||
"version": "5.0.1",
|
||||
"description": "",
|
||||
"cordova": {
|
||||
"id": "cordova-plugin-camera-tests",
|
||||
"platforms": []
|
||||
},
|
||||
"keywords": [
|
||||
"ecosystem:cordova"
|
||||
],
|
||||
"author": "",
|
||||
"license": "Apache-2.0"
|
||||
}
|
||||
31
tests/plugin.xml
Normal file
31
tests/plugin.xml
Normal file
@@ -0,0 +1,31 @@
|
||||
<?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="5.0.1">
|
||||
<name>Cordova Camera Plugin Tests</name>
|
||||
<license>Apache 2.0</license>
|
||||
|
||||
<js-module src="tests.js" name="tests">
|
||||
</js-module>
|
||||
</plugin>
|
||||
486
tests/tests.js
Normal file
486
tests/tests.js
Normal file
@@ -0,0 +1,486 @@
|
||||
/*
|
||||
*
|
||||
* 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, 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(navigator.camera.DestinationType.DATA_URL).toBe(0);
|
||||
expect(navigator.camera.DestinationType.FILE_URI).toBe(1);
|
||||
});
|
||||
|
||||
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) {
|
||||
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 logCallback (apiName, success) {
|
||||
return function () {
|
||||
log('Call to ' + apiName + (success ? ' success: ' : ' failed: ') + JSON.stringify([].slice.call(arguments)));
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Select image from library
|
||||
* 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
|
||||
* 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
|
||||
* 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
|
||||
* 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('Draw Using Canvas', function () {
|
||||
displayImageUsingCanvas();
|
||||
}, 'draw_canvas');
|
||||
|
||||
createActionButton('Remove Image', function () {
|
||||
removeImage();
|
||||
}, 'remove');
|
||||
};
|
||||
177
types/index.d.ts
vendored
Normal file
177
types/index.d.ts
vendored
Normal file
@@ -0,0 +1,177 @@
|
||||
// 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
|
||||
*/
|
||||
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;
|
||||
}
|
||||
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;
|
||||
}
|
||||
};
|
||||
185
www/Camera.js
Normal file
185
www/Camera.js
Normal file
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
var argscheck = require('cordova/argscheck');
|
||||
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.
|
||||
for (var key in Camera) {
|
||||
cameraExport[key] = Camera[key];
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function that provides an error message.
|
||||
* @callback module:camera.onError
|
||||
* @param {string} message - The message is provided by the device's native code.
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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 destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI);
|
||||
var sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA);
|
||||
var targetWidth = getValue(options.targetWidth, -1);
|
||||
var targetHeight = getValue(options.targetHeight, -1);
|
||||
var encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG);
|
||||
var mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE);
|
||||
var allowEdit = !!options.allowEdit;
|
||||
var correctOrientation = !!options.correctOrientation;
|
||||
var saveToPhotoAlbum = !!options.saveToPhotoAlbum;
|
||||
var popoverOptions = getValue(options.popoverOptions, null);
|
||||
var cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK);
|
||||
|
||||
var args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType,
|
||||
mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection];
|
||||
|
||||
exec(successCallback, errorCallback, 'Camera', 'takePicture', args);
|
||||
// XXX: commented out
|
||||
// return new CameraPopoverHandle();
|
||||
};
|
||||
|
||||
/**
|
||||
* 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;
|
||||
92
www/CameraConstants.js
Normal file
92
www/CameraConstants.js
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @module Camera
|
||||
*/
|
||||
module.exports = {
|
||||
/**
|
||||
* @description
|
||||
* Defines the output format of `Camera.getPicture` call.
|
||||
*
|
||||
* @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 if possible */
|
||||
DATA_URL: 0,
|
||||
/** Return file uri (content://media/external/images/media/2 for Android) */
|
||||
FILE_URI: 1
|
||||
},
|
||||
/**
|
||||
* @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.
|
||||
*
|
||||
* @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
|
||||
}
|
||||
};
|
||||
32
www/CameraPopoverHandle.js
Normal file
32
www/CameraPopoverHandle.js
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @ignore in favour of iOS' one
|
||||
* A handle to an image picker popover.
|
||||
*/
|
||||
var CameraPopoverHandle = function () {
|
||||
this.setPosition = function (popoverOptions) {
|
||||
console.log('CameraPopoverHandle.setPosition is only supported on iOS.');
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = CameraPopoverHandle;
|
||||
56
www/CameraPopoverOptions.js
Normal file
56
www/CameraPopoverOptions.js
Normal file
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
var Camera = require('./Camera');
|
||||
|
||||
/**
|
||||
* @namespace navigator
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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;
|
||||
this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY;
|
||||
this.popoverWidth = popoverWidth || 0;
|
||||
this.popoverHeight = popoverHeight || 0;
|
||||
};
|
||||
|
||||
module.exports = CameraPopoverOptions;
|
||||
66
www/ios/CameraPopoverHandle.js
Normal file
66
www/ios/CameraPopoverHandle.js
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
*
|
||||
* Licensed to the Apache Software Foundation (ASF) under one
|
||||
* or more contributor license agreements. See the NOTICE file
|
||||
* distributed with this work for additional information
|
||||
* regarding copyright ownership. The ASF licenses this file
|
||||
* to you under the Apache License, Version 2.0 (the
|
||||
* "License"); you may not use this file except in compliance
|
||||
* with the License. You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing,
|
||||
* software distributed under the License is distributed on an
|
||||
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
||||
* KIND, either express or implied. See the License for the
|
||||
* specific language governing permissions and limitations
|
||||
* under the License.
|
||||
*
|
||||
*/
|
||||
|
||||
var exec = require('cordova/exec');
|
||||
|
||||
/**
|
||||
* @namespace navigator
|
||||
*/
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = CameraPopoverHandle;
|
||||
Reference in New Issue
Block a user