Compare commits

..

25 Commits

Author SHA1 Message Date
Erisu
de462d9215 ci: use improved paramedic 2023-01-19 16:06:31 +09:00
エリス
827bb611ee ci: sync workflow with paramedic (#804) 2022-10-01 13:28:27 +09:00
jcesarmobile
d0545c879f fix(browser): use navigator.mediaDevices.getUserMedia (#810) 2022-09-30 00:59:27 +02:00
jcesarmobile
d0d46c151c docs(README): Document ANDROIDX_CORE_VERSION variable (#808) 2022-09-25 05:03:51 +02:00
エリス
a18fda7ddf dep(npm): bump package-lock v2 w/ rebuild (#800) 2022-08-10 16:49:43 +09:00
エリス
3e548770b7 ci(android): update java requirement for cordova-android@11 (#798) 2022-07-17 13:30:47 +09:00
Scott Murphy
4608f8ef80 fix(ios): preserving EXIF data (#712) 2022-03-22 16:23:56 +09:00
Marcus Abrahamsson
53223c3df2 fix(android): update queries in plugin.xml (#780)
Solves the issue with duplicate queries elements in AppManifest.xml

https://github.com/apache/cordova-plugin-camera/issues/779
2022-03-18 09:08:13 +09:00
エリス
bf12b39d18 ci(ios): update workflow w/ iOS 15 (#770) 2021-10-18 21:13:02 +09:00
エリス
ed216ce714 ci: remove old ci workflow (#766) 2021-09-25 16:02:04 +09:00
エリス
879712028a ci: add action-badge (#765) 2021-09-25 01:04:05 +09:00
エリス
204234b1b9 ci: remove travis & appveyor (#764) 2021-09-25 00:07:07 +09:00
エリス
0fba37cac3 ci: add gh-actions workflows (#762) 2021-09-16 22:17:11 +09:00
Erisu
5b8263732a Increment package version to 6.0.1-dev 2021-08-23 14:25:23 +09:00
Erisu
869f02da1a Updated version and RELEASENOTES.md for release 6.0.0 (camera-v6.0.0) 2021-08-19 17:14:44 +09:00
Dave Alden
e9db20e381 fix(android): return exception message (where it exists) (#687)
Co-authored-by: エリス <erisu@users.noreply.github.com>
Co-authored-by: jcesarmobile <jcesarmobile@gmail.com>
2021-08-11 16:56:42 +09:00
Francis
c7971d9f63 fix(android): file path correction if Uri authority is FileProvider (#585)
Co-authored-by: Tim Brust <ratchet.player@gmx.de>
Co-authored-by: Francis Monier <contactpro@francismonier.com>
Co-authored-by: Norman Breau <norman@normanbreau.com>
2021-08-11 16:34:20 +09:00
Niklas Merz
3112e5fb15 chore: add release notify action (#654)
Co-authored-by: Erisu <ellis.bryan@gmail.com>
2021-08-11 16:04:14 +09:00
Jesse MacFadyen
c56a255fe8 ci(gh-action): added workflow to run tests (#745)
Co-authored-by: Erisu <ellis.bryan@gmail.com>
2021-08-11 16:03:34 +09:00
エリス
0227cdcf14 feat(android)!: support AndroidX (#751)
* feat: migrate FileProvider to androidx
* feat: add androidx.core:core with variable override ANDROIDX_CORE_VERSION
2021-08-09 23:09:29 +09:00
Pieter Van Poyer
75bf807261 Bugfix issue 711 heic format (#731)
* Android - issue/711 - support .heic format
2021-08-09 15:36:58 +02:00
エリス
abfbbd35d5 fix(android): supports sdk-30 package visibility (#684) 2021-08-09 20:57:12 +09:00
エリス
59cf76d1da feat: bump cordova-android requirements for 10.x (#750) 2021-08-09 20:56:15 +09:00
エリス
4ee90a84f3 feat: bump plugin version for next major (#749)
Co-authored-by: Niklas Merz <nmerz@gedys-intraware.de>
2021-08-09 20:52:50 +09:00
Niklas Merz
5587bec320 Bump 5.0.4-dev 2021-08-09 10:53:00 +02:00
20 changed files with 3494 additions and 690 deletions

View File

@@ -1,33 +0,0 @@
# 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"
- nodejs_version: "14"
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

137
.github/workflows/android.yml vendored Normal file
View File

@@ -0,0 +1,137 @@
# 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.
name: Android Testsuite
on:
push:
paths-ignore:
- '**.md'
- 'LICENSE'
- '.eslint*'
pull_request:
paths-ignore:
- '**.md'
- 'LICENSE'
- '.eslint*'
jobs:
test:
name: Android ${{ matrix.versions.android }} Test
runs-on: macos-latest
continue-on-error: true
# hoist configurations to top that are expected to be updated
env:
# Storing a copy of the repo
repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
node-version: 16
# These are the default Java configurations used by most tests.
# To customize these options, add "java-distro" or "java-version" to the strategy matrix with its overriding value.
default_java-distro: temurin
default_java-version: 11
# These are the default Android System Image configurations used by most tests.
# To customize these options, add "system-image-arch" or "system-image-target" to the strategy matrix with its overriding value.
default_system-image-arch: x86_64
default_system-image-target: google_apis # Most system images have a google_api option. Set this as default.
# configurations for each testing strategy (test matrix)
strategy:
matrix:
versions:
# Test the lowest minimum supported APIs
- android: 5.1
android-api: 22
# Test the last 3-4 supported APIs
- android: 10
android-api: 29
- android: 11
android-api: 30
- android: 12
android-api: 31
- android: 12L
android-api: 32
timeout-minutes: 60
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: ${{ env.node-version }}
- uses: actions/setup-java@v3
env:
java-version: ${{ matrix.versions.java-version == '' && env.default_java-version || matrix.versions.java-version }}
java-distro: ${{ matrix.versions.java-distro == '' && env.default_java-distro || matrix.versions.java-distro }}
with:
distribution: ${{ env.java-distro }}
java-version: ${{ env.java-version }}
- name: Run Environment Information
run: |
node --version
npm --version
java -version
- name: Run npm install
run: |
export PATH="/usr/local/lib/android/sdk/platform-tools":$PATH
export JAVA_HOME=$JAVA_HOME_11_X64
npm i -g cordova@latest
npm ci
- name: Run paramedic install
if: ${{ endswith(env.repo, '/cordova-paramedic') != true }}
run: npm i -g github:erisu/cordova-paramedic\#fix/plugin-install-order
- uses: reactivecircus/android-emulator-runner@5de26e4bd23bf523e8a4b7f077df8bfb8e52b50e
env:
system-image-arch: ${{ matrix.versions.system-image-arch == '' && env.default_system-image-arch || matrix.versions.system-image-arch }}
system-image-target: ${{ matrix.versions.system-image-target == '' && env.default_system-image-target || matrix.versions.system-image-target }}
with:
api-level: ${{ matrix.versions.android-api }}
target: ${{ env.system-image-target }}
arch: ${{ env.system-image-arch }}
force-avd-creation: false
disable-animations: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim
script: echo "Pregenerate the AVD before running Paramedic"
- name: Run paramedic tests
uses: reactivecircus/android-emulator-runner@5de26e4bd23bf523e8a4b7f077df8bfb8e52b50e
env:
system-image-arch: ${{ matrix.versions.system-image-arch == '' && env.default_system-image-arch || matrix.versions.system-image-arch }}
system-image-target: ${{ matrix.versions.system-image-target == '' && env.default_system-image-target || matrix.versions.system-image-target }}
test_config: 'android-${{ matrix.versions.android }}.config.json'
# Generally, this should automatically work for cordova-paramedic & plugins. If the path is unique, this can be manually changed.
test_plugin_path: ${{ endswith(env.repo, '/cordova-paramedic') && './spec/testable-plugin/' || './' }}
paramedic: ${{ endswith(env.repo, '/cordova-paramedic') && 'node main.js' || 'cordova-paramedic' }}
with:
api-level: ${{ matrix.versions.android-api }}
target: ${{ env.system-image-target }}
arch: ${{ env.system-image-arch }}
force-avd-creation: false
disable-animations: false
emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim
script: ${{ env.paramedic }} --config ./pr/local/${{ env.test_config }} --plugin ${{ env.test_plugin_path }}

73
.github/workflows/chrome.yml vendored Normal file
View File

@@ -0,0 +1,73 @@
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
name: Chrome Testsuite
on:
push:
paths-ignore:
- '**.md'
- 'LICENSE'
- '.eslint*'
pull_request:
paths-ignore:
- '**.md'
- 'LICENSE'
- '.eslint*'
jobs:
test:
name: Chrome Latest Test
runs-on: ubuntu-latest
# hoist configurations to top that are expected to be updated
env:
# Storing a copy of the repo
repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
node-version: 16
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: ${{ env.node-version }}
- name: Run install xvfb
run: sudo apt-get install xvfb
- name: Run Environment Information
run: |
node --version
npm --version
- name: Run npm install
run: |
npm i -g cordova@latest
npm ci
- name: Run paramedic install
if: ${{ endswith(env.repo, '/cordova-paramedic') != true }}
run: npm i -g github:erisu/cordova-paramedic\#fix/plugin-install-order
- name: Run paramedic tests
env:
test_config: 'browser.config.json'
# Generally, this should automatically work for cordova-paramedic & plugins. If the path is unique, this can be manually changed.
test_plugin_path: ${{ endswith(env.repo, '/cordova-paramedic') && './spec/testable-plugin/' || './' }}
paramedic: ${{ endswith(env.repo, '/cordova-paramedic') && 'node main.js' || 'cordova-paramedic' }}
run: xvfb-run --auto-servernum ${{ env.paramedic }} --config ./pr/local/${{ env.test_config }} --plugin ${{ env.test_plugin_path }}

97
.github/workflows/ios.yml vendored Normal file
View File

@@ -0,0 +1,97 @@
# 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.
name: iOS Testsuite
on:
push:
paths-ignore:
- '**.md'
- 'LICENSE'
- '.eslint*'
pull_request:
paths-ignore:
- '**.md'
- 'LICENSE'
- '.eslint*'
jobs:
test:
name: iOS ${{ matrix.versions.ios-version }} Test
runs-on: ${{ matrix.versions.os-version }}
continue-on-error: true
# hoist configurations to top that are expected to be updated
env:
# Storing a copy of the repo
repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }}
node-version: 16
# > Starting April 26, 2021, all iOS and iPadOS apps submitted to the App Store must be built with Xcode 12 and the iOS 14 SDK.
# Because of Apple's requirement, listed above, We will only be using the latest Xcode release for testing.
# To customize these options, add "xcode-version" to the strategy matrix with its overriding value.
default_xcode-version: latest-stable
strategy:
matrix:
versions:
- os-version: macos-11
ios-version: 13.x
xcode-version: 11.x
- os-version: macos-11
ios-version: 14.x
xcode-version: 12.x
- os-version: macos-11
ios-version: 15.x
xcode-version: 13.x
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: ${{ env.node-version }}
- uses: maxim-lobanov/setup-xcode@881be567d30efed8fb3f12b5099d68c3fb72aa3d
env:
xcode-version: ${{ matrix.versions.xcode-version == '' && env.default_xcode-version || matrix.versions.xcode-version }}
with:
xcode-version: ${{ env.xcode-version }}
- name: Run Environment Information
run: |
node --version
npm --version
xcodebuild -version
- name: Run npm install
run: |
npm i -g cordova@latest ios-deploy@latest
npm ci
- name: Run paramedic install
if: ${{ endswith(env.repo, '/cordova-paramedic') != true }}
run: npm i -g github:erisu/cordova-paramedic\#fix/plugin-install-order
- name: Run paramedic tests
env:
test_config: 'ios-${{ matrix.versions.ios-version }}.config.json'
# Generally, this should automatically work for cordova-paramedic & plugins. If the path is unique, this can be manually changed.
test_plugin_path: ${{ endswith(env.repo, '/cordova-paramedic') && './spec/testable-plugin/' || './' }}
paramedic: ${{ endswith(env.repo, '/cordova-paramedic') && 'node main.js' || 'cordova-paramedic' }}
run: ${{ env.paramedic }} --config ./pr/local/${{ env.test_config }} --plugin ${{ env.test_plugin_path }}

56
.github/workflows/lint.yml vendored Normal file
View 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.
name: Lint Test
on:
push:
paths:
- '**.js'
- '.eslint*'
- '.github/workflow/lint.yml'
pull_request:
paths:
- '**.js'
- '.eslint*'
- '.github/workflow/lint.yml'
jobs:
test:
name: Lint Test
runs-on: ubuntu-latest
env:
node-version: 16
steps:
- uses: actions/checkout@v2
- uses: actions/setup-node@v2
with:
node-version: ${{ env.node-version }}
- name: Run Environment Information
run: |
node --version
npm --version
- name: Run npm install
run: |
npm ci
- name: Run lint test
run: |
npm run lint

13
.github/workflows/release-notify.yml vendored Normal file
View File

@@ -0,0 +1,13 @@
name: Close issue asking for release
on:
issues:
types: [opened]
jobs:
action-test:
runs-on: ubuntu-latest
steps:
- uses: niklasmerz/release-notify@master
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}

View File

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

View File

@@ -1,118 +0,0 @@
# 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: 14
# 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

View File

@@ -21,12 +21,10 @@ description: Take pictures with the device camera.
# under the License.
-->
|AppVeyor|Travis CI|
|:-:|:-:|
|[![Build status](https://ci.appveyor.com/api/projects/status/github/apache/cordova-plugin-camera?branch=master)](https://ci.appveyor.com/project/ApacheSoftwareFoundation/cordova-plugin-camera)|[![Build Status](https://travis-ci.org/apache/cordova-plugin-camera.svg?branch=master)](https://travis-ci.org/apache/cordova-plugin-camera)|
# cordova-plugin-camera
[![Android Testsuite](https://github.com/apache/cordova-plugin-camera/actions/workflows/android.yml/badge.svg)](https://github.com/apache/cordova-plugin-camera/actions/workflows/android.yml) [![Chrome Testsuite](https://github.com/apache/cordova-plugin-camera/actions/workflows/chrome.yml/badge.svg)](https://github.com/apache/cordova-plugin-camera/actions/workflows/chrome.yml) [![iOS Testsuite](https://github.com/apache/cordova-plugin-camera/actions/workflows/ios.yml/badge.svg)](https://github.com/apache/cordova-plugin-camera/actions/workflows/ios.yml) [![Lint Test](https://github.com/apache/cordova-plugin-camera/actions/workflows/lint.yml/badge.svg)](https://github.com/apache/cordova-plugin-camera/actions/workflows/lint.yml)
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.
@@ -40,16 +38,20 @@ Although the object is attached to the global scoped `navigator`, it is not avai
## 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
## Plugin variables
The plugin uses the `ANDROIDX_CORE_VERSION` variable to configure `androidx.core:core` dependency. This allows to avoid conflicts with other plugins that have the dependency hardcoded.
If no value is passed, it will use `1.6.+` as the default value.
The variable is configured on install time
cordova plugin add cordova-plugin-camera --variable ANDROIDX_CORE_VERSION=1.8.0
## How to Contribute

View File

@@ -20,6 +20,26 @@
-->
# Release Notes
### 6.0.0 (Aug 19, 2021)
**Feature:**
* [GH-751](https://github.com/apache/cordova-plugin-camera/pull/751) feat(android)!: support **AndroidX**
* [GH-750](https://github.com/apache/cordova-plugin-camera/pull/750) feat(android): bump `cordova-android` requirements for `10.x`
* [GH-731](https://github.com/apache/cordova-plugin-camera/pull/731) feat(android): encode `heic` format to `EncodingType` for webview display [#711](https://github.com/apache/cordova-plugin-camera/issues/711)
* [GH-684](https://github.com/apache/cordova-plugin-camera/pull/684) feat(android): `sdk-30` package visibility support
**Fix:**
* [GH-687](https://github.com/apache/cordova-plugin-camera/pull/687) fix(android): return exception message (where it exists)
* [GH-585](https://github.com/apache/cordova-plugin-camera/pull/585) fix(android): file path correction if `Uri` authority is `FileProvider`
**Chore & CI:**
* [GH-749](https://github.com/apache/cordova-plugin-camera/pull/749) chore: bump plugin version for next major
* [GH-654](https://github.com/apache/cordova-plugin-camera/pull/654) chore: add release notify action
* [GH-745](https://github.com/apache/cordova-plugin-camera/pull/745) ci(gh-action): added workflow to run tests
### 5.0.3 (Aug 04, 2021)
* [GH-754](https://github.com/apache/cordova-plugin-camera/pull/754) chore: rebuilt `package-lock.json`

3203
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-camera",
"version": "5.0.3",
"version": "6.0.1-dev",
"description": "Cordova Camera Plugin",
"types": "./types/index.d.ts",
"cordova": {
@@ -45,12 +45,17 @@
"cordova-ios": ">=5.1.0",
"cordova": ">=9.0.0"
},
"5.0.3": {
"5.0.4-dev": {
"cordova-android": "<10.0.0",
"cordova-ios": ">=5.1.0",
"cordova": ">=9.0.0"
},
"6.0.0": {
"cordova-android": ">=10.0.0",
"cordova-ios": ">=5.1.0",
"cordova": ">=9.0.0"
},
"7.0.0": {
"cordova": ">100"
}
}

View File

@@ -21,7 +21,7 @@
<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.3">
version="6.0.1-dev">
<name>Camera</name>
<description>Cordova Camera Plugin</description>
<license>Apache 2.0</license>
@@ -31,7 +31,7 @@
<engines>
<engine name="cordova" version=">=9.0.0"/>
<engine name="cordova-android" version="<10.0.0" />
<engine name="cordova-android" version=">=10.0.0" />
<engine name="cordova-ios" version=">=5.1.0" />
</engines>
@@ -69,6 +69,22 @@
</provider>
</config-file>
<config-file target="AndroidManifest.xml" parent="queries">
<intent>
<action android:name="android.media.action.IMAGE_CAPTURE" />
</intent>
<intent>
<action android:name="android.intent.action.GET_CONTENT" />
</intent>
<intent>
<action android:name="android.intent.action.PICK" />
</intent>
<intent>
<action android:name="com.android.camera.action.CROP" />
<data android:scheme="content" android:mimeType="image/*"/>
</intent>
</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" />
@@ -76,13 +92,12 @@
<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" />
<preference name="ANDROIDX_CORE_VERSION" default="1.6.+"/>
<framework src="androidx.core:core:$ANDROIDX_CORE_VERSION" />
<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 -->

View File

@@ -39,7 +39,7 @@ import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.v4.content.FileProvider;
import androidx.core.content.FileProvider;
import android.util.Base64;
import org.apache.cordova.BuildHelper;
@@ -87,6 +87,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
private static final String PNG_EXTENSION = "." + PNG_TYPE;
private static final String PNG_MIME_TYPE = "image/png";
private static final String JPEG_MIME_TYPE = "image/jpeg";
private static final String HEIC_MIME_TYPE = "image/heic";
private static final String GET_PICTURE = "Get Picture";
private static final String GET_VIDEO = "Get Video";
private static final String GET_All = "Get All";
@@ -197,7 +198,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
if(!PermissionHelper.hasPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)) {
PermissionHelper.requestPermission(this, SAVE_TO_ALBUM_SEC, Manifest.permission.READ_EXTERNAL_STORAGE);
} else {
this.getImage(this.srcType, destType, encodingType);
this.getImage(this.srcType, destType);
}
}
}
@@ -273,9 +274,9 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
if (takePicturePermission && saveAlbumPermission) {
takePicture(returnType, encodingType);
} else if (saveAlbumPermission && !takePicturePermission) {
} else if (saveAlbumPermission) {
PermissionHelper.requestPermission(this, TAKE_PIC_SEC, Manifest.permission.CAMERA);
} else if (!saveAlbumPermission && takePicturePermission) {
} else if (takePicturePermission) {
PermissionHelper.requestPermissions(this, TAKE_PIC_SEC,
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE});
} else {
@@ -356,11 +357,10 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
*
* @param srcType The album to get image from.
* @param returnType Set the type of image to return.
* @param encodingType
*/
// TODO: Images selected from SDCARD don't display correctly, but from CAMERA ALBUM do!
// TODO: Images from kitkat filechooser not going into crop function
public void getImage(int srcType, int returnType, int encodingType) {
public void getImage(int srcType, int returnType) {
Intent intent = new Intent();
String title = GET_PICTURE;
croppedUri = null;
@@ -420,7 +420,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// set crop properties
cropIntent.putExtra("crop", "true");
// indicate output X and Y
if (targetWidth > 0) {
cropIntent.putExtra("outputX", targetWidth);
@@ -439,7 +438,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
cropIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
cropIntent.putExtra("output", croppedUri);
// start the activity - we handle returning in onActivityResult
if (this.cordova != null) {
@@ -450,9 +448,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
LOG.e(LOG_TAG, "Crop operation not supported on this device");
try {
processResultFromCamera(destType, cameraIntent);
}
catch (IOException e)
{
} catch (IOException e) {
e.printStackTrace();
LOG.e(LOG_TAG, "Unable to write to file");
}
@@ -475,7 +471,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
this.croppedFilePath :
this.imageFilePath;
if (this.encodingType == JPEG) {
try {
//We don't support PNG, so let's not pretend we do
@@ -610,7 +605,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
ContentResolver resolver = this.cordova.getActivity().getContentResolver();
ContentValues contentValues = new ContentValues();
contentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, galleryPathVO.getGalleryFileName());
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, getMimetypeForFormat(encodingType));
contentValues.put(MediaStore.MediaColumns.MIME_TYPE, getMimetypeForEncodingType());
Uri galleryOutputUri = resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, contentValues);
InputStream fileStream = org.apache.cordova.camera.FileHelper.getInputStreamFromUriString(imageUri.toString(), cordova);
@@ -623,7 +618,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
private GalleryPathVO getPicturesPath() {
String timeStamp = new SimpleDateFormat(TIME_FORMAT).format(new Date());
String imageFileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? JPEG_EXTENSION : PNG_EXTENSION);
String imageFileName = "IMG_" + timeStamp + getExtensionForEncodingType();
File storageDir = Environment.getExternalStoragePublicDirectory(
Environment.DIRECTORY_PICTURES);
storageDir.mkdirs();
@@ -639,28 +634,20 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
/**
* Converts output image format int value to string value of mime type.
* @param outputFormat int Output format of camera API.
* Must be value of either JPEG or PNG constant
* @return String String value of mime type or empty string if mime type is not supported
*/
private String getMimetypeForFormat(int outputFormat) {
if (outputFormat == PNG) return PNG_MIME_TYPE;
if (outputFormat == JPEG) return JPEG_MIME_TYPE;
private String getMimetypeForEncodingType() {
if (encodingType == PNG) return PNG_MIME_TYPE;
if (encodingType == JPEG) return JPEG_MIME_TYPE;
return "";
}
private String outputModifiedBitmap(Bitmap bitmap, Uri uri) throws IOException {
private String outputModifiedBitmap(Bitmap bitmap, Uri uri, String mimeTypeOfOriginalFile) throws IOException {
// Some content: URIs do not map to file paths (e.g. picasa).
String realPath = FileHelper.getRealPath(uri, this.cordova);
String fileName = calculateModifiedBitmapOutputFileName(mimeTypeOfOriginalFile, realPath);
// Get filename from uri
String fileName = realPath != null ?
realPath.substring(realPath.lastIndexOf('/') + 1) :
"modified." + (this.encodingType == JPEG ? JPEG_TYPE : PNG_TYPE);
String timeStamp = new SimpleDateFormat(TIME_FORMAT).format(new Date());
//String fileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? ".jpg" : ".png");
String modifiedPath = getTempDirectoryPath() + "/" + fileName;
OutputStream os = new FileOutputStream(modifiedPath);
@@ -684,6 +671,23 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
return modifiedPath;
}
private String calculateModifiedBitmapOutputFileName(String mimeTypeOfOriginalFile, String realPath) {
if (realPath == null) {
return "modified" + getExtensionForEncodingType();
}
String fileName = realPath.substring(realPath.lastIndexOf('/') + 1);
if (getMimetypeForEncodingType().equals(mimeTypeOfOriginalFile)) {
return fileName;
}
// if the picture is not a jpeg or png, (a .heic for example) when processed to a bitmap
// the file extension is changed to the output format, f.e. an input file my_photo.heic could become my_photo.jpg
return fileName.substring(fileName.lastIndexOf(".") + 1) + getExtensionForEncodingType();
}
private String getExtensionForEncodingType() {
return this.encodingType == JPEG ? JPEG_EXTENSION : PNG_EXTENSION;
}
/**
* Applies all needed transformation to the image received from the gallery.
@@ -707,24 +711,22 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
String uriString = uri.toString();
String finalLocation = fileLocation != null ? fileLocation : uriString;
String mimeType = FileHelper.getMimeType(uriString, this.cordova);
String mimeTypeOfGalleryFile = FileHelper.getMimeType(uriString, this.cordova);
if (finalLocation == null) {
this.failPicture("Error retrieving result.");
} else {
// If you ask for video or the selected file doesn't have JPEG or PNG mime type
// there will be no attempt to resize any returned data
if (this.mediaType == VIDEO || !(JPEG_MIME_TYPE.equalsIgnoreCase(mimeType) || PNG_MIME_TYPE.equalsIgnoreCase(mimeType))) {
// If you ask for video or the selected file cannot be processed
// there will be no attempt to resize any returned data.
if (this.mediaType == VIDEO || !isImageMimeTypeProcessable(mimeTypeOfGalleryFile)) {
this.callbackContext.success(finalLocation);
}
else {
} else {
// This is a special case to just return the path as no scaling,
// rotating, nor compressing needs to be done
if (this.targetHeight == -1 && this.targetWidth == -1 &&
destType == FILE_URI && !this.correctOrientation &&
mimeType != null && mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType)))
getMimetypeForEncodingType().equalsIgnoreCase(mimeTypeOfGalleryFile))
{
this.callbackContext.success(finalLocation);
} else {
@@ -750,17 +752,17 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// Did we modify the image?
if ( (this.targetHeight > 0 && this.targetWidth > 0) ||
(this.correctOrientation && this.orientationCorrected) ||
!mimeType.equalsIgnoreCase(getMimetypeForFormat(encodingType)))
!mimeTypeOfGalleryFile.equalsIgnoreCase(getMimetypeForEncodingType()))
{
try {
String modifiedPath = this.outputModifiedBitmap(bitmap, uri);
String modifiedPath = this.outputModifiedBitmap(bitmap, uri, mimeTypeOfGalleryFile);
// The modified image is cached by the app in order to get around this and not have to delete you
// application cache I'm adding the current system time to the end of the file url.
this.callbackContext.success("file://" + modifiedPath + "?" + System.currentTimeMillis());
} catch (Exception e) {
e.printStackTrace();
this.failPicture("Error retrieving image.");
this.failPicture("Error retrieving image: "+e.getLocalizedMessage());
}
} else {
this.callbackContext.success(finalLocation);
@@ -777,6 +779,18 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
/**
* JPEG, PNG and HEIC mime types (images) can be scaled, decreased in quantity, corrected by orientation.
* But f.e. an image/gif cannot be scaled, but is can be selected through the PHOTOLIBRARY.
*
* @param mimeType The mimeType to check
* @return if the mimeType is a processable image mime type
*/
private boolean isImageMimeTypeProcessable(String mimeType) {
return JPEG_MIME_TYPE.equalsIgnoreCase(mimeType) || PNG_MIME_TYPE.equalsIgnoreCase(mimeType)
|| HEIC_MIME_TYPE.equalsIgnoreCase(mimeType);
}
/**
* Called when the camera view exits.
*
@@ -830,7 +844,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
} catch (IOException e) {
e.printStackTrace();
this.failPicture("Error capturing image.");
this.failPicture("Error capturing image: "+e.getLocalizedMessage());
}
}
@@ -974,7 +988,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
if (fileStream != null) {
// Generate a temporary file
String timeStamp = new SimpleDateFormat(TIME_FORMAT).format(new Date());
String fileName = "IMG_" + timeStamp + (this.encodingType == JPEG ? JPEG_EXTENSION : PNG_EXTENSION);
String fileName = "IMG_" + timeStamp + (getExtensionForEncodingType());
localFile = new File(getTempDirectoryPath() + fileName);
galleryUri = Uri.fromFile(localFile);
writeUncompressedImage(fileStream, galleryUri);
@@ -998,15 +1012,11 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
rotate = 0;
}
}
}
catch (Exception e)
{
} catch (Exception e) {
LOG.e(LOG_TAG,"Exception while getting input stream: "+ e.toString());
return null;
}
try {
// figure out the original width and height of the image
BitmapFactory.Options options = new BitmapFactory.Options();
@@ -1052,7 +1062,6 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
// determine the correct aspect ratio
int[] widthHeight = calculateAspectRatio(rotatedWidth, rotatedHeight);
// Load in the smallest bitmap possible that is closest to the size we want
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(rotatedWidth, rotatedHeight, widthHeight[0], widthHeight[1]);
@@ -1092,8 +1101,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
}
return scaledBitmap;
}
finally {
} finally {
// delete the temporary copy
if (localFile != null) {
localFile.delete();
@@ -1269,7 +1277,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
code = null;
}
} catch (Exception e) {
this.failPicture("Error compressing image.");
this.failPicture("Error compressing image: "+e.getLocalizedMessage());
}
jpeg_data = null;
}
@@ -1305,9 +1313,8 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
this.conn.disconnect();
}
public void onRequestPermissionResult(int requestCode, String[] permissions,
int[] grantResults) throws JSONException {
int[] grantResults) {
for (int r : grantResults) {
if (r == PackageManager.PERMISSION_DENIED) {
this.callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.ERROR, PERMISSION_DENIED_ERROR));
@@ -1319,7 +1326,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
takePicture(this.destType, this.encodingType);
break;
case SAVE_TO_ALBUM_SEC:
this.getImage(this.srcType, this.destType, this.encodingType);
this.getImage(this.srcType, this.destType);
break;
}
}
@@ -1381,7 +1388,7 @@ public class CameraLauncher extends CordovaPlugin implements MediaScannerConnect
}
if (state.containsKey(IMAGE_FILE_PATH_KEY)) {
this.imageFilePath = state.getString(IMAGE_FILE_PATH_KEY);
this.imageFilePath = state.getString(IMAGE_FILE_PATH_KEY);
}
this.callbackContext = callbackContext;

View File

@@ -19,7 +19,6 @@ 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;
@@ -29,8 +28,8 @@ import android.provider.MediaStore;
import android.webkit.MimeTypeMap;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.LOG;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
@@ -44,7 +43,7 @@ public class FileHelper {
* 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 uri the URI of the audio/image/video
* @param cordova the current application context
* @return the full path to the file
*/
@@ -57,7 +56,7 @@ public class FileHelper {
* 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 uriString the URI string from which to obtain the input stream
* @param cordova the current application context
* @return the full path to the file
*/
@@ -132,6 +131,9 @@ public class FileHelper {
if (isGooglePhotosUri(uri))
return uri.getLastPathSegment();
if (isFileProviderUri(context, uri))
return getFileProviderPath(context, uri);
return getDataColumn(context, uri, null, null);
}
// File
@@ -142,22 +144,6 @@ public class FileHelper {
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.
*
@@ -177,6 +163,7 @@ public class FileHelper {
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);
@@ -206,6 +193,7 @@ public class FileHelper {
* @return a path without the "file://" prefix
*/
public static String stripFileProtocol(String uriString) {
if (uriString.startsWith("file://")) {
uriString = uriString.substring(7);
}
@@ -225,7 +213,7 @@ public class FileHelper {
}
return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
}
/**
* Returns the mime type of the data specified by the given URI string.
*
@@ -233,7 +221,7 @@ public class FileHelper {
* @return the mime type of the specified data
*/
public static String getMimeType(String uriString, CordovaInterface cordova) {
String mimeType = null;
String mimeType;
Uri uri = Uri.parse(uriString);
if (uriString.startsWith("content://")) {
@@ -316,4 +304,28 @@ public class FileHelper {
public static boolean isGooglePhotosUri(Uri uri) {
return "com.google.android.apps.photos.content".equals(uri.getAuthority());
}
/**
* @param context The Application context
* @param uri The Uri is checked by functions
* @return Whether the Uri authority is FileProvider
*/
public static boolean isFileProviderUri(final Context context, final Uri uri) {
final String packageName = context.getPackageName();
final String authority = new StringBuilder(packageName).append(".provider").toString();
return authority.equals(uri.getAuthority());
}
/**
* @param context The Application context
* @param uri The Uri is checked by functions
* @return File path or null if file is missing
*/
public static String getFileProviderPath(final Context context, final Uri uri)
{
final File appDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
final File file = new File(appDir, uri.getLastPathSegment());
return file.exists() ? file.toString(): null;
}
}

View File

@@ -18,4 +18,4 @@
*/
package org.apache.cordova.camera;
public class FileProvider extends android.support.v4.content.FileProvider {}
public class FileProvider extends androidx.core.content.FileProvider {}

View File

@@ -111,7 +111,11 @@ function capture (success, errorCallback, opts) {
document.body.appendChild(parent);
};
if (navigator.getUserMedia) {
if (navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({ video: true, audio: false })
.then(successCallback)
.catch(errorCallback);
} else if (navigator.getUserMedia) {
navigator.getUserMedia({ video: true, audio: false }, successCallback, errorCallback);
} else {
alert('Browser does not support camera :(');

View File

@@ -29,6 +29,7 @@
#import <ImageIO/CGImageDestination.h>
#import <MobileCoreServices/UTCoreTypes.h>
#import <objc/message.h>
#import <Photos/Photos.h>
#ifndef __CORDOVA_4_0_0
#import <Cordova/NSData+Base64.h>
@@ -159,7 +160,7 @@ static NSString* toBase64(NSData* data) {
if (pictureOptions.sourceType == UIImagePickerControllerSourceTypeCamera) {
[AVCaptureDevice requestAccessForMediaType:AVMediaTypeVideo completionHandler:^(BOOL granted)
{
if(!granted)
if (!granted)
{
// Denied; show an alert
dispatch_async(dispatch_get_main_queue(), ^{
@@ -174,11 +175,32 @@ static NSString* toBase64(NSData* data) {
[weakSelf.viewController presentViewController:alertController animated:YES completion:nil];
});
} else {
[weakSelf showCameraPicker:command.callbackId withOptions:pictureOptions];
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf showCameraPicker:command.callbackId withOptions:pictureOptions];
});
}
}];
} else {
[weakSelf showCameraPicker:command.callbackId withOptions:pictureOptions];
[weakSelf options:pictureOptions requestPhotoPermissions:^(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 roll has been prohibited; please enable it in the Settings 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]];
[weakSelf sendNoPermissionResult:command.callbackId];
}]];
[weakSelf.viewController presentViewController:alertController animated:YES completion:nil];
});
} else {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf showCameraPicker:command.callbackId withOptions:pictureOptions];
});
}
}];
}
}];
}
@@ -367,24 +389,51 @@ static NSString* toBase64(NSData* data) {
data = UIImageJPEGRepresentation(image, [options.quality floatValue] / 100.0f);
}
if (options.usesGeolocation) {
NSDictionary* controllerMetadata = [info objectForKey:@"UIImagePickerControllerMediaMetadata"];
if (pickerController.sourceType == UIImagePickerControllerSourceTypeCamera) {
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;
}
} else if (pickerController.sourceType == UIImagePickerControllerSourceTypePhotoLibrary) {
PHAsset* asset = [info objectForKey:@"UIImagePickerControllerPHAsset"];
NSDictionary* controllerMetadata = [self getImageMetadataFromAsset:asset];
self.data = data;
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];
NSMutableDictionary* TIFFDictionary = [[controllerMetadata objectForKey:(NSString*)kCGImagePropertyTIFFDictionary
]mutableCopy];
if (TIFFDictionary) {
[self.metadata setObject:TIFFDictionary forKey:(NSString*)kCGImagePropertyTIFFDictionary];
}
NSMutableDictionary* GPSDictionary = [[controllerMetadata objectForKey:(NSString*)kCGImagePropertyGPSDictionary
]mutableCopy];
if (GPSDictionary) {
[self.metadata setObject:GPSDictionary forKey:(NSString*)kCGImagePropertyGPSDictionary
];
}
[[self locationManager] startUpdatingLocation];
}
data = nil;
}
}
break;
default:
@@ -394,6 +443,78 @@ static NSString* toBase64(NSData* data) {
return data;
}
/* --------------------------------------------------------------
-- get the metadata of the image from a PHAsset
-------------------------------------------------------------- */
- (NSDictionary*)getImageMetadataFromAsset:(PHAsset*)asset {
if(asset == nil) {
return nil;
}
// get photo info from this asset
__block NSDictionary *dict = nil;
PHImageRequestOptions *imageRequestOptions = [[PHImageRequestOptions alloc] init];
imageRequestOptions.synchronous = YES;
[[PHImageManager defaultManager]
requestImageDataForAsset:asset
options:imageRequestOptions
resultHandler: ^(NSData *imageData, NSString *dataUTI, UIImageOrientation orientation, NSDictionary *info) {
dict = [self convertImageMetadata:imageData]; // as this imageData is in NSData format so we need a method to convert this NSData into NSDictionary
}];
return dict;
}
-(NSDictionary*)convertImageMetadata:(NSData*)imageData {
CGImageSourceRef imageSource = CGImageSourceCreateWithData((__bridge CFDataRef)(imageData), NULL);
if (imageSource) {
NSDictionary *options = @{(NSString *)kCGImageSourceShouldCache : [NSNumber numberWithBool:NO]};
CFDictionaryRef imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, (__bridge CFDictionaryRef)options);
if (imageProperties) {
NSDictionary *metadata = (__bridge NSDictionary *)imageProperties;
CFRelease(imageProperties);
CFRelease(imageSource);
NSLog(@"Metadata of selected image%@", metadata);// image metadata after converting NSData into NSDictionary
return metadata;
}
CFRelease(imageSource);
}
NSLog(@"Can't read image metadata");
return nil;
}
- (void)options:(CDVPictureOptions*)options requestPhotoPermissions:(void (^)(BOOL auth))completion
{
if((unsigned long)options.sourceType == 1){
completion(YES);
}
else{
PHAuthorizationStatus status = [PHPhotoLibrary authorizationStatus];
switch (status) {
case PHAuthorizationStatusAuthorized:
completion(YES);
break;
case PHAuthorizationStatusNotDetermined: {
[PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus authorizationStatus) {
if (authorizationStatus == PHAuthorizationStatusAuthorized) {
completion(YES);
} else {
completion(NO);
}
}];
break;
}
default:
completion(NO);
break;
}
}
}
- (NSString*)tempFilePath:(NSString*)extension
{
NSString* docsPath = [NSTemporaryDirectory()stringByStandardizingPath];
@@ -454,17 +575,48 @@ static NSString* toBase64(NSData* data) {
image = [self retrieveImage:info options:options];
NSData* data = [self processImage:image info:info options:options];
if (data) {
if (pickerController.sourceType == UIImagePickerControllerSourceTypePhotoLibrary) {
NSMutableData *imageDataWithExif = [NSMutableData data];
if (self.metadata) {
CGImageSourceRef sourceImage = CGImageSourceCreateWithData((__bridge CFDataRef)self.data, NULL);
CFStringRef sourceType = CGImageSourceGetType(sourceImage);
NSString* extension = options.encodingType == EncodingTypePNG? @"png" : @"jpg";
NSString* filePath = [self tempFilePath:extension];
NSError* err = nil;
CGImageDestinationRef destinationImage = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageDataWithExif, sourceType, 1, NULL);
CGImageDestinationAddImageFromSource(destinationImage, sourceImage, 0, (__bridge CFDictionaryRef)self.metadata);
CGImageDestinationFinalize(destinationImage);
// 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]];
CFRelease(sourceImage);
CFRelease(destinationImage);
} else {
imageDataWithExif = [self.data mutableCopy];
}
NSError* err = nil;
NSString* extension = self.pickerController.pictureOptions.encodingType == EncodingTypePNG ? @"png":@"jpg";
NSString* filePath = [self tempFilePath:extension];
// save file
if (![imageDataWithExif 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]];
}
} else if (pickerController.sourceType != UIImagePickerControllerSourceTypeCamera || !options.usesGeolocation) {
// No need to save file if usesGeolocation is true since it will be saved after the location is tracked
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;
@@ -649,19 +801,23 @@ static NSString* toBase64(NSData* data) {
{
CDVPictureOptions* options = self.pickerController.pictureOptions;
CDVPluginResult* result = nil;
NSMutableData *imageDataWithExif = [NSMutableData data];
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);
CGImageDestinationRef destinationImage = CGImageDestinationCreateWithData((__bridge CFMutableDataRef)imageDataWithExif, sourceType, 1, NULL);
CGImageDestinationAddImageFromSource(destinationImage, sourceImage, 0, (__bridge CFDictionaryRef)self.metadata);
CGImageDestinationFinalize(destinationImage);
dataCopy = nil;
CFRelease(sourceImage);
CFRelease(destinationImage);
} else {
imageDataWithExif = [self.data mutableCopy];
}
switch (options.destinationType) {
@@ -695,7 +851,7 @@ static NSString* toBase64(NSData* data) {
self.pickerController = nil;
self.data = nil;
self.metadata = nil;
imageDataWithExif = nil;
if (options.saveToPhotoAlbum) {
UIImageWriteToSavedPhotosAlbum([[UIImage alloc] initWithData:self.data], nil, nil, nil);
}

View File

@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-camera-tests",
"version": "5.0.3",
"version": "6.0.1-dev",
"description": "",
"cordova": {
"id": "cordova-plugin-camera-tests",

View File

@@ -22,7 +22,7 @@
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.3">
version="6.0.1-dev">
<name>Cordova Camera Plugin Tests</name>
<license>Apache 2.0</license>