├── .asf.yaml ├── .eslintrc.yml ├── .gitattributes ├── .github ├── ISSUE_TEMPLATE.md ├── ISSUE_TEMPLATE │ ├── BUG_REPORT.md │ ├── FEATURE_REQUEST.md │ └── SUPPORT_QUESTION.md ├── PULL_REQUEST_TEMPLATE.md └── workflows │ ├── android.yml │ ├── chrome.yml │ ├── ios.yml │ ├── lint.yml │ └── release-notify.yml ├── .gitignore ├── .npmignore ├── .npmrc ├── CONTRIBUTING.md ├── LICENSE ├── NOTICE ├── README.md ├── RELEASENOTES.md ├── package-lock.json ├── package.json ├── plugin.xml ├── src ├── android │ ├── CameraLauncher.java │ ├── ExifHelper.java │ ├── FileHelper.java │ ├── FileProvider.java │ ├── GalleryPathVO.java │ └── xml │ │ └── camera_provider_paths.xml ├── browser │ └── CameraProxy.js └── ios │ ├── CDVCamera.h │ ├── CDVCamera.m │ ├── CDVExif.h │ ├── CDVJpegHeaderWriter.h │ ├── CDVJpegHeaderWriter.m │ ├── UIImage+CropScaleOrientation.h │ └── UIImage+CropScaleOrientation.m ├── tests ├── ios │ ├── .gitignore │ ├── CDVCameraTest.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ ├── CDVCameraTest.xccheckout │ │ │ └── xcschemes │ │ │ └── CordovaLib.xcscheme │ ├── CDVCameraTest │ │ ├── CDVCameraLibTests │ │ │ ├── CameraTest.m │ │ │ └── Info.plist │ │ └── CDVCameraTest.xcodeproj │ │ │ ├── project.pbxproj │ │ │ ├── project.xcworkspace │ │ │ ├── contents.xcworkspacedata │ │ │ └── xcshareddata │ │ │ │ └── CDVCameraTest.xccheckout │ │ │ └── xcshareddata │ │ │ └── xcschemes │ │ │ ├── CDVCameraLib.xcscheme │ │ │ └── CDVCameraLibTests.xcscheme │ ├── README.md │ └── package.json ├── package-lock.json ├── package.json ├── plugin.xml └── tests.js ├── types └── index.d.ts └── www ├── Camera.js ├── CameraConstants.js ├── CameraPopoverHandle.js ├── CameraPopoverOptions.js └── ios └── CameraPopoverHandle.js /.asf.yaml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | github: 19 | description: Apache Cordova Plugin camera 20 | homepage: https://cordova.apache.org/ 21 | 22 | labels: 23 | - cordova 24 | - mobile 25 | - javascript 26 | - nodejs 27 | - hacktoberfest 28 | - java 29 | - objective-c 30 | - cordova-plugin 31 | 32 | features: 33 | wiki: false 34 | issues: true 35 | projects: true 36 | 37 | enabled_merge_buttons: 38 | squash: true 39 | merge: false 40 | rebase: false 41 | 42 | notifications: 43 | commits: commits@cordova.apache.org 44 | issues: issues@cordova.apache.org 45 | pullrequests_status: issues@cordova.apache.org 46 | pullrequests_comment: issues@cordova.apache.org 47 | -------------------------------------------------------------------------------- /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | root: true 19 | extends: '@cordova/eslint-config/browser' 20 | 21 | overrides: 22 | - files: [tests/**/*.js] 23 | extends: '@cordova/eslint-config/node-tests' 24 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | * text eol=lf 2 | 3 | # source code 4 | *.php text 5 | *.css text 6 | *.sass text 7 | *.scss text 8 | *.less text 9 | *.styl text 10 | *.js text 11 | *.coffee text 12 | *.json text 13 | *.htm text 14 | *.html text 15 | *.xml text 16 | *.svg text 17 | *.txt text 18 | *.ini text 19 | *.inc text 20 | *.pl text 21 | *.rb text 22 | *.py text 23 | *.scm text 24 | *.sql text 25 | *.sh text 26 | *.bat text 27 | 28 | # templates 29 | *.ejs text 30 | *.hbt text 31 | *.jade text 32 | *.haml text 33 | *.hbs text 34 | *.dot text 35 | *.tmpl text 36 | *.phtml text 37 | 38 | # server config 39 | .htaccess text 40 | 41 | # git config 42 | .gitattributes text 43 | .gitignore text 44 | .gitconfig text 45 | 46 | # code analysis config 47 | .jshintrc text 48 | .jscsrc text 49 | .jshintignore text 50 | .csslintrc text 51 | 52 | # misc config 53 | *.yaml text 54 | *.yml text 55 | .editorconfig text 56 | 57 | # build config 58 | *.npmignore text 59 | *.bowerrc text 60 | 61 | # Heroku 62 | Procfile text 63 | .slugignore text 64 | 65 | # Documentation 66 | *.md text 67 | LICENSE text 68 | AUTHORS text 69 | 70 | 71 | # 72 | ## These files are binary and should be left untouched 73 | # 74 | 75 | # (binary is a macro for -text -diff) 76 | *.png binary 77 | *.jpg binary 78 | *.jpeg binary 79 | *.gif binary 80 | *.ico binary 81 | *.mov binary 82 | *.mp4 binary 83 | *.mp3 binary 84 | *.flv binary 85 | *.fla binary 86 | *.swf binary 87 | *.gz binary 88 | *.zip binary 89 | *.7z binary 90 | *.ttf binary 91 | *.eot binary 92 | *.woff binary 93 | *.pyc binary 94 | *.pdf binary 95 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 5 | 6 | ### Issue Type 7 | 8 | 9 | - [ ] Bug Report 10 | - [ ] Feature Request 11 | - [ ] Support Question 12 | 13 | ## Description 14 | 15 | ## Information 16 | 17 | 18 | ### Command or Code 19 | 20 | 21 | ### Environment, Platform, Device 22 | 23 | 24 | 25 | 26 | ### Version information 27 | 34 | 35 | 36 | 37 | ## Checklist 38 | 39 | 40 | - [ ] I searched for already existing GitHub issues about this 41 | - [ ] I updated all Cordova tooling to their most recent version 42 | - [ ] I included all the necessary information above 43 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/BUG_REPORT.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🐛 Bug Report 3 | about: If something isn't working as expected. 4 | 5 | --- 6 | 7 | # Bug Report 8 | 9 | ## Problem 10 | 11 | ### What is expected to happen? 12 | 13 | 14 | 15 | ### What does actually happen? 16 | 17 | 18 | 19 | ## Information 20 | 21 | 22 | 23 | 24 | ### Command or Code 25 | 26 | 27 | 28 | 29 | ### Environment, Platform, Device 30 | 31 | 32 | 33 | 34 | ### Version information 35 | 42 | 43 | 44 | 45 | ## Checklist 46 | 47 | 48 | - [ ] I searched for existing GitHub issues 49 | - [ ] I updated all Cordova tooling to most recent version 50 | - [ ] I included all the necessary information above 51 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/FEATURE_REQUEST.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 🚀 Feature Request 3 | about: A suggestion for a new functionality 4 | 5 | --- 6 | 7 | # Feature Request 8 | 9 | ## Motivation Behind Feature 10 | 11 | 12 | 13 | 14 | ## Feature Description 15 | 20 | 21 | 22 | 23 | ## Alternatives or Workarounds 24 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/SUPPORT_QUESTION.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: 💬 Support Question 3 | about: If you have a question, please check out our Slack or StackOverflow! 4 | 5 | --- 6 | 7 | 8 | 9 | Apache Cordova uses GitHub Issues as a feature request and bug tracker _only_. 10 | For usage and support questions, please check out the resources below. Thanks! 11 | 12 | --- 13 | 14 | You can get answers to your usage and support questions about **Apache Cordova** on: 15 | 16 | * GitHub Discussions: https://github.com/apache/cordova/discussions 17 | * Slack Community Chat: https://cordova.slack.com (you can sign-up at https://s.apache.org/cordova-slack) 18 | * StackOverflow: https://stackoverflow.com/questions/tagged/cordova using the tag `cordova` 19 | 20 | --- 21 | 22 | If you are using a tool that uses Cordova internally, like e.g. Ionic, check their support channels: 23 | 24 | * **Ionic Framework** 25 | * [Ionic Community Forum](https://forum.ionicframework.com/) 26 | * [Ionic Discord](https://ionic.link/discord) -------------------------------------------------------------------------------- /.github/PULL_REQUEST_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | 8 | 9 | ### Platforms affected 10 | 11 | 12 | 13 | ### Motivation and Context 14 | 15 | 16 | 17 | 18 | 19 | ### Description 20 | 21 | 22 | 23 | 24 | ### Testing 25 | 26 | 27 | 28 | 29 | ### Checklist 30 | 31 | - [ ] I've run the tests to see all new and existing tests pass 32 | - [ ] I added automated test coverage as appropriate for this change 33 | - [ ] Commit is prefixed with `(platform)` if this change only applies to one platform (e.g. `(android)`) 34 | - [ ] 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/)) 35 | - [ ] I've updated the documentation if necessary 36 | -------------------------------------------------------------------------------- /.github/workflows/android.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | name: Android Testsuite 19 | 20 | on: 21 | push: 22 | paths-ignore: 23 | - '**.md' 24 | - 'LICENSE' 25 | - '.eslint*' 26 | 27 | pull_request: 28 | paths-ignore: 29 | - '**.md' 30 | - 'LICENSE' 31 | - '.eslint*' 32 | 33 | jobs: 34 | test: 35 | name: Android ${{ matrix.versions.android }} Test 36 | runs-on: ubuntu-latest 37 | continue-on-error: true 38 | 39 | # hoist configurations to top that are expected to be updated 40 | env: 41 | # Storing a copy of the repo 42 | repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }} 43 | 44 | node-version: 20 45 | 46 | # These are the default Java configurations used by most tests. 47 | # To customize these options, add "java-distro" or "java-version" to the strategy matrix with its overriding value. 48 | default_java-distro: temurin 49 | default_java-version: 17 50 | 51 | # These are the default Android System Image configurations used by most tests. 52 | # To customize these options, add "system-image-arch" or "system-image-target" to the strategy matrix with its overriding value. 53 | default_system-image-arch: x86_64 54 | default_system-image-target: google_apis # Most system images have a google_api option. Set this as default. 55 | 56 | # configurations for each testing strategy (test matrix) 57 | strategy: 58 | matrix: 59 | versions: 60 | - android: 7 61 | android-api: 24 62 | 63 | - android: 7.1 64 | android-api: 25 65 | 66 | - android: 8 67 | android-api: 26 68 | 69 | - android: 8.1 70 | android-api: 27 71 | system-image-arch: x86 72 | 73 | - android: 9 74 | android-api: 28 75 | 76 | - android: 10 77 | android-api: 29 78 | 79 | - android: 11 80 | android-api: 30 81 | 82 | - android: 12 83 | android-api: 31 84 | 85 | - android: 12L 86 | android-api: 32 87 | 88 | - android: 13 89 | android-api: 33 90 | 91 | - android: 14 92 | android-api: 34 93 | 94 | timeout-minutes: 60 95 | 96 | steps: 97 | - uses: actions/checkout@v4 98 | - uses: actions/setup-node@v4 99 | with: 100 | node-version: ${{ env.node-version }} 101 | - uses: actions/setup-java@v4 102 | env: 103 | java-version: ${{ matrix.versions.java-version == '' && env.default_java-version || matrix.versions.java-version }} 104 | java-distro: ${{ matrix.versions.java-distro == '' && env.default_java-distro || matrix.versions.java-distro }} 105 | with: 106 | distribution: ${{ env.java-distro }} 107 | java-version: ${{ env.java-version }} 108 | 109 | - name: Enable KVM group perms 110 | run: | 111 | echo 'KERNEL=="kvm", GROUP="kvm", MODE="0666", OPTIONS+="static_node=kvm"' | sudo tee /etc/udev/rules.d/99-kvm4all.rules 112 | sudo udevadm control --reload-rules 113 | sudo udevadm trigger --name-match=kvm 114 | 115 | - name: Run Environment Information 116 | run: | 117 | node --version 118 | npm --version 119 | java -version 120 | 121 | - name: Run npm install 122 | run: | 123 | export PATH="/usr/local/lib/android/sdk/platform-tools":$PATH 124 | export JAVA_HOME=$JAVA_HOME_11_X64 125 | npm i -g cordova@latest 126 | npm ci 127 | 128 | - name: Run paramedic install 129 | if: ${{ endswith(env.repo, '/cordova-paramedic') != true }} 130 | run: npm i -g github:apache/cordova-paramedic 131 | 132 | - uses: reactivecircus/android-emulator-runner@v2 133 | env: 134 | system-image-arch: ${{ matrix.versions.system-image-arch == '' && env.default_system-image-arch || matrix.versions.system-image-arch }} 135 | system-image-target: ${{ matrix.versions.system-image-target == '' && env.default_system-image-target || matrix.versions.system-image-target }} 136 | with: 137 | api-level: ${{ matrix.versions.android-api }} 138 | target: ${{ env.system-image-target }} 139 | arch: ${{ env.system-image-arch }} 140 | force-avd-creation: false 141 | disable-animations: false 142 | emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim 143 | script: echo "Pregenerate the AVD before running Paramedic" 144 | 145 | - name: Run paramedic tests 146 | uses: reactivecircus/android-emulator-runner@v2 147 | env: 148 | system-image-arch: ${{ matrix.versions.system-image-arch == '' && env.default_system-image-arch || matrix.versions.system-image-arch }} 149 | system-image-target: ${{ matrix.versions.system-image-target == '' && env.default_system-image-target || matrix.versions.system-image-target }} 150 | test_config: 'android-${{ matrix.versions.android }}.config.json' 151 | # Generally, this should automatically work for cordova-paramedic & plugins. If the path is unique, this can be manually changed. 152 | test_plugin_path: ${{ endswith(env.repo, '/cordova-paramedic') && './spec/testable-plugin/' || './' }} 153 | paramedic: ${{ endswith(env.repo, '/cordova-paramedic') && 'node main.js' || 'cordova-paramedic' }} 154 | with: 155 | api-level: ${{ matrix.versions.android-api }} 156 | target: ${{ env.system-image-target }} 157 | arch: ${{ env.system-image-arch }} 158 | force-avd-creation: false 159 | disable-animations: false 160 | emulator-options: -no-window -gpu swiftshader_indirect -noaudio -no-boot-anim 161 | script: ${{ env.paramedic }} --config ./pr/local/${{ env.test_config }} --plugin ${{ env.test_plugin_path }} 162 | -------------------------------------------------------------------------------- /.github/workflows/chrome.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | name: Chrome Testsuite 19 | 20 | on: 21 | push: 22 | paths-ignore: 23 | - '**.md' 24 | - 'LICENSE' 25 | - '.eslint*' 26 | pull_request: 27 | paths-ignore: 28 | - '**.md' 29 | - 'LICENSE' 30 | - '.eslint*' 31 | 32 | jobs: 33 | test: 34 | name: Chrome Latest Test 35 | runs-on: ubuntu-latest 36 | 37 | # hoist configurations to top that are expected to be updated 38 | env: 39 | # Storing a copy of the repo 40 | repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }} 41 | 42 | node-version: 20 43 | 44 | steps: 45 | - uses: actions/checkout@v4 46 | - uses: actions/setup-node@v4 47 | with: 48 | node-version: ${{ env.node-version }} 49 | 50 | - name: Run install xvfb 51 | run: sudo apt-get install xvfb 52 | 53 | - name: Run Environment Information 54 | run: | 55 | node --version 56 | npm --version 57 | 58 | - name: Run npm install 59 | run: | 60 | npm i -g cordova@latest 61 | npm ci 62 | 63 | - name: Run paramedic install 64 | if: ${{ endswith(env.repo, '/cordova-paramedic') != true }} 65 | run: npm i -g github:apache/cordova-paramedic 66 | 67 | - name: Run paramedic tests 68 | env: 69 | test_config: 'browser.config.json' 70 | # Generally, this should automatically work for cordova-paramedic & plugins. If the path is unique, this can be manually changed. 71 | test_plugin_path: ${{ endswith(env.repo, '/cordova-paramedic') && './spec/testable-plugin/' || './' }} 72 | paramedic: ${{ endswith(env.repo, '/cordova-paramedic') && 'node main.js' || 'cordova-paramedic' }} 73 | run: xvfb-run --auto-servernum ${{ env.paramedic }} --config ./pr/local/${{ env.test_config }} --plugin ${{ env.test_plugin_path }} 74 | -------------------------------------------------------------------------------- /.github/workflows/ios.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | name: iOS Testsuite 19 | 20 | on: 21 | push: 22 | paths-ignore: 23 | - '**.md' 24 | - 'LICENSE' 25 | - '.eslint*' 26 | pull_request: 27 | paths-ignore: 28 | - '**.md' 29 | - 'LICENSE' 30 | - '.eslint*' 31 | 32 | jobs: 33 | test: 34 | name: iOS ${{ matrix.versions.ios-version }} Test 35 | runs-on: ${{ matrix.versions.os-version }} 36 | continue-on-error: true 37 | 38 | # hoist configurations to top that are expected to be updated 39 | env: 40 | # Storing a copy of the repo 41 | repo: ${{ github.event.pull_request.head.repo.full_name || github.repository }} 42 | 43 | node-version: 20 44 | 45 | # > 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. 46 | # Because of Apple's requirement, listed above, We will only be using the latest Xcode release for testing. 47 | # To customize these options, add "xcode-version" to the strategy matrix with its overriding value. 48 | default_xcode-version: latest-stable 49 | 50 | strategy: 51 | matrix: 52 | versions: 53 | - os-version: macos-12 54 | ios-version: 15.x 55 | xcode-version: 13.x 56 | 57 | - os-version: macos-14 58 | ios-version: 16.x 59 | xcode-version: 14.x 60 | 61 | - os-version: macos-14 62 | ios-version: 17.x 63 | xcode-version: 15.x 64 | 65 | steps: 66 | - uses: actions/checkout@v4 67 | - uses: actions/setup-node@v4 68 | with: 69 | node-version: ${{ env.node-version }} 70 | - uses: maxim-lobanov/setup-xcode@60606e260d2fc5762a71e64e74b2174e8ea3c8bd 71 | env: 72 | xcode-version: ${{ matrix.versions.xcode-version == '' && env.default_xcode-version || matrix.versions.xcode-version }} 73 | with: 74 | xcode-version: ${{ env.xcode-version }} 75 | 76 | - name: Run Environment Information 77 | run: | 78 | node --version 79 | npm --version 80 | xcodebuild -version 81 | 82 | - name: Run npm install 83 | run: | 84 | npm i -g cordova@latest ios-deploy@latest 85 | npm ci 86 | 87 | - name: Run paramedic install 88 | if: ${{ endswith(env.repo, '/cordova-paramedic') != true }} 89 | run: npm i -g github:apache/cordova-paramedic 90 | 91 | - name: Run paramedic tests 92 | env: 93 | test_config: 'ios-${{ matrix.versions.ios-version }}.config.json' 94 | # Generally, this should automatically work for cordova-paramedic & plugins. If the path is unique, this can be manually changed. 95 | test_plugin_path: ${{ endswith(env.repo, '/cordova-paramedic') && './spec/testable-plugin/' || './' }} 96 | paramedic: ${{ endswith(env.repo, '/cordova-paramedic') && 'node main.js' || 'cordova-paramedic' }} 97 | run: ${{ env.paramedic }} --config ./pr/local/${{ env.test_config }} --plugin ${{ env.test_plugin_path }} 98 | -------------------------------------------------------------------------------- /.github/workflows/lint.yml: -------------------------------------------------------------------------------- 1 | # Licensed to the Apache Software Foundation (ASF) under one 2 | # or more contributor license agreements. See the NOTICE file 3 | # distributed with this work for additional information 4 | # regarding copyright ownership. The ASF licenses this file 5 | # to you under the Apache License, Version 2.0 (the 6 | # "License"); you may not use this file except in compliance 7 | # with the License. You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, 12 | # software distributed under the License is distributed on an 13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 14 | # KIND, either express or implied. See the License for the 15 | # specific language governing permissions and limitations 16 | # under the License. 17 | 18 | name: Lint Test 19 | 20 | on: 21 | push: 22 | paths: 23 | - '**.js' 24 | - '.eslint*' 25 | - '.github/workflow/lint.yml' 26 | pull_request: 27 | paths: 28 | - '**.js' 29 | - '.eslint*' 30 | - '.github/workflow/lint.yml' 31 | 32 | jobs: 33 | test: 34 | name: Lint Test 35 | runs-on: ubuntu-latest 36 | env: 37 | node-version: 20 38 | 39 | steps: 40 | - uses: actions/checkout@v4 41 | - uses: actions/setup-node@v4 42 | with: 43 | node-version: ${{ env.node-version }} 44 | 45 | - name: Run Environment Information 46 | run: | 47 | node --version 48 | npm --version 49 | 50 | - name: Run npm install 51 | run: | 52 | npm ci 53 | 54 | - name: Run lint test 55 | run: | 56 | npm run lint 57 | -------------------------------------------------------------------------------- /.github/workflows/release-notify.yml: -------------------------------------------------------------------------------- 1 | name: Close issue asking for release 2 | 3 | on: 4 | issues: 5 | types: [opened] 6 | 7 | jobs: 8 | action-test: 9 | runs-on: ubuntu-latest 10 | steps: 11 | - uses: niklasmerz/release-notify@master 12 | with: 13 | repo-token: ${{ secrets.GITHUB_TOKEN }} 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #If ignorance is bliss, then somebody knock the smile off my face 2 | 3 | *.csproj.user 4 | *.suo 5 | *.cache 6 | Thumbs.db 7 | *.DS_Store 8 | 9 | *.bak 10 | *.cache 11 | *.log 12 | *.swp 13 | *.user 14 | 15 | /node_modules/** 16 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | .* 2 | tests 3 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | registry=https://registry.npmjs.org 2 | 3 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 21 | 22 | # Contributing to Apache Cordova 23 | 24 | Anyone can contribute to Cordova. And we need your contributions. 25 | 26 | There are multiple ways to contribute: report bugs, improve the docs, and 27 | contribute code. 28 | 29 | For instructions on this, start with the 30 | [contribution overview](http://cordova.apache.org/contribute/). 31 | 32 | The details are explained there, but the important items are: 33 | - Check for Github issues that corresponds to your contribution and link or create them if necessary. 34 | - Run the tests so your patch doesn't break existing functionality. 35 | 36 | We look forward to your contributions! 37 | 38 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Apache Cordova 2 | Copyright 2012 The Apache Software Foundation 3 | 4 | This product includes software developed at 5 | The Apache Software Foundation (http://www.apache.org/). 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cordova-plugin-camera", 3 | "version": "8.0.1-dev", 4 | "description": "Cordova Camera Plugin", 5 | "types": "./types/index.d.ts", 6 | "cordova": { 7 | "id": "cordova-plugin-camera", 8 | "platforms": [ 9 | "android", 10 | "ios", 11 | "browser" 12 | ] 13 | }, 14 | "repository": "github:apache/cordova-plugin-camera", 15 | "bugs": "https://github.com/apache/cordova-plugin-camera/issues", 16 | "keywords": [ 17 | "cordova", 18 | "camera", 19 | "ecosystem:cordova", 20 | "cordova-android", 21 | "cordova-ios", 22 | "cordova-browser" 23 | ], 24 | "scripts": { 25 | "test": "npm run lint", 26 | "lint": "eslint ." 27 | }, 28 | "author": "Apache Software Foundation", 29 | "license": "Apache-2.0", 30 | "engines": { 31 | "cordovaDependencies": { 32 | "3.0.0": { 33 | "cordova-android": ">=6.3.0" 34 | }, 35 | "4.1.0": { 36 | "cordova-android": ">=6.3.0", 37 | "cordova": ">=7.1.0" 38 | }, 39 | "5.0.0": { 40 | "cordova-android": ">=9.0.0", 41 | "cordova-ios": ">=5.1.0", 42 | "cordova": ">=9.0.0" 43 | }, 44 | "5.0.4-dev": { 45 | "cordova-android": "<10.0.0", 46 | "cordova-ios": ">=5.1.0", 47 | "cordova": ">=9.0.0" 48 | }, 49 | "6.0.0": { 50 | "cordova-android": ">=10.0.0", 51 | "cordova-ios": ">=5.1.0", 52 | "cordova": ">=9.0.0" 53 | }, 54 | "7.0.0": { 55 | "cordova-android": ">=12.0.0", 56 | "cordova-ios": ">=5.1.0", 57 | "cordova": ">=9.0.0" 58 | }, 59 | "8.0.0": { 60 | "cordova-android": ">=12.0.0", 61 | "cordova-ios": ">=5.1.0", 62 | "cordova": ">=9.0.0" 63 | }, 64 | "9.0.0": { 65 | "cordova": ">100" 66 | } 67 | } 68 | }, 69 | "devDependencies": { 70 | "@cordova/eslint-config": "^5.1.0" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 25 | Camera 26 | Cordova Camera Plugin 27 | Apache 2.0 28 | cordova,camera 29 | https://github.com/apache/cordova-plugin-camera 30 | https://github.com/apache/cordova-plugin-camera/issues 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 63 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | -------------------------------------------------------------------------------- /src/android/ExifHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | package org.apache.cordova.camera; 20 | 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | 24 | import android.media.ExifInterface; 25 | 26 | public class ExifHelper { 27 | private String aperture = null; 28 | private String datetime = null; 29 | private String exposureTime = null; 30 | private String flash = null; 31 | private String focalLength = null; 32 | private String gpsAltitude = null; 33 | private String gpsAltitudeRef = null; 34 | private String gpsDateStamp = null; 35 | private String gpsLatitude = null; 36 | private String gpsLatitudeRef = null; 37 | private String gpsLongitude = null; 38 | private String gpsLongitudeRef = null; 39 | private String gpsProcessingMethod = null; 40 | private String gpsTimestamp = null; 41 | private String iso = null; 42 | private String make = null; 43 | private String model = null; 44 | private String orientation = null; 45 | private String whiteBalance = null; 46 | 47 | private ExifInterface inFile = null; 48 | private ExifInterface outFile = null; 49 | 50 | /** 51 | * The file before it is compressed 52 | * 53 | * @param filePath 54 | * @throws IOException 55 | */ 56 | public void createInFile(String filePath) throws IOException { 57 | this.inFile = new ExifInterface(filePath); 58 | } 59 | 60 | /** 61 | * The file before it is compressed 62 | * 63 | * @param input 64 | * @throws IOException 65 | */ 66 | public void createInFile(InputStream input) throws IOException { 67 | this.inFile = new ExifInterface(input); 68 | } 69 | 70 | /** 71 | * The file after it has been compressed 72 | * 73 | * @param filePath 74 | * @throws IOException 75 | */ 76 | public void createOutFile(String filePath) throws IOException { 77 | this.outFile = new ExifInterface(filePath); 78 | } 79 | 80 | /** 81 | * Reads all the EXIF data from the input file. 82 | */ 83 | public void readExifData() { 84 | this.aperture = inFile.getAttribute(ExifInterface.TAG_APERTURE); 85 | this.datetime = inFile.getAttribute(ExifInterface.TAG_DATETIME); 86 | this.exposureTime = inFile.getAttribute(ExifInterface.TAG_EXPOSURE_TIME); 87 | this.flash = inFile.getAttribute(ExifInterface.TAG_FLASH); 88 | this.focalLength = inFile.getAttribute(ExifInterface.TAG_FOCAL_LENGTH); 89 | this.gpsAltitude = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE); 90 | this.gpsAltitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF); 91 | this.gpsDateStamp = inFile.getAttribute(ExifInterface.TAG_GPS_DATESTAMP); 92 | this.gpsLatitude = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE); 93 | this.gpsLatitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LATITUDE_REF); 94 | this.gpsLongitude = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE); 95 | this.gpsLongitudeRef = inFile.getAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF); 96 | this.gpsProcessingMethod = inFile.getAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD); 97 | this.gpsTimestamp = inFile.getAttribute(ExifInterface.TAG_GPS_TIMESTAMP); 98 | this.iso = inFile.getAttribute(ExifInterface.TAG_ISO); 99 | this.make = inFile.getAttribute(ExifInterface.TAG_MAKE); 100 | this.model = inFile.getAttribute(ExifInterface.TAG_MODEL); 101 | this.orientation = inFile.getAttribute(ExifInterface.TAG_ORIENTATION); 102 | this.whiteBalance = inFile.getAttribute(ExifInterface.TAG_WHITE_BALANCE); 103 | } 104 | 105 | /** 106 | * Writes the previously stored EXIF data to the output file. 107 | * 108 | * @throws IOException 109 | */ 110 | public void writeExifData() throws IOException { 111 | // Don't try to write to a null file 112 | if (this.outFile == null) { 113 | return; 114 | } 115 | 116 | if (this.aperture != null) { 117 | this.outFile.setAttribute(ExifInterface.TAG_APERTURE, this.aperture); 118 | } 119 | if (this.datetime != null) { 120 | this.outFile.setAttribute(ExifInterface.TAG_DATETIME, this.datetime); 121 | } 122 | if (this.exposureTime != null) { 123 | this.outFile.setAttribute(ExifInterface.TAG_EXPOSURE_TIME, this.exposureTime); 124 | } 125 | if (this.flash != null) { 126 | this.outFile.setAttribute(ExifInterface.TAG_FLASH, this.flash); 127 | } 128 | if (this.focalLength != null) { 129 | this.outFile.setAttribute(ExifInterface.TAG_FOCAL_LENGTH, this.focalLength); 130 | } 131 | if (this.gpsAltitude != null) { 132 | this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE, this.gpsAltitude); 133 | } 134 | if (this.gpsAltitudeRef != null) { 135 | this.outFile.setAttribute(ExifInterface.TAG_GPS_ALTITUDE_REF, this.gpsAltitudeRef); 136 | } 137 | if (this.gpsDateStamp != null) { 138 | this.outFile.setAttribute(ExifInterface.TAG_GPS_DATESTAMP, this.gpsDateStamp); 139 | } 140 | if (this.gpsLatitude != null) { 141 | this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE, this.gpsLatitude); 142 | } 143 | if (this.gpsLatitudeRef != null) { 144 | this.outFile.setAttribute(ExifInterface.TAG_GPS_LATITUDE_REF, this.gpsLatitudeRef); 145 | } 146 | if (this.gpsLongitude != null) { 147 | this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE, this.gpsLongitude); 148 | } 149 | if (this.gpsLongitudeRef != null) { 150 | this.outFile.setAttribute(ExifInterface.TAG_GPS_LONGITUDE_REF, this.gpsLongitudeRef); 151 | } 152 | if (this.gpsProcessingMethod != null) { 153 | this.outFile.setAttribute(ExifInterface.TAG_GPS_PROCESSING_METHOD, this.gpsProcessingMethod); 154 | } 155 | if (this.gpsTimestamp != null) { 156 | this.outFile.setAttribute(ExifInterface.TAG_GPS_TIMESTAMP, this.gpsTimestamp); 157 | } 158 | if (this.iso != null) { 159 | this.outFile.setAttribute(ExifInterface.TAG_ISO, this.iso); 160 | } 161 | if (this.make != null) { 162 | this.outFile.setAttribute(ExifInterface.TAG_MAKE, this.make); 163 | } 164 | if (this.model != null) { 165 | this.outFile.setAttribute(ExifInterface.TAG_MODEL, this.model); 166 | } 167 | if (this.orientation != null) { 168 | this.outFile.setAttribute(ExifInterface.TAG_ORIENTATION, this.orientation); 169 | } 170 | if (this.whiteBalance != null) { 171 | this.outFile.setAttribute(ExifInterface.TAG_WHITE_BALANCE, this.whiteBalance); 172 | } 173 | 174 | this.outFile.saveAttributes(); 175 | } 176 | 177 | public int getOrientation() { 178 | int o = Integer.parseInt(this.orientation); 179 | 180 | if (o == ExifInterface.ORIENTATION_NORMAL) { 181 | return 0; 182 | } else if (o == ExifInterface.ORIENTATION_ROTATE_90) { 183 | return 90; 184 | } else if (o == ExifInterface.ORIENTATION_ROTATE_180) { 185 | return 180; 186 | } else if (o == ExifInterface.ORIENTATION_ROTATE_270) { 187 | return 270; 188 | } else { 189 | return 0; 190 | } 191 | } 192 | 193 | public void resetOrientation() { 194 | this.orientation = "" + ExifInterface.ORIENTATION_NORMAL; 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/android/FileHelper.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | http://www.apache.org/licenses/LICENSE-2.0 10 | Unless required by applicable law or agreed to in writing, 11 | software distributed under the License is distributed on an 12 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 13 | KIND, either express or implied. See the License for the 14 | specific language governing permissions and limitations 15 | under the License. 16 | */ 17 | package org.apache.cordova.camera; 18 | 19 | import android.annotation.SuppressLint; 20 | import android.content.ContentUris; 21 | import android.content.Context; 22 | import android.database.Cursor; 23 | import android.net.Uri; 24 | import android.os.Build; 25 | import android.os.Environment; 26 | import android.provider.DocumentsContract; 27 | import android.provider.MediaStore; 28 | import android.webkit.MimeTypeMap; 29 | 30 | import org.apache.cordova.CordovaInterface; 31 | 32 | import java.io.File; 33 | import java.io.FileInputStream; 34 | import java.io.IOException; 35 | import java.io.InputStream; 36 | import java.util.Locale; 37 | 38 | public class FileHelper { 39 | private static final String LOG_TAG = "FileUtils"; 40 | private static final String _DATA = "_data"; 41 | 42 | /** 43 | * Returns the real path of the given URI string. 44 | * If the given URI string represents a content:// URI, the real path is retrieved from the media store. 45 | * 46 | * @param uri the URI of the audio/image/video 47 | * @param cordova the current application context 48 | * @return the full path to the file 49 | */ 50 | @SuppressWarnings("deprecation") 51 | public static String getRealPath(Uri uri, CordovaInterface cordova) { 52 | return FileHelper.getRealPathFromURI(cordova.getActivity(), uri); 53 | } 54 | 55 | /** 56 | * Returns the real path of the given URI. 57 | * If the given URI is a content:// URI, the real path is retrieved from the media store. 58 | * 59 | * @param uriString the URI string from which to obtain the input stream 60 | * @param cordova the current application context 61 | * @return the full path to the file 62 | */ 63 | public static String getRealPath(String uriString, CordovaInterface cordova) { 64 | return FileHelper.getRealPath(Uri.parse(uriString), cordova); 65 | } 66 | 67 | @SuppressLint("NewApi") 68 | public static String getRealPathFromURI(final Context context, final Uri uri) { 69 | // DocumentProvider 70 | if (DocumentsContract.isDocumentUri(context, uri)) { 71 | 72 | // ExternalStorageProvider 73 | if (isExternalStorageDocument(uri)) { 74 | final String docId = DocumentsContract.getDocumentId(uri); 75 | final String[] split = docId.split(":"); 76 | final String type = split[0]; 77 | 78 | if ("primary".equalsIgnoreCase(type)) { 79 | return Environment.getExternalStorageDirectory() + "/" + split[1]; 80 | } 81 | 82 | // TODO handle non-primary volumes 83 | } 84 | // DownloadsProvider 85 | else if (isDownloadsDocument(uri)) { 86 | 87 | final String id = DocumentsContract.getDocumentId(uri); 88 | if (id != null && id.length() > 0) { 89 | if (id.startsWith("raw:")) { 90 | return id.replaceFirst("raw:", ""); 91 | } 92 | try { 93 | final Uri contentUri = ContentUris.withAppendedId( 94 | Uri.parse("content://downloads/public_downloads"), Long.valueOf(id)); 95 | 96 | return getDataColumn(context, contentUri, null, null); 97 | } catch (NumberFormatException e) { 98 | return null; 99 | } 100 | } else { 101 | return null; 102 | } 103 | } 104 | // MediaProvider 105 | else if (isMediaDocument(uri)) { 106 | final String docId = DocumentsContract.getDocumentId(uri); 107 | final String[] split = docId.split(":"); 108 | final String type = split[0]; 109 | 110 | Uri contentUri = null; 111 | if ("image".equals(type)) { 112 | contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; 113 | } else if ("video".equals(type)) { 114 | contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI; 115 | } else if ("audio".equals(type)) { 116 | contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI; 117 | } 118 | 119 | final String selection = "_id=?"; 120 | final String[] selectionArgs = new String[] { 121 | split[1] 122 | }; 123 | 124 | return getDataColumn(context, contentUri, selection, selectionArgs); 125 | } 126 | } 127 | // MediaStore (and general) 128 | else if ("content".equalsIgnoreCase(uri.getScheme())) { 129 | 130 | // Return the remote address 131 | if (isGooglePhotosUri(uri)) 132 | return uri.getLastPathSegment(); 133 | 134 | if (isFileProviderUri(context, uri)) 135 | return getFileProviderPath(context, uri); 136 | 137 | return getDataColumn(context, uri, null, null); 138 | } 139 | // File 140 | else if ("file".equalsIgnoreCase(uri.getScheme())) { 141 | return uri.getPath(); 142 | } 143 | 144 | return null; 145 | } 146 | 147 | /** 148 | * Returns an input stream based on given URI string. 149 | * 150 | * @param uriString the URI string from which to obtain the input stream 151 | * @param cordova the current application context 152 | * @return an input stream into the data at the given URI or null if given an invalid URI string 153 | * @throws IOException 154 | */ 155 | public static InputStream getInputStreamFromUriString(String uriString, CordovaInterface cordova) 156 | throws IOException { 157 | InputStream returnValue = null; 158 | if (uriString.startsWith("content")) { 159 | Uri uri = Uri.parse(uriString); 160 | returnValue = cordova.getActivity().getContentResolver().openInputStream(uri); 161 | } else if (uriString.startsWith("file://")) { 162 | int question = uriString.indexOf("?"); 163 | if (question > -1) { 164 | uriString = uriString.substring(0, question); 165 | } 166 | 167 | if (uriString.startsWith("file:///android_asset/")) { 168 | Uri uri = Uri.parse(uriString); 169 | String relativePath = uri.getPath().substring(15); 170 | returnValue = cordova.getActivity().getAssets().open(relativePath); 171 | } else { 172 | // might still be content so try that first 173 | try { 174 | returnValue = cordova.getActivity().getContentResolver().openInputStream(Uri.parse(uriString)); 175 | } catch (Exception e) { 176 | returnValue = null; 177 | } 178 | if (returnValue == null) { 179 | returnValue = new FileInputStream(getRealPath(uriString, cordova)); 180 | } 181 | } 182 | } else { 183 | returnValue = new FileInputStream(uriString); 184 | } 185 | return returnValue; 186 | } 187 | 188 | /** 189 | * Removes the "file://" prefix from the given URI string, if applicable. 190 | * If the given URI string doesn't have a "file://" prefix, it is returned unchanged. 191 | * 192 | * @param uriString the URI string to operate on 193 | * @return a path without the "file://" prefix 194 | */ 195 | public static String stripFileProtocol(String uriString) { 196 | 197 | if (uriString.startsWith("file://")) { 198 | uriString = uriString.substring(7); 199 | } 200 | return uriString; 201 | } 202 | 203 | public static String getMimeTypeForExtension(String path) { 204 | String extension = path; 205 | int lastDot = extension.lastIndexOf('.'); 206 | if (lastDot != -1) { 207 | extension = extension.substring(lastDot + 1); 208 | } 209 | // Convert the URI string to lower case to ensure compatibility with MimeTypeMap (see CB-2185). 210 | extension = extension.toLowerCase(Locale.getDefault()); 211 | if (extension.equals("3ga")) { 212 | return "audio/3gpp"; 213 | } 214 | return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension); 215 | } 216 | 217 | /** 218 | * Returns the mime type of the data specified by the given URI string. 219 | * 220 | * @param uriString the URI string of the data 221 | * @return the mime type of the specified data 222 | */ 223 | public static String getMimeType(String uriString, CordovaInterface cordova) { 224 | String mimeType; 225 | 226 | Uri uri = Uri.parse(uriString); 227 | if (uriString.startsWith("content://")) { 228 | mimeType = cordova.getActivity().getContentResolver().getType(uri); 229 | } else { 230 | mimeType = getMimeTypeForExtension(uri.getPath()); 231 | } 232 | 233 | return mimeType; 234 | } 235 | 236 | /** 237 | * Get the value of the data column for this Uri. This is useful for 238 | * MediaStore Uris, and other file-based ContentProviders. 239 | * 240 | * @param context The context. 241 | * @param uri The Uri to query. 242 | * @param selection (Optional) Filter used in the query. 243 | * @param selectionArgs (Optional) Selection arguments used in the query. 244 | * @return The value of the _data column, which is typically a file path. 245 | * @author paulburke 246 | */ 247 | public static String getDataColumn(Context context, Uri uri, String selection, 248 | String[] selectionArgs) { 249 | 250 | Cursor cursor = null; 251 | final String column = "_data"; 252 | final String[] projection = { 253 | column 254 | }; 255 | 256 | try { 257 | cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, 258 | null); 259 | if (cursor != null && cursor.moveToFirst()) { 260 | 261 | final int column_index = cursor.getColumnIndexOrThrow(column); 262 | return cursor.getString(column_index); 263 | } 264 | } catch (Exception e) { 265 | return null; 266 | } finally { 267 | if (cursor != null) 268 | cursor.close(); 269 | } 270 | return null; 271 | } 272 | 273 | /** 274 | * @param uri The Uri to check. 275 | * @return Whether the Uri authority is ExternalStorageProvider. 276 | * @author paulburke 277 | */ 278 | public static boolean isExternalStorageDocument(Uri uri) { 279 | return "com.android.externalstorage.documents".equals(uri.getAuthority()); 280 | } 281 | 282 | /** 283 | * @param uri The Uri to check. 284 | * @return Whether the Uri authority is DownloadsProvider. 285 | * @author paulburke 286 | */ 287 | public static boolean isDownloadsDocument(Uri uri) { 288 | return "com.android.providers.downloads.documents".equals(uri.getAuthority()); 289 | } 290 | 291 | /** 292 | * @param uri The Uri to check. 293 | * @return Whether the Uri authority is MediaProvider. 294 | * @author paulburke 295 | */ 296 | public static boolean isMediaDocument(Uri uri) { 297 | return "com.android.providers.media.documents".equals(uri.getAuthority()); 298 | } 299 | 300 | /** 301 | * @param uri The Uri to check. 302 | * @return Whether the Uri authority is Google Photos. 303 | */ 304 | public static boolean isGooglePhotosUri(Uri uri) { 305 | return "com.google.android.apps.photos.content".equals(uri.getAuthority()); 306 | } 307 | 308 | /** 309 | * @param context The Application context 310 | * @param uri The Uri is checked by functions 311 | * @return Whether the Uri authority is FileProvider 312 | */ 313 | public static boolean isFileProviderUri(final Context context, final Uri uri) { 314 | final String packageName = context.getPackageName(); 315 | final String authority = new StringBuilder(packageName).append(".provider").toString(); 316 | return authority.equals(uri.getAuthority()); 317 | } 318 | 319 | /** 320 | * @param context The Application context 321 | * @param uri The Uri is checked by functions 322 | * @return File path or null if file is missing 323 | */ 324 | public static String getFileProviderPath(final Context context, final Uri uri) 325 | { 326 | final File appDir = context.getExternalFilesDir(Environment.DIRECTORY_PICTURES); 327 | final File file = new File(appDir, uri.getLastPathSegment()); 328 | return file.exists() ? file.toString(): null; 329 | } 330 | 331 | } 332 | -------------------------------------------------------------------------------- /src/android/FileProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | package org.apache.cordova.camera; 20 | 21 | public class FileProvider extends androidx.core.content.FileProvider {} 22 | -------------------------------------------------------------------------------- /src/android/GalleryPathVO.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | package org.apache.cordova.camera; 20 | 21 | public class GalleryPathVO { 22 | private final String galleryPath; 23 | private String picturesDirectory; 24 | private String galleryFileName; 25 | 26 | public GalleryPathVO(String picturesDirectory, String galleryFileName) { 27 | this.picturesDirectory = picturesDirectory; 28 | this.galleryFileName = galleryFileName; 29 | this.galleryPath = this.picturesDirectory + "/" + this.galleryFileName; 30 | } 31 | 32 | public String getGalleryPath() { 33 | return galleryPath; 34 | } 35 | 36 | public String getPicturesDirectory() { 37 | return picturesDirectory; 38 | } 39 | 40 | public String getGalleryFileName() { 41 | return galleryFileName; 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /src/android/xml/camera_provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/browser/CameraProxy.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on an 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | * KIND, either express or implied. See the License for the 17 | * specific language governing permissions and limitations 18 | * under the License. 19 | * 20 | */ 21 | 22 | const HIGHEST_POSSIBLE_Z_INDEX = 2147483647; 23 | 24 | function takePicture (success, error, opts) { 25 | if (opts && opts[2] === 1) { 26 | capture(success, error, opts); 27 | } else { 28 | const input = document.createElement('input'); 29 | input.style.position = 'relative'; 30 | input.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX; 31 | input.className = 'cordova-camera-select'; 32 | input.type = 'file'; 33 | input.name = 'files[]'; 34 | 35 | input.onchange = function (inputEvent) { 36 | const reader = new FileReader(); /* eslint no-undef : 0 */ 37 | reader.onload = function (readerEvent) { 38 | input.parentNode.removeChild(input); 39 | 40 | const imageData = readerEvent.target.result; 41 | 42 | return success(imageData); 43 | }; 44 | 45 | reader.readAsDataURL(inputEvent.target.files[0]); 46 | }; 47 | 48 | document.body.appendChild(input); 49 | } 50 | } 51 | 52 | function capture (success, errorCallback, opts) { 53 | let localMediaStream; 54 | let targetWidth = opts[3]; 55 | let targetHeight = opts[4]; 56 | 57 | targetWidth = targetWidth === -1 ? 320 : targetWidth; 58 | targetHeight = targetHeight === -1 ? 240 : targetHeight; 59 | 60 | const video = document.createElement('video'); 61 | const button = document.createElement('button'); 62 | const parent = document.createElement('div'); 63 | parent.style.position = 'relative'; 64 | parent.style.zIndex = HIGHEST_POSSIBLE_Z_INDEX; 65 | parent.className = 'cordova-camera-capture'; 66 | parent.appendChild(video); 67 | parent.appendChild(button); 68 | 69 | video.width = targetWidth; 70 | video.height = targetHeight; 71 | button.innerHTML = 'Capture!'; 72 | 73 | button.onclick = function () { 74 | // create a canvas and capture a frame from video stream 75 | const canvas = document.createElement('canvas'); 76 | canvas.width = targetWidth; 77 | canvas.height = targetHeight; 78 | canvas.getContext('2d').drawImage(video, 0, 0, targetWidth, targetHeight); 79 | 80 | // convert image stored in canvas to base64 encoded image 81 | const imageData = canvas.toDataURL('image/png'); 82 | 83 | // stop video stream, remove video and button. 84 | // Note that MediaStream.stop() is deprecated as of Chrome 47. 85 | if (localMediaStream.stop) { 86 | localMediaStream.stop(); 87 | } else { 88 | localMediaStream.getTracks().forEach(function (track) { 89 | track.stop(); 90 | }); 91 | } 92 | parent.parentNode.removeChild(parent); 93 | 94 | return success(imageData); 95 | }; 96 | 97 | navigator.getUserMedia = navigator.getUserMedia || 98 | navigator.webkitGetUserMedia || 99 | navigator.mozGetUserMedia || 100 | navigator.msGetUserMedia; 101 | 102 | const successCallback = function (stream) { 103 | localMediaStream = stream; 104 | if ('srcObject' in video) { 105 | video.srcObject = localMediaStream; 106 | } else { 107 | video.src = window.URL.createObjectURL(localMediaStream); 108 | } 109 | video.play(); 110 | document.body.appendChild(parent); 111 | }; 112 | 113 | if (navigator.mediaDevices.getUserMedia) { 114 | navigator.mediaDevices.getUserMedia({ video: true, audio: false }) 115 | .then(successCallback) 116 | .catch(errorCallback); 117 | } else if (navigator.getUserMedia) { 118 | navigator.getUserMedia({ video: true, audio: false }, successCallback, errorCallback); 119 | } else { 120 | alert('Browser does not support camera :('); 121 | } 122 | } 123 | 124 | module.exports = { 125 | takePicture, 126 | cleanup: function () {} 127 | }; 128 | 129 | require('cordova/exec/proxy').add('Camera', module.exports); 130 | -------------------------------------------------------------------------------- /src/ios/CDVCamera.h: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | #import 21 | #import 22 | #import 23 | #import 24 | 25 | enum CDVDestinationType { 26 | DestinationTypeDataUrl = 0, 27 | DestinationTypeFileUri 28 | }; 29 | typedef NSUInteger CDVDestinationType; 30 | 31 | enum CDVEncodingType { 32 | EncodingTypeJPEG = 0, 33 | EncodingTypePNG 34 | }; 35 | typedef NSUInteger CDVEncodingType; 36 | 37 | enum CDVMediaType { 38 | MediaTypePicture = 0, 39 | MediaTypeVideo, 40 | MediaTypeAll 41 | }; 42 | typedef NSUInteger CDVMediaType; 43 | 44 | @interface CDVPictureOptions : NSObject 45 | 46 | @property (strong) NSNumber* quality; 47 | @property (assign) CDVDestinationType destinationType; 48 | @property (assign) UIImagePickerControllerSourceType sourceType; 49 | @property (assign) CGSize targetSize; 50 | @property (assign) CDVEncodingType encodingType; 51 | @property (assign) CDVMediaType mediaType; 52 | @property (assign) BOOL allowsEditing; 53 | @property (assign) BOOL correctOrientation; 54 | @property (assign) BOOL saveToPhotoAlbum; 55 | @property (strong) NSDictionary* popoverOptions; 56 | @property (assign) UIImagePickerControllerCameraDevice cameraDirection; 57 | 58 | @property (assign) BOOL popoverSupported; 59 | @property (assign) BOOL usesGeolocation; 60 | @property (assign) BOOL cropToSize; 61 | 62 | + (instancetype) createFromTakePictureArguments:(CDVInvokedUrlCommand*)command; 63 | 64 | @end 65 | 66 | @interface CDVCameraPicker : UIImagePickerController 67 | 68 | @property (strong) CDVPictureOptions* pictureOptions; 69 | 70 | @property (copy) NSString* callbackId; 71 | @property (copy) NSString* postUrl; 72 | @property (strong) UIPopoverController* pickerPopoverController; 73 | @property (assign) BOOL cropToSize; 74 | @property (strong) UIView* webView; 75 | 76 | + (instancetype) createFromPictureOptions:(CDVPictureOptions*)options; 77 | 78 | @end 79 | 80 | // ======================================================================= // 81 | 82 | @interface CDVCamera : CDVPlugin 86 | {} 87 | 88 | @property (strong) CDVCameraPicker* pickerController; 89 | @property (strong) NSMutableDictionary *metadata; 90 | @property (strong, nonatomic) CLLocationManager *locationManager; 91 | @property (strong) NSData* data; 92 | 93 | /* 94 | * getPicture 95 | * 96 | * arguments: 97 | * 1: this is the javascript function that will be called with the results, the first parameter passed to the 98 | * javascript function is the picture as a Base64 encoded string 99 | * 2: this is the javascript function to be called if there was an error 100 | * options: 101 | * quality: integer between 1 and 100 102 | */ 103 | - (void)takePicture:(CDVInvokedUrlCommand*)command; 104 | - (void)cleanup:(CDVInvokedUrlCommand*)command; 105 | - (void)repositionPopover:(CDVInvokedUrlCommand*)command; 106 | 107 | - (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingMediaWithInfo:(NSDictionary*)info; 108 | - (void)imagePickerController:(UIImagePickerController*)picker didFinishPickingImage:(UIImage*)image editingInfo:(NSDictionary*)editingInfo; 109 | - (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker; 110 | - (void)navigationController:(UINavigationController *)navigationController willShowViewController:(UIViewController *)viewController animated:(BOOL)animated; 111 | 112 | - (void)locationManager:(CLLocationManager*)manager didUpdateToLocation:(CLLocation*)newLocation fromLocation:(CLLocation*)oldLocation; 113 | - (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error; 114 | 115 | @end 116 | -------------------------------------------------------------------------------- /src/ios/CDVExif.h: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | #ifndef CordovaLib_ExifData_h 21 | #define CordovaLib_ExifData_h 22 | 23 | // exif data types 24 | typedef enum exifDataTypes { 25 | EDT_UBYTE = 1, // 8 bit unsigned integer 26 | EDT_ASCII_STRING, // 8 bits containing 7 bit ASCII code, null terminated 27 | EDT_USHORT, // 16 bit unsigned integer 28 | EDT_ULONG, // 32 bit unsigned integer 29 | EDT_URATIONAL, // 2 longs, first is numerator and second is denominator 30 | EDT_SBYTE, 31 | EDT_UNDEFINED, // 8 bits 32 | EDT_SSHORT, 33 | EDT_SLONG, // 32bit signed integer (2's complement) 34 | EDT_SRATIONAL, // 2 SLONGS, first long is numerator, second is denominator 35 | EDT_SINGLEFLOAT, 36 | EDT_DOUBLEFLOAT 37 | } ExifDataTypes; 38 | 39 | // maps integer code for exif data types to width in bytes 40 | static const int DataTypeToWidth[] = {1,1,2,4,8,1,1,2,4,8,4,8}; 41 | 42 | static const int RECURSE_HORIZON = 8; 43 | #endif 44 | -------------------------------------------------------------------------------- /src/ios/CDVJpegHeaderWriter.h: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | #import 21 | 22 | @interface CDVJpegHeaderWriter : NSObject { 23 | NSDictionary * SubIFDTagFormatDict; 24 | NSDictionary * IFD0TagFormatDict; 25 | } 26 | 27 | - (NSData*) spliceExifBlockIntoJpeg: (NSData*) jpegdata 28 | withExifBlock: (NSString*) exifstr; 29 | - (NSString*) createExifAPP1 : (NSDictionary*) datadict; 30 | - (NSString*) formattedHexStringFromDecimalNumber: (NSNumber*) numb 31 | withPlaces: (NSNumber*) width; 32 | - (NSString*) formatNumberWithLeadingZeroes: (NSNumber*) numb 33 | withPlaces: (NSNumber*) places; 34 | - (NSString*) decimalToUnsignedRational: (NSNumber*) numb 35 | withResultNumerator: (NSNumber**) numerator 36 | withResultDenominator: (NSNumber**) denominator; 37 | - (void) continuedFraction: (double) val 38 | withFractionList: (NSMutableArray*) fractionlist 39 | withHorizon: (int) horizon; 40 | //- (void) expandContinuedFraction: (NSArray*) fractionlist; 41 | - (void) splitDouble: (double) val 42 | withIntComponent: (int*) rightside 43 | withFloatRemainder: (double*) leftside; 44 | - (NSString*) formatRationalWithNumerator: (NSNumber*) numerator 45 | withDenominator: (NSNumber*) denominator 46 | asSigned: (Boolean) signedFlag; 47 | - (NSString*) hexStringFromData : (NSData*) data; 48 | - (NSNumber*) numericFromHexString : (NSString *) hexstring; 49 | 50 | /* 51 | - (void) readExifMetaData : (NSData*) imgdata; 52 | - (void) spliceImageData : (NSData*) imgdata withExifData: (NSDictionary*) exifdata; 53 | - (void) locateExifMetaData : (NSData*) imgdata; 54 | - (NSString*) createExifAPP1 : (NSDictionary*) datadict; 55 | - (void) createExifDataString : (NSDictionary*) datadict; 56 | - (NSString*) createDataElement : (NSString*) element 57 | withElementData: (NSString*) data 58 | withExternalDataBlock: (NSDictionary*) memblock; 59 | - (NSString*) hexStringFromData : (NSData*) data; 60 | - (NSNumber*) numericFromHexString : (NSString *) hexstring; 61 | */ 62 | @end 63 | -------------------------------------------------------------------------------- /src/ios/UIImage+CropScaleOrientation.h: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | #import 21 | 22 | @interface UIImage (CropScaleOrientation) 23 | 24 | - (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize; 25 | - (UIImage*)imageCorrectedForCaptureOrientation; 26 | - (UIImage*)imageCorrectedForCaptureOrientation:(UIImageOrientation)imageOrientation; 27 | - (UIImage*)imageByScalingNotCroppingForSize:(CGSize)targetSize; 28 | 29 | @end -------------------------------------------------------------------------------- /src/ios/UIImage+CropScaleOrientation.m: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | #import "UIImage+CropScaleOrientation.h" 21 | 22 | @implementation UIImage (CropScaleOrientation) 23 | 24 | - (UIImage*)imageByScalingAndCroppingForSize:(CGSize)targetSize 25 | { 26 | UIImage* sourceImage = self; 27 | UIImage* newImage = nil; 28 | CGSize imageSize = sourceImage.size; 29 | CGFloat width = imageSize.width; 30 | CGFloat height = imageSize.height; 31 | CGFloat targetWidth = targetSize.width; 32 | CGFloat targetHeight = targetSize.height; 33 | CGFloat scaleFactor = 0.0; 34 | CGFloat scaledWidth = targetWidth; 35 | CGFloat scaledHeight = targetHeight; 36 | CGPoint thumbnailPoint = CGPointMake(0.0, 0.0); 37 | 38 | if (CGSizeEqualToSize(imageSize, targetSize) == NO) { 39 | CGFloat widthFactor = targetWidth / width; 40 | CGFloat heightFactor = targetHeight / height; 41 | 42 | if (widthFactor > heightFactor) { 43 | scaleFactor = widthFactor; // scale to fit height 44 | } else { 45 | scaleFactor = heightFactor; // scale to fit width 46 | } 47 | scaledWidth = width * scaleFactor; 48 | scaledHeight = height * scaleFactor; 49 | 50 | // center the image 51 | if (widthFactor > heightFactor) { 52 | thumbnailPoint.y = (targetHeight - scaledHeight) * 0.5; 53 | } else if (widthFactor < heightFactor) { 54 | thumbnailPoint.x = (targetWidth - scaledWidth) * 0.5; 55 | } 56 | } 57 | 58 | UIGraphicsBeginImageContext(targetSize); // this will crop 59 | 60 | CGRect thumbnailRect = CGRectZero; 61 | thumbnailRect.origin = thumbnailPoint; 62 | thumbnailRect.size.width = scaledWidth; 63 | thumbnailRect.size.height = scaledHeight; 64 | 65 | [sourceImage drawInRect:thumbnailRect]; 66 | 67 | newImage = UIGraphicsGetImageFromCurrentImageContext(); 68 | if (newImage == nil) { 69 | NSLog(@"could not scale image"); 70 | } 71 | 72 | // pop the context to get back to the default 73 | UIGraphicsEndImageContext(); 74 | return newImage; 75 | } 76 | 77 | - (UIImage*)imageCorrectedForCaptureOrientation:(UIImageOrientation)imageOrientation 78 | { 79 | float rotation_radians = 0; 80 | bool perpendicular = false; 81 | 82 | switch (imageOrientation) { 83 | case UIImageOrientationUp : 84 | rotation_radians = 0.0; 85 | break; 86 | 87 | case UIImageOrientationDown: 88 | rotation_radians = M_PI; // don't be scared of radians, if you're reading this, you're good at math 89 | break; 90 | 91 | case UIImageOrientationRight: 92 | rotation_radians = M_PI_2; 93 | perpendicular = true; 94 | break; 95 | 96 | case UIImageOrientationLeft: 97 | rotation_radians = -M_PI_2; 98 | perpendicular = true; 99 | break; 100 | 101 | default: 102 | break; 103 | } 104 | 105 | UIGraphicsBeginImageContext(CGSizeMake(self.size.width, self.size.height)); 106 | CGContextRef context = UIGraphicsGetCurrentContext(); 107 | 108 | // Rotate around the center point 109 | CGContextTranslateCTM(context, self.size.width / 2, self.size.height / 2); 110 | CGContextRotateCTM(context, rotation_radians); 111 | 112 | CGContextScaleCTM(context, 1.0, -1.0); 113 | float width = perpendicular ? self.size.height : self.size.width; 114 | float height = perpendicular ? self.size.width : self.size.height; 115 | CGContextDrawImage(context, CGRectMake(-width / 2, -height / 2, width, height), [self CGImage]); 116 | 117 | // Move the origin back since the rotation might've change it (if its 90 degrees) 118 | if (perpendicular) { 119 | CGContextTranslateCTM(context, -self.size.height / 2, -self.size.width / 2); 120 | } 121 | 122 | UIImage* newImage = UIGraphicsGetImageFromCurrentImageContext(); 123 | UIGraphicsEndImageContext(); 124 | return newImage; 125 | } 126 | 127 | - (UIImage*)imageCorrectedForCaptureOrientation 128 | { 129 | return [self imageCorrectedForCaptureOrientation:[self imageOrientation]]; 130 | } 131 | 132 | - (UIImage*)imageByScalingNotCroppingForSize:(CGSize)targetSize 133 | { 134 | UIImage* sourceImage = self; 135 | UIImage* newImage = nil; 136 | CGSize imageSize = sourceImage.size; 137 | CGFloat width = imageSize.width; 138 | CGFloat height = imageSize.height; 139 | CGFloat targetWidth = targetSize.width; 140 | CGFloat targetHeight = targetSize.height; 141 | CGFloat scaleFactor = 0.0; 142 | CGSize scaledSize = targetSize; 143 | 144 | if (CGSizeEqualToSize(imageSize, targetSize) == NO) { 145 | CGFloat widthFactor = targetWidth / width; 146 | CGFloat heightFactor = targetHeight / height; 147 | 148 | // opposite comparison to imageByScalingAndCroppingForSize in order to contain the image within the given bounds 149 | if (widthFactor > heightFactor) { 150 | scaleFactor = heightFactor; // scale to fit height 151 | } else { 152 | scaleFactor = widthFactor; // scale to fit width 153 | } 154 | scaledSize = CGSizeMake(MIN(width * scaleFactor, targetWidth), MIN(height * scaleFactor, targetHeight)); 155 | } 156 | 157 | // If the pixels are floats, it causes a white line in iOS8 and probably other versions too 158 | scaledSize.width = (int)scaledSize.width; 159 | scaledSize.height = (int)scaledSize.height; 160 | 161 | UIGraphicsBeginImageContext(scaledSize); // this will resize 162 | 163 | [sourceImage drawInRect:CGRectMake(0, 0, scaledSize.width, scaledSize.height)]; 164 | 165 | newImage = UIGraphicsGetImageFromCurrentImageContext(); 166 | if (newImage == nil) { 167 | NSLog(@"could not scale image"); 168 | } 169 | 170 | // pop the context to get back to the default 171 | UIGraphicsEndImageContext(); 172 | return newImage; 173 | } 174 | 175 | @end 176 | -------------------------------------------------------------------------------- /tests/ios/.gitignore: -------------------------------------------------------------------------------- 1 | node_modules -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest.xcworkspace/xcshareddata/CDVCameraTest.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 6BE9AD73-1B9F-4362-98D7-DC631BEC6185 9 | IDESourceControlProjectName 10 | CDVCameraTest 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 729B5706E7BAF4E9EE7AEE3C003A08107411AB7C 14 | github.com:shazron/cordova-plugin-camera.git 15 | 16 | IDESourceControlProjectPath 17 | tests/ios/CDVCameraTest.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 729B5706E7BAF4E9EE7AEE3C003A08107411AB7C 21 | ../../.. 22 | 23 | IDESourceControlProjectURL 24 | github.com:shazron/cordova-plugin-camera.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | 729B5706E7BAF4E9EE7AEE3C003A08107411AB7C 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 729B5706E7BAF4E9EE7AEE3C003A08107411AB7C 36 | IDESourceControlWCCName 37 | cordova-plugin-camera 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest.xcworkspace/xcshareddata/xcschemes/CordovaLib.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest/CDVCameraLibTests/CameraTest.m: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | #import 21 | #import 22 | #import "CDVCamera.h" 23 | #import "UIImage+CropScaleOrientation.h" 24 | #import 25 | 26 | 27 | @interface CameraTest : XCTestCase 28 | 29 | @property (nonatomic, strong) CDVCamera* plugin; 30 | 31 | @end 32 | 33 | @interface CDVCamera () 34 | 35 | // expose private interface 36 | - (NSData*)processImage:(UIImage*)image info:(NSDictionary*)info options:(CDVPictureOptions*)options; 37 | - (UIImage*)retrieveImage:(NSDictionary*)info options:(CDVPictureOptions*)options; 38 | - (CDVPluginResult*)resultForImage:(CDVPictureOptions*)options info:(NSDictionary*)info; 39 | - (CDVPluginResult*)resultForVideo:(NSDictionary*)info; 40 | 41 | @end 42 | 43 | @implementation CameraTest 44 | 45 | - (void)setUp { 46 | [super setUp]; 47 | // Put setup code here. This method is called before the invocation of each test method in the class. 48 | 49 | self.plugin = [[CDVCamera alloc] init]; 50 | } 51 | 52 | - (void)tearDown { 53 | // Put teardown code here. This method is called after the invocation of each test method in the class. 54 | [super tearDown]; 55 | } 56 | 57 | - (void) testPictureOptionsCreate 58 | { 59 | NSArray* args; 60 | CDVPictureOptions* options; 61 | NSDictionary* popoverOptions; 62 | 63 | // No arguments, check whether the defaults are set 64 | args = @[]; 65 | CDVInvokedUrlCommand* command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"]; 66 | 67 | options = [CDVPictureOptions createFromTakePictureArguments:command]; 68 | 69 | XCTAssertEqual([options.quality intValue], 50); 70 | XCTAssertEqual(options.destinationType, (int)DestinationTypeFileUri); 71 | XCTAssertEqual(options.sourceType, (int)UIImagePickerControllerSourceTypeCamera); 72 | XCTAssertEqual(options.targetSize.width, 0); 73 | XCTAssertEqual(options.targetSize.height, 0); 74 | XCTAssertEqual(options.encodingType, (int)EncodingTypeJPEG); 75 | XCTAssertEqual(options.mediaType, (int)MediaTypePicture); 76 | XCTAssertEqual(options.allowsEditing, NO); 77 | XCTAssertEqual(options.correctOrientation, NO); 78 | XCTAssertEqual(options.saveToPhotoAlbum, NO); 79 | XCTAssertEqualObjects(options.popoverOptions, nil); 80 | XCTAssertEqual(options.cameraDirection, (int)UIImagePickerControllerCameraDeviceRear); 81 | XCTAssertEqual(options.popoverSupported, NO); 82 | XCTAssertEqual(options.usesGeolocation, NO); 83 | 84 | // Set each argument, check whether they are set. different from defaults 85 | popoverOptions = @{ @"x" : @1, @"y" : @2, @"width" : @3, @"height" : @4, @"popoverWidth": @200, @"popoverHeight": @300 }; 86 | 87 | args = @[ 88 | @(49), 89 | @(DestinationTypeDataUrl), 90 | @(UIImagePickerControllerSourceTypePhotoLibrary), 91 | @(120), 92 | @(240), 93 | @(EncodingTypePNG), 94 | @(MediaTypeVideo), 95 | @YES, 96 | @YES, 97 | @YES, 98 | popoverOptions, 99 | @(UIImagePickerControllerCameraDeviceFront), 100 | ]; 101 | 102 | command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"]; 103 | options = [CDVPictureOptions createFromTakePictureArguments:command]; 104 | 105 | XCTAssertEqual([options.quality intValue], 49); 106 | XCTAssertEqual(options.destinationType, (int)DestinationTypeDataUrl); 107 | XCTAssertEqual(options.sourceType, (int)UIImagePickerControllerSourceTypePhotoLibrary); 108 | XCTAssertEqual(options.targetSize.width, 120); 109 | XCTAssertEqual(options.targetSize.height, 240); 110 | XCTAssertEqual(options.encodingType, (int)EncodingTypePNG); 111 | XCTAssertEqual(options.mediaType, (int)MediaTypeVideo); 112 | XCTAssertEqual(options.allowsEditing, YES); 113 | XCTAssertEqual(options.correctOrientation, YES); 114 | XCTAssertEqual(options.saveToPhotoAlbum, YES); 115 | XCTAssertEqualObjects(options.popoverOptions, popoverOptions); 116 | XCTAssertEqual(options.cameraDirection, (int)UIImagePickerControllerCameraDeviceFront); 117 | XCTAssertEqual(options.popoverSupported, NO); 118 | XCTAssertEqual(options.usesGeolocation, NO); 119 | } 120 | 121 | - (void) testCameraPickerCreate 122 | { 123 | NSDictionary* popoverOptions; 124 | NSArray* args; 125 | CDVPictureOptions* pictureOptions; 126 | CDVCameraPicker* picker; 127 | 128 | // Souce is Camera, and image type 129 | 130 | popoverOptions = @{ @"x" : @1, @"y" : @2, @"width" : @3, @"height" : @4, @"popoverWidth": @200, @"popoverHeight": @300 }; 131 | args = @[ 132 | @(49), 133 | @(DestinationTypeDataUrl), 134 | @(UIImagePickerControllerSourceTypeCamera), 135 | @(120), 136 | @(240), 137 | @(EncodingTypePNG), 138 | @(MediaTypeAll), 139 | @YES, 140 | @YES, 141 | @YES, 142 | popoverOptions, 143 | @(UIImagePickerControllerCameraDeviceFront), 144 | ]; 145 | 146 | CDVInvokedUrlCommand* command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"]; 147 | pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command]; 148 | 149 | if ([UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType]) { 150 | picker = [CDVCameraPicker createFromPictureOptions:pictureOptions]; 151 | 152 | XCTAssertEqualObjects(picker.pictureOptions, pictureOptions); 153 | 154 | XCTAssertEqual(picker.sourceType, pictureOptions.sourceType); 155 | XCTAssertEqual(picker.allowsEditing, pictureOptions.allowsEditing); 156 | XCTAssertEqualObjects(picker.mediaTypes, @[(NSString*)kUTTypeImage]); 157 | XCTAssertEqual(picker.cameraDevice, pictureOptions.cameraDirection); 158 | } 159 | 160 | // Souce is not Camera, and all media types 161 | 162 | args = @[ 163 | @(49), 164 | @(DestinationTypeDataUrl), 165 | @(UIImagePickerControllerSourceTypePhotoLibrary), 166 | @(120), 167 | @(240), 168 | @(EncodingTypePNG), 169 | @(MediaTypeAll), 170 | @YES, 171 | @YES, 172 | @YES, 173 | popoverOptions, 174 | @(UIImagePickerControllerCameraDeviceFront), 175 | ]; 176 | 177 | command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"]; 178 | pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command]; 179 | 180 | if ([UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType]) { 181 | picker = [CDVCameraPicker createFromPictureOptions:pictureOptions]; 182 | 183 | XCTAssertEqualObjects(picker.pictureOptions, pictureOptions); 184 | 185 | XCTAssertEqual(picker.sourceType, pictureOptions.sourceType); 186 | XCTAssertEqual(picker.allowsEditing, pictureOptions.allowsEditing); 187 | XCTAssertEqualObjects(picker.mediaTypes, [UIImagePickerController availableMediaTypesForSourceType:picker.sourceType]); 188 | } 189 | 190 | // Souce is not Camera, and either Image or Movie media type 191 | 192 | args = @[ 193 | @(49), 194 | @(DestinationTypeDataUrl), 195 | @(UIImagePickerControllerSourceTypePhotoLibrary), 196 | @(120), 197 | @(240), 198 | @(EncodingTypePNG), 199 | @(MediaTypeVideo), 200 | @YES, 201 | @YES, 202 | @YES, 203 | popoverOptions, 204 | @(UIImagePickerControllerCameraDeviceFront), 205 | ]; 206 | 207 | command = [[CDVInvokedUrlCommand alloc] initWithArguments:args callbackId:@"dummy" className:@"myclassname" methodName:@"mymethodname"]; 208 | pictureOptions = [CDVPictureOptions createFromTakePictureArguments:command]; 209 | 210 | if ([UIImagePickerController isSourceTypeAvailable:pictureOptions.sourceType]) { 211 | picker = [CDVCameraPicker createFromPictureOptions:pictureOptions]; 212 | 213 | XCTAssertEqualObjects(picker.pictureOptions, pictureOptions); 214 | 215 | XCTAssertEqual(picker.sourceType, pictureOptions.sourceType); 216 | XCTAssertEqual(picker.allowsEditing, pictureOptions.allowsEditing); 217 | XCTAssertEqualObjects(picker.mediaTypes, @[(NSString*)kUTTypeMovie]); 218 | } 219 | } 220 | 221 | - (UIImage*) createImage:(CGRect)rect orientation:(UIImageOrientation)imageOrientation { 222 | UIGraphicsBeginImageContext(rect.size); 223 | CGContextRef context = UIGraphicsGetCurrentContext(); 224 | 225 | CGContextSetFillColorWithColor(context, [[UIColor greenColor] CGColor]); 226 | CGContextFillRect(context, rect); 227 | 228 | CGImageRef result = CGBitmapContextCreateImage(UIGraphicsGetCurrentContext()); 229 | UIImage* image = [UIImage imageWithCGImage:result scale:1.0f orientation:imageOrientation]; 230 | 231 | UIGraphicsEndImageContext(); 232 | 233 | return image; 234 | } 235 | 236 | - (void) testImageScaleCropForSize { 237 | 238 | UIImage *sourceImagePortrait, *sourceImageLandscape, *targetImage; 239 | CGSize targetSize = CGSizeZero; 240 | 241 | sourceImagePortrait = [self createImage:CGRectMake(0, 0, 2448, 3264) orientation:UIImageOrientationUp]; 242 | sourceImageLandscape = [self createImage:CGRectMake(0, 0, 3264, 2448) orientation:UIImageOrientationUp]; 243 | 244 | // test 640x480 245 | 246 | targetSize = CGSizeMake(640, 480); 247 | 248 | targetImage = [sourceImagePortrait imageByScalingAndCroppingForSize:targetSize]; 249 | XCTAssertEqual(targetImage.size.width, targetSize.width); 250 | XCTAssertEqual(targetImage.size.height, targetSize.height); 251 | 252 | targetImage = [sourceImageLandscape imageByScalingAndCroppingForSize:targetSize]; 253 | XCTAssertEqual(targetImage.size.width, targetSize.width); 254 | XCTAssertEqual(targetImage.size.height, targetSize.height); 255 | 256 | 257 | // test 800x600 258 | 259 | targetSize = CGSizeMake(800, 600); 260 | 261 | targetImage = [sourceImagePortrait imageByScalingAndCroppingForSize:targetSize]; 262 | XCTAssertEqual(targetImage.size.width, targetSize.width); 263 | XCTAssertEqual(targetImage.size.height, targetSize.height); 264 | 265 | targetImage = [sourceImageLandscape imageByScalingAndCroppingForSize:targetSize]; 266 | XCTAssertEqual(targetImage.size.width, targetSize.width); 267 | XCTAssertEqual(targetImage.size.height, targetSize.height); 268 | 269 | // test 1024x768 270 | 271 | targetSize = CGSizeMake(1024, 768); 272 | 273 | targetImage = [sourceImagePortrait imageByScalingAndCroppingForSize:targetSize]; 274 | XCTAssertEqual(targetImage.size.width, targetSize.width); 275 | XCTAssertEqual(targetImage.size.height, targetSize.height); 276 | 277 | targetImage = [sourceImageLandscape imageByScalingAndCroppingForSize:targetSize]; 278 | XCTAssertEqual(targetImage.size.width, targetSize.width); 279 | XCTAssertEqual(targetImage.size.height, targetSize.height); 280 | } 281 | 282 | - (void) testImageScaleNoCropForSize { 283 | UIImage *sourceImagePortrait, *sourceImageLandscape, *targetImage; 284 | CGSize targetSize = CGSizeZero; 285 | 286 | sourceImagePortrait = [self createImage:CGRectMake(0, 0, 2448, 3264) orientation:UIImageOrientationUp]; 287 | sourceImageLandscape = [self createImage:CGRectMake(0, 0, 3264, 2448) orientation:UIImageOrientationUp]; 288 | 289 | // test 640x480 290 | 291 | targetSize = CGSizeMake(480, 640); 292 | 293 | targetImage = [sourceImagePortrait imageByScalingNotCroppingForSize:targetSize]; 294 | XCTAssertEqual(targetImage.size.width, targetSize.width); 295 | XCTAssertEqual(targetImage.size.height, targetSize.height); 296 | 297 | targetSize = CGSizeMake(640, 480); 298 | 299 | targetImage = [sourceImageLandscape imageByScalingNotCroppingForSize:targetSize]; 300 | XCTAssertEqual(targetImage.size.width, targetSize.width); 301 | XCTAssertEqual(targetImage.size.height, targetSize.height); 302 | 303 | 304 | // test 800x600 305 | 306 | targetSize = CGSizeMake(600, 800); 307 | 308 | targetImage = [sourceImagePortrait imageByScalingNotCroppingForSize:targetSize]; 309 | XCTAssertEqual(targetImage.size.width, targetSize.width); 310 | XCTAssertEqual(targetImage.size.height, targetSize.height); 311 | 312 | targetSize = CGSizeMake(800, 600); 313 | 314 | targetImage = [sourceImageLandscape imageByScalingNotCroppingForSize:targetSize]; 315 | XCTAssertEqual(targetImage.size.width, targetSize.width); 316 | XCTAssertEqual(targetImage.size.height, targetSize.height); 317 | 318 | // test 1024x768 319 | 320 | targetSize = CGSizeMake(768, 1024); 321 | 322 | targetImage = [sourceImagePortrait imageByScalingNotCroppingForSize:targetSize]; 323 | XCTAssertEqual(targetImage.size.width, targetSize.width); 324 | XCTAssertEqual(targetImage.size.height, targetSize.height); 325 | 326 | targetSize = CGSizeMake(1024, 768); 327 | 328 | targetImage = [sourceImageLandscape imageByScalingNotCroppingForSize:targetSize]; 329 | XCTAssertEqual(targetImage.size.width, targetSize.width); 330 | XCTAssertEqual(targetImage.size.height, targetSize.height); 331 | } 332 | 333 | - (void) testImageCorrectedForOrientation { 334 | UIImage *sourceImagePortrait, *sourceImageLandscape, *targetImage; 335 | CGSize targetSize = CGSizeZero; 336 | 337 | sourceImagePortrait = [self createImage:CGRectMake(0, 0, 2448, 3264) orientation:UIImageOrientationDown]; 338 | sourceImageLandscape = [self createImage:CGRectMake(0, 0, 3264, 2448) orientation:UIImageOrientationDown]; 339 | 340 | // PORTRAIT - image size should be unchanged 341 | 342 | targetSize = CGSizeMake(2448, 3264); 343 | 344 | targetImage = [sourceImagePortrait imageCorrectedForCaptureOrientation:UIImageOrientationUp]; 345 | XCTAssertEqual(targetImage.size.width, targetSize.width); 346 | XCTAssertEqual(targetImage.size.height, targetSize.height); 347 | XCTAssertEqual(targetImage.imageOrientation, UIImageOrientationUp); 348 | 349 | targetImage = [sourceImagePortrait imageCorrectedForCaptureOrientation:UIImageOrientationDown]; 350 | XCTAssertEqual(targetImage.size.width, targetSize.width); 351 | XCTAssertEqual(targetImage.size.height, targetSize.height); 352 | XCTAssertEqual(targetImage.imageOrientation, UIImageOrientationUp); 353 | 354 | targetImage = [sourceImagePortrait imageCorrectedForCaptureOrientation:UIImageOrientationRight]; 355 | XCTAssertEqual(targetImage.size.width, targetSize.width); 356 | XCTAssertEqual(targetImage.size.height, targetSize.height); 357 | XCTAssertEqual(targetImage.imageOrientation, UIImageOrientationUp); 358 | 359 | targetImage = [sourceImagePortrait imageCorrectedForCaptureOrientation:UIImageOrientationLeft]; 360 | XCTAssertEqual(targetImage.size.width, targetSize.width); 361 | XCTAssertEqual(targetImage.size.height, targetSize.height); 362 | XCTAssertEqual(targetImage.imageOrientation, UIImageOrientationUp); 363 | 364 | // LANDSCAPE - image size should be unchanged 365 | 366 | targetSize = CGSizeMake(3264, 2448); 367 | 368 | targetImage = [sourceImageLandscape imageCorrectedForCaptureOrientation:UIImageOrientationUp]; 369 | XCTAssertEqual(targetImage.size.width, targetSize.width); 370 | XCTAssertEqual(targetImage.size.height, targetSize.height); 371 | 372 | targetImage = [sourceImageLandscape imageCorrectedForCaptureOrientation:UIImageOrientationDown]; 373 | XCTAssertEqual(targetImage.size.width, targetSize.width); 374 | XCTAssertEqual(targetImage.size.height, targetSize.height); 375 | 376 | targetImage = [sourceImageLandscape imageCorrectedForCaptureOrientation:UIImageOrientationRight]; 377 | XCTAssertEqual(targetImage.size.width, targetSize.width); 378 | XCTAssertEqual(targetImage.size.height, targetSize.height); 379 | 380 | targetImage = [sourceImageLandscape imageCorrectedForCaptureOrientation:UIImageOrientationLeft]; 381 | XCTAssertEqual(targetImage.size.width, targetSize.width); 382 | XCTAssertEqual(targetImage.size.height, targetSize.height); 383 | } 384 | 385 | 386 | - (void) testRetrieveImage 387 | { 388 | CDVPictureOptions* pictureOptions = [[CDVPictureOptions alloc] init]; 389 | NSDictionary *infoDict1, *infoDict2; 390 | UIImage* resultImage; 391 | 392 | UIImage* originalImage = [self createImage:CGRectMake(0, 0, 1024, 768) orientation:UIImageOrientationDown]; 393 | UIImage* originalCorrectedForOrientation = [originalImage imageCorrectedForCaptureOrientation]; 394 | 395 | UIImage* editedImage = [self createImage:CGRectMake(0, 0, 800, 600) orientation:UIImageOrientationDown]; 396 | UIImage* scaledImageWithCrop = [originalImage imageByScalingAndCroppingForSize:CGSizeMake(640, 480)]; 397 | UIImage* scaledImageNoCrop = [originalImage imageByScalingNotCroppingForSize:CGSizeMake(640, 480)]; 398 | 399 | infoDict1 = @{ 400 | UIImagePickerControllerOriginalImage : originalImage 401 | }; 402 | 403 | infoDict2 = @{ 404 | UIImagePickerControllerOriginalImage : originalImage, 405 | UIImagePickerControllerEditedImage : editedImage 406 | }; 407 | 408 | // Original with no options 409 | 410 | pictureOptions.allowsEditing = YES; 411 | pictureOptions.targetSize = CGSizeZero; 412 | pictureOptions.cropToSize = NO; 413 | pictureOptions.correctOrientation = NO; 414 | 415 | resultImage = [self.plugin retrieveImage:infoDict1 options:pictureOptions]; 416 | XCTAssertEqualObjects(resultImage, originalImage); 417 | 418 | // Original with no options 419 | 420 | pictureOptions.allowsEditing = YES; 421 | pictureOptions.targetSize = CGSizeZero; 422 | pictureOptions.cropToSize = NO; 423 | pictureOptions.correctOrientation = NO; 424 | 425 | resultImage = [self.plugin retrieveImage:infoDict2 options:pictureOptions]; 426 | XCTAssertEqualObjects(resultImage, editedImage); 427 | 428 | // Original with corrected orientation 429 | 430 | pictureOptions.allowsEditing = YES; 431 | pictureOptions.targetSize = CGSizeZero; 432 | pictureOptions.cropToSize = NO; 433 | pictureOptions.correctOrientation = YES; 434 | 435 | resultImage = [self.plugin retrieveImage:infoDict1 options:pictureOptions]; 436 | XCTAssertNotEqual(resultImage.imageOrientation, originalImage.imageOrientation); 437 | XCTAssertEqual(resultImage.imageOrientation, originalCorrectedForOrientation.imageOrientation); 438 | XCTAssertEqual(resultImage.size.width, originalCorrectedForOrientation.size.width); 439 | XCTAssertEqual(resultImage.size.height, originalCorrectedForOrientation.size.height); 440 | 441 | // Original with targetSize, no crop 442 | 443 | pictureOptions.allowsEditing = YES; 444 | pictureOptions.targetSize = CGSizeMake(640, 480); 445 | pictureOptions.cropToSize = NO; 446 | pictureOptions.correctOrientation = NO; 447 | 448 | resultImage = [self.plugin retrieveImage:infoDict1 options:pictureOptions]; 449 | XCTAssertEqual(resultImage.size.width, scaledImageNoCrop.size.width); 450 | XCTAssertEqual(resultImage.size.height, scaledImageNoCrop.size.height); 451 | 452 | // Original with targetSize, plus crop 453 | 454 | pictureOptions.allowsEditing = YES; 455 | pictureOptions.targetSize = CGSizeMake(640, 480); 456 | pictureOptions.cropToSize = YES; 457 | pictureOptions.correctOrientation = NO; 458 | 459 | resultImage = [self.plugin retrieveImage:infoDict1 options:pictureOptions]; 460 | XCTAssertEqual(resultImage.size.width, scaledImageWithCrop.size.width); 461 | XCTAssertEqual(resultImage.size.height, scaledImageWithCrop.size.height); 462 | } 463 | 464 | - (void) testProcessImage 465 | { 466 | CDVPictureOptions* pictureOptions = [[CDVPictureOptions alloc] init]; 467 | NSData* resultData; 468 | 469 | UIImage* originalImage = [self createImage:CGRectMake(0, 0, 1024, 768) orientation:UIImageOrientationDown]; 470 | NSData* originalImageDataPNG = UIImagePNGRepresentation(originalImage); 471 | NSData* originalImageDataJPEG = UIImageJPEGRepresentation(originalImage, 1.0); 472 | 473 | // Original, PNG 474 | 475 | pictureOptions.allowsEditing = YES; 476 | pictureOptions.targetSize = CGSizeZero; 477 | pictureOptions.cropToSize = NO; 478 | pictureOptions.correctOrientation = NO; 479 | pictureOptions.encodingType = EncodingTypePNG; 480 | 481 | resultData = [self.plugin processImage:originalImage info:@{} options:pictureOptions]; 482 | XCTAssertEqualObjects([resultData base64EncodedStringWithOptions:0], [originalImageDataPNG base64EncodedStringWithOptions:0]); 483 | 484 | // Original, JPEG, full quality 485 | 486 | pictureOptions.allowsEditing = NO; 487 | pictureOptions.targetSize = CGSizeZero; 488 | pictureOptions.cropToSize = NO; 489 | pictureOptions.correctOrientation = NO; 490 | pictureOptions.encodingType = EncodingTypeJPEG; 491 | 492 | resultData = [self.plugin processImage:originalImage info:@{} options:pictureOptions]; 493 | XCTAssertEqualObjects([resultData base64EncodedStringWithOptions:0], [originalImageDataJPEG base64EncodedStringWithOptions:0]); 494 | 495 | // Original, JPEG, with quality value 496 | 497 | pictureOptions.allowsEditing = YES; 498 | pictureOptions.targetSize = CGSizeZero; 499 | pictureOptions.cropToSize = NO; 500 | pictureOptions.correctOrientation = NO; 501 | pictureOptions.encodingType = EncodingTypeJPEG; 502 | pictureOptions.quality = @(57); 503 | 504 | NSData* originalImageDataJPEGWithQuality = UIImageJPEGRepresentation(originalImage, [pictureOptions.quality floatValue]/ 100.f); 505 | resultData = [self.plugin processImage:originalImage info:@{} options:pictureOptions]; 506 | XCTAssertEqualObjects([resultData base64EncodedStringWithOptions:0], [originalImageDataJPEGWithQuality base64EncodedStringWithOptions:0]); 507 | 508 | // TODO: usesGeolocation is not tested 509 | } 510 | 511 | @end 512 | -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest/CDVCameraLibTests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 23 | 24 | 25 | CFBundleDevelopmentRegion 26 | en 27 | CFBundleExecutable 28 | $(EXECUTABLE_NAME) 29 | CFBundleIdentifier 30 | org.apache.cordova.$(PRODUCT_NAME:rfc1034identifier) 31 | CFBundleInfoDictionaryVersion 32 | 6.0 33 | CFBundleName 34 | $(PRODUCT_NAME) 35 | CFBundlePackageType 36 | BNDL 37 | CFBundleShortVersionString 38 | 1.0 39 | CFBundleSignature 40 | ???? 41 | CFBundleVersion 42 | 1 43 | 44 | 45 | -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 30486FEB1A40DC350065C233 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FEA1A40DC350065C233 /* UIKit.framework */; }; 11 | 30486FED1A40DC3B0065C233 /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FEC1A40DC3A0065C233 /* Foundation.framework */; }; 12 | 30486FF91A40DCC70065C233 /* CDVCamera.m in Sources */ = {isa = PBXBuildFile; fileRef = 30486FF31A40DCC70065C233 /* CDVCamera.m */; }; 13 | 30486FFA1A40DCC70065C233 /* CDVJpegHeaderWriter.m in Sources */ = {isa = PBXBuildFile; fileRef = 30486FF61A40DCC70065C233 /* CDVJpegHeaderWriter.m */; }; 14 | 30486FFB1A40DCC70065C233 /* UIImage+CropScaleOrientation.m in Sources */ = {isa = PBXBuildFile; fileRef = 30486FF81A40DCC70065C233 /* UIImage+CropScaleOrientation.m */; }; 15 | 304870011A40DD620065C233 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FFE1A40DD180065C233 /* CoreGraphics.framework */; }; 16 | 304870021A40DD860065C233 /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FFE1A40DD180065C233 /* CoreGraphics.framework */; }; 17 | 304870031A40DD8C0065C233 /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 30486FEA1A40DC350065C233 /* UIKit.framework */; }; 18 | 304870051A40DD9A0065C233 /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304870041A40DD9A0065C233 /* MobileCoreServices.framework */; }; 19 | 304870071A40DDAC0065C233 /* AssetsLibrary.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304870061A40DDAC0065C233 /* AssetsLibrary.framework */; }; 20 | 304870091A40DDB90065C233 /* CoreLocation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 304870081A40DDB90065C233 /* CoreLocation.framework */; }; 21 | 3048700B1A40DDF30065C233 /* ImageIO.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 3048700A1A40DDF30065C233 /* ImageIO.framework */; }; 22 | 308F59B11A4228730031A4D4 /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E9F519019DA0F8300DA31AC /* libCordova.a */; }; 23 | 7E9F51B119DA114400DA31AC /* CameraTest.m in Sources */ = {isa = PBXBuildFile; fileRef = 7E9F51B019DA114400DA31AC /* CameraTest.m */; }; 24 | 7E9F51B919DA1B1600DA31AC /* libCDVCameraLib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 7E9F519519DA102000DA31AC /* libCDVCameraLib.a */; }; 25 | /* End PBXBuildFile section */ 26 | 27 | /* Begin PBXContainerItemProxy section */ 28 | 30486FFC1A40DCE80065C233 /* PBXContainerItemProxy */ = { 29 | isa = PBXContainerItemProxy; 30 | containerPortal = 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */; 31 | proxyType = 1; 32 | remoteGlobalIDString = D2AAC07D0554694100DB518D; 33 | remoteInfo = CordovaLib; 34 | }; 35 | 7E9F518F19DA0F8300DA31AC /* PBXContainerItemProxy */ = { 36 | isa = PBXContainerItemProxy; 37 | containerPortal = 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */; 38 | proxyType = 2; 39 | remoteGlobalIDString = 68A32D7114102E1C006B237C; 40 | remoteInfo = CordovaLib; 41 | }; 42 | 7E9F51AC19DA10DE00DA31AC /* PBXContainerItemProxy */ = { 43 | isa = PBXContainerItemProxy; 44 | containerPortal = 7E9F517219DA09CE00DA31AC /* Project object */; 45 | proxyType = 1; 46 | remoteGlobalIDString = 7E9F519419DA102000DA31AC; 47 | remoteInfo = CDVCameraLib; 48 | }; 49 | /* End PBXContainerItemProxy section */ 50 | 51 | /* Begin PBXCopyFilesBuildPhase section */ 52 | 7E9F519319DA102000DA31AC /* CopyFiles */ = { 53 | isa = PBXCopyFilesBuildPhase; 54 | buildActionMask = 2147483647; 55 | dstPath = "include/$(PRODUCT_NAME)"; 56 | dstSubfolderSpec = 16; 57 | files = ( 58 | ); 59 | runOnlyForDeploymentPostprocessing = 0; 60 | }; 61 | /* End PBXCopyFilesBuildPhase section */ 62 | 63 | /* Begin PBXFileReference section */ 64 | 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; }; 65 | 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; }; 66 | 30486FF21A40DCC70065C233 /* CDVCamera.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVCamera.h; sourceTree = ""; }; 67 | 30486FF31A40DCC70065C233 /* CDVCamera.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVCamera.m; sourceTree = ""; }; 68 | 30486FF41A40DCC70065C233 /* CDVExif.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVExif.h; sourceTree = ""; }; 69 | 30486FF51A40DCC70065C233 /* CDVJpegHeaderWriter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CDVJpegHeaderWriter.h; sourceTree = ""; }; 70 | 30486FF61A40DCC70065C233 /* CDVJpegHeaderWriter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CDVJpegHeaderWriter.m; sourceTree = ""; }; 71 | 30486FF71A40DCC70065C233 /* UIImage+CropScaleOrientation.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "UIImage+CropScaleOrientation.h"; sourceTree = ""; }; 72 | 30486FF81A40DCC70065C233 /* UIImage+CropScaleOrientation.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIImage+CropScaleOrientation.m"; sourceTree = ""; }; 73 | 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; }; 74 | 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; }; 75 | 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; }; 76 | 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; }; 77 | 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; }; 78 | 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = "../node_modules/cordova-ios/CordovaLib/CordovaLib.xcodeproj"; sourceTree = ""; }; 79 | 7E9F519519DA102000DA31AC /* libCDVCameraLib.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCDVCameraLib.a; sourceTree = BUILT_PRODUCTS_DIR; }; 80 | 7E9F519F19DA102000DA31AC /* CDVCameraLibTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CDVCameraLibTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 81 | 7E9F51A219DA102000DA31AC /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 82 | 7E9F51B019DA114400DA31AC /* CameraTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CameraTest.m; sourceTree = ""; }; 83 | /* End PBXFileReference section */ 84 | 85 | /* Begin PBXFrameworksBuildPhase section */ 86 | 7E9F519219DA102000DA31AC /* Frameworks */ = { 87 | isa = PBXFrameworksBuildPhase; 88 | buildActionMask = 2147483647; 89 | files = ( 90 | 308F59B11A4228730031A4D4 /* libCordova.a in Frameworks */, 91 | 304870011A40DD620065C233 /* CoreGraphics.framework in Frameworks */, 92 | 30486FED1A40DC3B0065C233 /* Foundation.framework in Frameworks */, 93 | 30486FEB1A40DC350065C233 /* UIKit.framework in Frameworks */, 94 | ); 95 | runOnlyForDeploymentPostprocessing = 0; 96 | }; 97 | 7E9F519C19DA102000DA31AC /* Frameworks */ = { 98 | isa = PBXFrameworksBuildPhase; 99 | buildActionMask = 2147483647; 100 | files = ( 101 | 3048700B1A40DDF30065C233 /* ImageIO.framework in Frameworks */, 102 | 304870091A40DDB90065C233 /* CoreLocation.framework in Frameworks */, 103 | 304870071A40DDAC0065C233 /* AssetsLibrary.framework in Frameworks */, 104 | 304870051A40DD9A0065C233 /* MobileCoreServices.framework in Frameworks */, 105 | 304870031A40DD8C0065C233 /* UIKit.framework in Frameworks */, 106 | 304870021A40DD860065C233 /* CoreGraphics.framework in Frameworks */, 107 | 7E9F51B919DA1B1600DA31AC /* libCDVCameraLib.a in Frameworks */, 108 | ); 109 | runOnlyForDeploymentPostprocessing = 0; 110 | }; 111 | /* End PBXFrameworksBuildPhase section */ 112 | 113 | /* Begin PBXGroup section */ 114 | 30486FF11A40DCC70065C233 /* CDVCameraLib */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 30486FF21A40DCC70065C233 /* CDVCamera.h */, 118 | 30486FF31A40DCC70065C233 /* CDVCamera.m */, 119 | 30486FF41A40DCC70065C233 /* CDVExif.h */, 120 | 30486FF51A40DCC70065C233 /* CDVJpegHeaderWriter.h */, 121 | 30486FF61A40DCC70065C233 /* CDVJpegHeaderWriter.m */, 122 | 30486FF71A40DCC70065C233 /* UIImage+CropScaleOrientation.h */, 123 | 30486FF81A40DCC70065C233 /* UIImage+CropScaleOrientation.m */, 124 | ); 125 | name = CDVCameraLib; 126 | path = ../../../src/ios; 127 | sourceTree = ""; 128 | }; 129 | 308F59B01A4227A60031A4D4 /* Frameworks */ = { 130 | isa = PBXGroup; 131 | children = ( 132 | 3048700A1A40DDF30065C233 /* ImageIO.framework */, 133 | 304870081A40DDB90065C233 /* CoreLocation.framework */, 134 | 304870061A40DDAC0065C233 /* AssetsLibrary.framework */, 135 | 304870041A40DD9A0065C233 /* MobileCoreServices.framework */, 136 | 30486FFE1A40DD180065C233 /* CoreGraphics.framework */, 137 | 30486FEC1A40DC3A0065C233 /* Foundation.framework */, 138 | 30486FEA1A40DC350065C233 /* UIKit.framework */, 139 | ); 140 | name = Frameworks; 141 | sourceTree = ""; 142 | }; 143 | 7E9F517119DA09CE00DA31AC = { 144 | isa = PBXGroup; 145 | children = ( 146 | 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */, 147 | 308F59B01A4227A60031A4D4 /* Frameworks */, 148 | 30486FF11A40DCC70065C233 /* CDVCameraLib */, 149 | 7E9F51A019DA102000DA31AC /* CDVCameraLibTests */, 150 | 7E9F517D19DA0A0A00DA31AC /* Products */, 151 | ); 152 | sourceTree = ""; 153 | }; 154 | 7E9F517D19DA0A0A00DA31AC /* Products */ = { 155 | isa = PBXGroup; 156 | children = ( 157 | 7E9F519519DA102000DA31AC /* libCDVCameraLib.a */, 158 | 7E9F519F19DA102000DA31AC /* CDVCameraLibTests.xctest */, 159 | ); 160 | name = Products; 161 | sourceTree = ""; 162 | }; 163 | 7E9F518C19DA0F8300DA31AC /* Products */ = { 164 | isa = PBXGroup; 165 | children = ( 166 | 7E9F519019DA0F8300DA31AC /* libCordova.a */, 167 | ); 168 | name = Products; 169 | sourceTree = ""; 170 | }; 171 | 7E9F51A019DA102000DA31AC /* CDVCameraLibTests */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | 7E9F51A119DA102000DA31AC /* Supporting Files */, 175 | 7E9F51B019DA114400DA31AC /* CameraTest.m */, 176 | ); 177 | path = CDVCameraLibTests; 178 | sourceTree = ""; 179 | }; 180 | 7E9F51A119DA102000DA31AC /* Supporting Files */ = { 181 | isa = PBXGroup; 182 | children = ( 183 | 7E9F51A219DA102000DA31AC /* Info.plist */, 184 | ); 185 | name = "Supporting Files"; 186 | sourceTree = ""; 187 | }; 188 | /* End PBXGroup section */ 189 | 190 | /* Begin PBXNativeTarget section */ 191 | 7E9F519419DA102000DA31AC /* CDVCameraLib */ = { 192 | isa = PBXNativeTarget; 193 | buildConfigurationList = 7E9F51A319DA102000DA31AC /* Build configuration list for PBXNativeTarget "CDVCameraLib" */; 194 | buildPhases = ( 195 | 7E9F519119DA102000DA31AC /* Sources */, 196 | 7E9F519219DA102000DA31AC /* Frameworks */, 197 | 7E9F519319DA102000DA31AC /* CopyFiles */, 198 | ); 199 | buildRules = ( 200 | ); 201 | dependencies = ( 202 | 30486FFD1A40DCE80065C233 /* PBXTargetDependency */, 203 | ); 204 | name = CDVCameraLib; 205 | productName = CDVCameraLib; 206 | productReference = 7E9F519519DA102000DA31AC /* libCDVCameraLib.a */; 207 | productType = "com.apple.product-type.library.static"; 208 | }; 209 | 7E9F519E19DA102000DA31AC /* CDVCameraLibTests */ = { 210 | isa = PBXNativeTarget; 211 | buildConfigurationList = 7E9F51A619DA102000DA31AC /* Build configuration list for PBXNativeTarget "CDVCameraLibTests" */; 212 | buildPhases = ( 213 | 7E9F519B19DA102000DA31AC /* Sources */, 214 | 7E9F519C19DA102000DA31AC /* Frameworks */, 215 | 7E9F519D19DA102000DA31AC /* Resources */, 216 | ); 217 | buildRules = ( 218 | ); 219 | dependencies = ( 220 | 7E9F51AD19DA10DE00DA31AC /* PBXTargetDependency */, 221 | ); 222 | name = CDVCameraLibTests; 223 | productName = CDVCameraLibTests; 224 | productReference = 7E9F519F19DA102000DA31AC /* CDVCameraLibTests.xctest */; 225 | productType = "com.apple.product-type.bundle.unit-test"; 226 | }; 227 | /* End PBXNativeTarget section */ 228 | 229 | /* Begin PBXProject section */ 230 | 7E9F517219DA09CE00DA31AC /* Project object */ = { 231 | isa = PBXProject; 232 | attributes = { 233 | LastUpgradeCheck = 0610; 234 | TargetAttributes = { 235 | 7E9F519419DA102000DA31AC = { 236 | CreatedOnToolsVersion = 6.0; 237 | }; 238 | 7E9F519E19DA102000DA31AC = { 239 | CreatedOnToolsVersion = 6.0; 240 | }; 241 | }; 242 | }; 243 | buildConfigurationList = 7E9F517519DA09CE00DA31AC /* Build configuration list for PBXProject "CDVCameraTest" */; 244 | compatibilityVersion = "Xcode 3.2"; 245 | developmentRegion = English; 246 | hasScannedForEncodings = 0; 247 | knownRegions = ( 248 | en, 249 | ); 250 | mainGroup = 7E9F517119DA09CE00DA31AC; 251 | productRefGroup = 7E9F517D19DA0A0A00DA31AC /* Products */; 252 | projectDirPath = ""; 253 | projectReferences = ( 254 | { 255 | ProductGroup = 7E9F518C19DA0F8300DA31AC /* Products */; 256 | ProjectRef = 7E9F518B19DA0F8300DA31AC /* CordovaLib.xcodeproj */; 257 | }, 258 | ); 259 | projectRoot = ""; 260 | targets = ( 261 | 7E9F519419DA102000DA31AC /* CDVCameraLib */, 262 | 7E9F519E19DA102000DA31AC /* CDVCameraLibTests */, 263 | ); 264 | }; 265 | /* End PBXProject section */ 266 | 267 | /* Begin PBXReferenceProxy section */ 268 | 7E9F519019DA0F8300DA31AC /* libCordova.a */ = { 269 | isa = PBXReferenceProxy; 270 | fileType = archive.ar; 271 | path = libCordova.a; 272 | remoteRef = 7E9F518F19DA0F8300DA31AC /* PBXContainerItemProxy */; 273 | sourceTree = BUILT_PRODUCTS_DIR; 274 | }; 275 | /* End PBXReferenceProxy section */ 276 | 277 | /* Begin PBXResourcesBuildPhase section */ 278 | 7E9F519D19DA102000DA31AC /* Resources */ = { 279 | isa = PBXResourcesBuildPhase; 280 | buildActionMask = 2147483647; 281 | files = ( 282 | ); 283 | runOnlyForDeploymentPostprocessing = 0; 284 | }; 285 | /* End PBXResourcesBuildPhase section */ 286 | 287 | /* Begin PBXSourcesBuildPhase section */ 288 | 7E9F519119DA102000DA31AC /* Sources */ = { 289 | isa = PBXSourcesBuildPhase; 290 | buildActionMask = 2147483647; 291 | files = ( 292 | 30486FF91A40DCC70065C233 /* CDVCamera.m in Sources */, 293 | 30486FFB1A40DCC70065C233 /* UIImage+CropScaleOrientation.m in Sources */, 294 | 30486FFA1A40DCC70065C233 /* CDVJpegHeaderWriter.m in Sources */, 295 | ); 296 | runOnlyForDeploymentPostprocessing = 0; 297 | }; 298 | 7E9F519B19DA102000DA31AC /* Sources */ = { 299 | isa = PBXSourcesBuildPhase; 300 | buildActionMask = 2147483647; 301 | files = ( 302 | 7E9F51B119DA114400DA31AC /* CameraTest.m in Sources */, 303 | ); 304 | runOnlyForDeploymentPostprocessing = 0; 305 | }; 306 | /* End PBXSourcesBuildPhase section */ 307 | 308 | /* Begin PBXTargetDependency section */ 309 | 30486FFD1A40DCE80065C233 /* PBXTargetDependency */ = { 310 | isa = PBXTargetDependency; 311 | name = CordovaLib; 312 | targetProxy = 30486FFC1A40DCE80065C233 /* PBXContainerItemProxy */; 313 | }; 314 | 7E9F51AD19DA10DE00DA31AC /* PBXTargetDependency */ = { 315 | isa = PBXTargetDependency; 316 | target = 7E9F519419DA102000DA31AC /* CDVCameraLib */; 317 | targetProxy = 7E9F51AC19DA10DE00DA31AC /* PBXContainerItemProxy */; 318 | }; 319 | /* End PBXTargetDependency section */ 320 | 321 | /* Begin XCBuildConfiguration section */ 322 | 7E9F517619DA09CE00DA31AC /* Debug */ = { 323 | isa = XCBuildConfiguration; 324 | buildSettings = { 325 | ONLY_ACTIVE_ARCH = YES; 326 | }; 327 | name = Debug; 328 | }; 329 | 7E9F517719DA09CE00DA31AC /* Release */ = { 330 | isa = XCBuildConfiguration; 331 | buildSettings = { 332 | }; 333 | name = Release; 334 | }; 335 | 7E9F51A419DA102000DA31AC /* Debug */ = { 336 | isa = XCBuildConfiguration; 337 | buildSettings = { 338 | ALWAYS_SEARCH_USER_PATHS = NO; 339 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 340 | CLANG_CXX_LIBRARY = "libc++"; 341 | CLANG_ENABLE_MODULES = YES; 342 | CLANG_ENABLE_OBJC_ARC = YES; 343 | CLANG_WARN_BOOL_CONVERSION = YES; 344 | CLANG_WARN_CONSTANT_CONVERSION = YES; 345 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 346 | CLANG_WARN_EMPTY_BODY = YES; 347 | CLANG_WARN_ENUM_CONVERSION = YES; 348 | CLANG_WARN_INT_CONVERSION = YES; 349 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 350 | CLANG_WARN_UNREACHABLE_CODE = YES; 351 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 352 | COPY_PHASE_STRIP = NO; 353 | ENABLE_STRICT_OBJC_MSGSEND = YES; 354 | GCC_C_LANGUAGE_STANDARD = gnu99; 355 | GCC_DYNAMIC_NO_PIC = NO; 356 | GCC_OPTIMIZATION_LEVEL = 0; 357 | GCC_PREPROCESSOR_DEFINITIONS = ( 358 | "DEBUG=1", 359 | "$(inherited)", 360 | ); 361 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 362 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 363 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 364 | GCC_WARN_UNDECLARED_SELECTOR = YES; 365 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 366 | GCC_WARN_UNUSED_FUNCTION = YES; 367 | GCC_WARN_UNUSED_VARIABLE = YES; 368 | HEADER_SEARCH_PATHS = ( 369 | "$(inherited)", 370 | "\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"", 371 | "\"$(OBJROOT)/UninstalledProducts/include\"", 372 | "\"$(BUILT_PRODUCTS_DIR)\"", 373 | ); 374 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 375 | MTL_ENABLE_DEBUG_INFO = YES; 376 | ONLY_ACTIVE_ARCH = YES; 377 | OTHER_LDFLAGS = "-ObjC"; 378 | PRODUCT_NAME = "$(TARGET_NAME)"; 379 | SDKROOT = iphoneos; 380 | SKIP_INSTALL = YES; 381 | }; 382 | name = Debug; 383 | }; 384 | 7E9F51A519DA102000DA31AC /* Release */ = { 385 | isa = XCBuildConfiguration; 386 | buildSettings = { 387 | ALWAYS_SEARCH_USER_PATHS = NO; 388 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 389 | CLANG_CXX_LIBRARY = "libc++"; 390 | CLANG_ENABLE_MODULES = YES; 391 | CLANG_ENABLE_OBJC_ARC = YES; 392 | CLANG_WARN_BOOL_CONVERSION = YES; 393 | CLANG_WARN_CONSTANT_CONVERSION = YES; 394 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 395 | CLANG_WARN_EMPTY_BODY = YES; 396 | CLANG_WARN_ENUM_CONVERSION = YES; 397 | CLANG_WARN_INT_CONVERSION = YES; 398 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 399 | CLANG_WARN_UNREACHABLE_CODE = YES; 400 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 401 | COPY_PHASE_STRIP = YES; 402 | ENABLE_NS_ASSERTIONS = NO; 403 | ENABLE_STRICT_OBJC_MSGSEND = YES; 404 | GCC_C_LANGUAGE_STANDARD = gnu99; 405 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 406 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 407 | GCC_WARN_UNDECLARED_SELECTOR = YES; 408 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 409 | GCC_WARN_UNUSED_FUNCTION = YES; 410 | GCC_WARN_UNUSED_VARIABLE = YES; 411 | HEADER_SEARCH_PATHS = ( 412 | "$(inherited)", 413 | "\"$(TARGET_BUILD_DIR)/usr/local/lib/include\"", 414 | "\n\"$(OBJROOT)/UninstalledProducts/include\"\n\"$(BUILT_PRODUCTS_DIR)\"", 415 | ); 416 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 417 | MTL_ENABLE_DEBUG_INFO = NO; 418 | OTHER_LDFLAGS = "-ObjC"; 419 | PRODUCT_NAME = "$(TARGET_NAME)"; 420 | SDKROOT = iphoneos; 421 | SKIP_INSTALL = YES; 422 | VALIDATE_PRODUCT = YES; 423 | }; 424 | name = Release; 425 | }; 426 | 7E9F51A719DA102000DA31AC /* Debug */ = { 427 | isa = XCBuildConfiguration; 428 | buildSettings = { 429 | ALWAYS_SEARCH_USER_PATHS = NO; 430 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 431 | CLANG_CXX_LIBRARY = "libc++"; 432 | CLANG_ENABLE_MODULES = YES; 433 | CLANG_ENABLE_OBJC_ARC = YES; 434 | CLANG_WARN_BOOL_CONVERSION = YES; 435 | CLANG_WARN_CONSTANT_CONVERSION = YES; 436 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 437 | CLANG_WARN_EMPTY_BODY = YES; 438 | CLANG_WARN_ENUM_CONVERSION = YES; 439 | CLANG_WARN_INT_CONVERSION = YES; 440 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 441 | CLANG_WARN_UNREACHABLE_CODE = YES; 442 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 443 | COPY_PHASE_STRIP = NO; 444 | ENABLE_STRICT_OBJC_MSGSEND = YES; 445 | FRAMEWORK_SEARCH_PATHS = ( 446 | "$(SDKROOT)/Developer/Library/Frameworks", 447 | "$(inherited)", 448 | ); 449 | GCC_C_LANGUAGE_STANDARD = gnu99; 450 | GCC_DYNAMIC_NO_PIC = NO; 451 | GCC_OPTIMIZATION_LEVEL = 0; 452 | GCC_PREPROCESSOR_DEFINITIONS = ( 453 | "DEBUG=1", 454 | "$(inherited)", 455 | ); 456 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 457 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 458 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 459 | GCC_WARN_UNDECLARED_SELECTOR = YES; 460 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 461 | GCC_WARN_UNUSED_FUNCTION = YES; 462 | GCC_WARN_UNUSED_VARIABLE = YES; 463 | INFOPLIST_FILE = CDVCameraLibTests/Info.plist; 464 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 465 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 466 | MTL_ENABLE_DEBUG_INFO = YES; 467 | ONLY_ACTIVE_ARCH = YES; 468 | OTHER_LDFLAGS = ( 469 | "$(inherited)", 470 | "-framework", 471 | XCTest, 472 | "-all_load", 473 | "-ObjC", 474 | ); 475 | PRODUCT_NAME = "$(TARGET_NAME)"; 476 | SDKROOT = iphoneos; 477 | }; 478 | name = Debug; 479 | }; 480 | 7E9F51A819DA102000DA31AC /* Release */ = { 481 | isa = XCBuildConfiguration; 482 | buildSettings = { 483 | ALWAYS_SEARCH_USER_PATHS = NO; 484 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 485 | CLANG_CXX_LIBRARY = "libc++"; 486 | CLANG_ENABLE_MODULES = YES; 487 | CLANG_ENABLE_OBJC_ARC = YES; 488 | CLANG_WARN_BOOL_CONVERSION = YES; 489 | CLANG_WARN_CONSTANT_CONVERSION = YES; 490 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 491 | CLANG_WARN_EMPTY_BODY = YES; 492 | CLANG_WARN_ENUM_CONVERSION = YES; 493 | CLANG_WARN_INT_CONVERSION = YES; 494 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 495 | CLANG_WARN_UNREACHABLE_CODE = YES; 496 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 497 | COPY_PHASE_STRIP = YES; 498 | ENABLE_NS_ASSERTIONS = NO; 499 | ENABLE_STRICT_OBJC_MSGSEND = YES; 500 | FRAMEWORK_SEARCH_PATHS = ( 501 | "$(SDKROOT)/Developer/Library/Frameworks", 502 | "$(inherited)", 503 | ); 504 | GCC_C_LANGUAGE_STANDARD = gnu99; 505 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 506 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 507 | GCC_WARN_UNDECLARED_SELECTOR = YES; 508 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 509 | GCC_WARN_UNUSED_FUNCTION = YES; 510 | GCC_WARN_UNUSED_VARIABLE = YES; 511 | INFOPLIST_FILE = CDVCameraLibTests/Info.plist; 512 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 513 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 514 | MTL_ENABLE_DEBUG_INFO = NO; 515 | OTHER_LDFLAGS = ( 516 | "$(inherited)", 517 | "-framework", 518 | XCTest, 519 | "-all_load", 520 | "-ObjC", 521 | ); 522 | PRODUCT_NAME = "$(TARGET_NAME)"; 523 | SDKROOT = iphoneos; 524 | VALIDATE_PRODUCT = YES; 525 | }; 526 | name = Release; 527 | }; 528 | /* End XCBuildConfiguration section */ 529 | 530 | /* Begin XCConfigurationList section */ 531 | 7E9F517519DA09CE00DA31AC /* Build configuration list for PBXProject "CDVCameraTest" */ = { 532 | isa = XCConfigurationList; 533 | buildConfigurations = ( 534 | 7E9F517619DA09CE00DA31AC /* Debug */, 535 | 7E9F517719DA09CE00DA31AC /* Release */, 536 | ); 537 | defaultConfigurationIsVisible = 0; 538 | defaultConfigurationName = Release; 539 | }; 540 | 7E9F51A319DA102000DA31AC /* Build configuration list for PBXNativeTarget "CDVCameraLib" */ = { 541 | isa = XCConfigurationList; 542 | buildConfigurations = ( 543 | 7E9F51A419DA102000DA31AC /* Debug */, 544 | 7E9F51A519DA102000DA31AC /* Release */, 545 | ); 546 | defaultConfigurationIsVisible = 0; 547 | defaultConfigurationName = Release; 548 | }; 549 | 7E9F51A619DA102000DA31AC /* Build configuration list for PBXNativeTarget "CDVCameraLibTests" */ = { 550 | isa = XCConfigurationList; 551 | buildConfigurations = ( 552 | 7E9F51A719DA102000DA31AC /* Debug */, 553 | 7E9F51A819DA102000DA31AC /* Release */, 554 | ); 555 | defaultConfigurationIsVisible = 0; 556 | defaultConfigurationName = Release; 557 | }; 558 | /* End XCConfigurationList section */ 559 | }; 560 | rootObject = 7E9F517219DA09CE00DA31AC /* Project object */; 561 | } 562 | -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj/project.xcworkspace/xcshareddata/CDVCameraTest.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 6BE9AD73-1B9F-4362-98D7-DC631BEC6185 9 | IDESourceControlProjectName 10 | CDVCameraTest 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | BEF5A5D0FF64801E558286389440357A9233D7DB 14 | https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git 15 | 16 | IDESourceControlProjectPath 17 | tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | BEF5A5D0FF64801E558286389440357A9233D7DB 21 | ../../../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://git-wip-us.apache.org/repos/asf/cordova-plugin-camera.git 25 | IDESourceControlProjectVersion 26 | 111 27 | IDESourceControlProjectWCCIdentifier 28 | BEF5A5D0FF64801E558286389440357A9233D7DB 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | BEF5A5D0FF64801E558286389440357A9233D7DB 36 | IDESourceControlWCCName 37 | cordova-plugin-camera 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj/xcshareddata/xcschemes/CDVCameraLib.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 42 | 43 | 49 | 50 | 51 | 52 | 53 | 54 | 60 | 61 | 67 | 68 | 69 | 70 | 72 | 73 | 76 | 77 | 78 | -------------------------------------------------------------------------------- /tests/ios/CDVCameraTest/CDVCameraTest.xcodeproj/xcshareddata/xcschemes/CDVCameraLibTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /tests/ios/README.md: -------------------------------------------------------------------------------- 1 | 19 | 20 | # iOS Tests for CDVCamera 21 | 22 | You need to install `node.js` to pull in `cordova-ios`. 23 | 24 | First install cordova-ios: 25 | 26 | npm install 27 | 28 | ... in the current folder. 29 | 30 | 31 | # Testing from Xcode 32 | 33 | 1. Launch the `CDVCameraTest.xcworkspace` file. 34 | 2. Choose "CDVCameraLibTests" from the scheme drop-down menu 35 | 3. Click and hold on the `Play` button, and choose the `Wrench` icon to run the tests 36 | 37 | 38 | # Testing from the command line 39 | 40 | npm test 41 | -------------------------------------------------------------------------------- /tests/ios/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cordova-plugin-camera-test-ios", 3 | "version": "1.0.0", 4 | "description": "iOS Unit Tests for Camera Plugin", 5 | "author": "Apache Software Foundation", 6 | "license": "Apache Version 2.0", 7 | "dependencies": { 8 | "cordova-ios": "*" 9 | }, 10 | "scripts": { 11 | "test": "xcodebuild -scheme CordovaLib && xcodebuild test -scheme CDVCameraLibTests -destination 'platform=iOS Simulator,name=iPhone 5s'" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cordova-plugin-camera-tests", 3 | "version": "8.0.1-dev", 4 | "lockfileVersion": 3, 5 | "requires": true, 6 | "packages": { 7 | "": { 8 | "name": "cordova-plugin-camera-tests", 9 | "version": "8.0.1-dev", 10 | "license": "Apache-2.0" 11 | } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /tests/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cordova-plugin-camera-tests", 3 | "version": "8.0.1-dev", 4 | "description": "", 5 | "cordova": { 6 | "id": "cordova-plugin-camera-tests", 7 | "platforms": [] 8 | }, 9 | "keywords": [ 10 | "ecosystem:cordova" 11 | ], 12 | "author": "", 13 | "license": "Apache-2.0" 14 | } 15 | -------------------------------------------------------------------------------- /tests/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 20 | 21 | 26 | Cordova Camera Plugin Tests 27 | Apache 2.0 28 | 29 | 30 | 31 | 32 | -------------------------------------------------------------------------------- /tests/tests.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on an 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | * KIND, either express or implied. See the License for the 17 | * specific language governing permissions and limitations 18 | * under the License. 19 | * 20 | */ 21 | 22 | /* globals Camera, resolveLocalFileSystemURL, FileEntry, CameraPopoverOptions, LocalFileSystem */ 23 | /* eslint-env jasmine */ 24 | 25 | exports.defineAutoTests = function () { 26 | describe('Camera (navigator.camera)', function () { 27 | it('should exist', function () { 28 | expect(navigator.camera).toBeDefined(); 29 | }); 30 | 31 | it('should contain a getPicture function', function () { 32 | expect(navigator.camera.getPicture).toBeDefined(); 33 | expect(typeof navigator.camera.getPicture === 'function').toBe(true); 34 | }); 35 | }); 36 | 37 | describe('Camera Constants (window.Camera + navigator.camera)', function () { 38 | it('camera.spec.1 window.Camera should exist', function () { 39 | expect(window.Camera).toBeDefined(); 40 | }); 41 | 42 | it('camera.spec.2 should contain three DestinationType constants', function () { 43 | expect(Camera.DestinationType.DATA_URL).toBe(0); 44 | expect(Camera.DestinationType.FILE_URI).toBe(1); 45 | expect(navigator.camera.DestinationType.DATA_URL).toBe(0); 46 | expect(navigator.camera.DestinationType.FILE_URI).toBe(1); 47 | }); 48 | 49 | it('camera.spec.3 should contain two EncodingType constants', function () { 50 | expect(Camera.EncodingType.JPEG).toBe(0); 51 | expect(Camera.EncodingType.PNG).toBe(1); 52 | expect(navigator.camera.EncodingType.JPEG).toBe(0); 53 | expect(navigator.camera.EncodingType.PNG).toBe(1); 54 | }); 55 | 56 | it('camera.spec.4 should contain three MediaType constants', function () { 57 | expect(Camera.MediaType.PICTURE).toBe(0); 58 | expect(Camera.MediaType.VIDEO).toBe(1); 59 | expect(Camera.MediaType.ALLMEDIA).toBe(2); 60 | expect(navigator.camera.MediaType.PICTURE).toBe(0); 61 | expect(navigator.camera.MediaType.VIDEO).toBe(1); 62 | expect(navigator.camera.MediaType.ALLMEDIA).toBe(2); 63 | }); 64 | 65 | it('camera.spec.5 should contain three PictureSourceType constants', function () { 66 | expect(Camera.PictureSourceType.PHOTOLIBRARY).toBe(0); 67 | expect(Camera.PictureSourceType.CAMERA).toBe(1); 68 | expect(Camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2); 69 | expect(navigator.camera.PictureSourceType.PHOTOLIBRARY).toBe(0); 70 | expect(navigator.camera.PictureSourceType.CAMERA).toBe(1); 71 | expect(navigator.camera.PictureSourceType.SAVEDPHOTOALBUM).toBe(2); 72 | }); 73 | }); 74 | }; 75 | 76 | /******************************************************************************/ 77 | /******************************************************************************/ 78 | /******************************************************************************/ 79 | 80 | exports.defineManualTests = function (contentEl, createActionButton) { 81 | let pictureUrl = null; 82 | let fileObj = null; 83 | let fileEntry = null; 84 | const pageStartTime = +new Date(); 85 | 86 | // default camera options 87 | const camQualityDefault = ['50', 50]; 88 | const camDestinationTypeDefault = ['FILE_URI', 1]; 89 | const camPictureSourceTypeDefault = ['CAMERA', 1]; 90 | const camAllowEditDefault = ['allowEdit', false]; 91 | const camEncodingTypeDefault = ['JPEG', 0]; 92 | const camMediaTypeDefault = ['mediaType', 0]; 93 | const camCorrectOrientationDefault = ['correctOrientation', false]; 94 | const camSaveToPhotoAlbumDefault = ['saveToPhotoAlbum', true]; 95 | 96 | function log (value) { 97 | console.log(value); 98 | document.getElementById('camera_status').textContent += (new Date() - pageStartTime) / 1000 + ': ' + value + '\n'; 99 | } 100 | 101 | function clearStatus () { 102 | document.getElementById('camera_status').innerHTML = ''; 103 | document.getElementById('camera_image').src = 'about:blank'; 104 | const canvas = document.getElementById('canvas'); 105 | canvas.width = canvas.height = 1; 106 | pictureUrl = null; 107 | fileObj = null; 108 | fileEntry = null; 109 | } 110 | 111 | function setPicture (url, callback) { 112 | try { 113 | window.atob(url); 114 | // if we got here it is a base64 string (DATA_URL) 115 | url = 'data:image/jpeg;base64,' + url; 116 | } catch (e) { 117 | // not DATA_URL 118 | } 119 | log('URL: "' + url.slice(0, 90) + '"'); 120 | 121 | pictureUrl = url; 122 | const img = document.getElementById('camera_image'); 123 | const startTime = new Date(); 124 | img.src = url; 125 | img.onload = function () { 126 | log('Img size: ' + img.naturalWidth + 'x' + img.naturalHeight); 127 | log('Image tag load time: ' + (new Date() - startTime)); 128 | if (callback) { 129 | callback(); 130 | } 131 | }; 132 | } 133 | 134 | function onGetPictureError (e) { 135 | log('Error getting picture: ' + (e.code || e)); 136 | } 137 | 138 | function getPictureWin (data) { 139 | setPicture(data); 140 | // TODO: Fix resolveLocalFileSystemURI to work with native-uri. 141 | if (pictureUrl.indexOf('file:') === 0 || pictureUrl.indexOf('content:') === 0) { 142 | resolveLocalFileSystemURL(data, function (e) { 143 | fileEntry = e; 144 | logCallback('resolveLocalFileSystemURL()', true)(e.toURL()); 145 | readFile(); 146 | }, logCallback('resolveLocalFileSystemURL()', false)); 147 | } else if (pictureUrl.indexOf('data:image/jpeg;base64') === 0) { 148 | // do nothing 149 | } else { 150 | const path = pictureUrl.replace(/^file:\/\/(localhost)?/, '').replace(/%20/g, ' '); 151 | fileEntry = new FileEntry('image_name.png', path); 152 | } 153 | } 154 | 155 | function getPicture () { 156 | clearStatus(); 157 | const options = extractOptions(); 158 | log('Getting picture with options: ' + JSON.stringify(options)); 159 | const popoverHandle = navigator.camera.getPicture(getPictureWin, onGetPictureError, options); 160 | 161 | // Reposition the popover if the orientation changes. 162 | window.onorientationchange = function () { 163 | const newPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, 0, 300, 400); 164 | popoverHandle.setPosition(newPopoverOptions); 165 | }; 166 | } 167 | 168 | function logCallback (apiName, success) { 169 | return function () { 170 | log('Call to ' + apiName + (success ? ' success: ' : ' failed: ') + JSON.stringify([].slice.call(arguments))); 171 | }; 172 | } 173 | 174 | /** 175 | * Select image from library 176 | * This calls FileEntry.getMetadata, FileEntry.setMetadata, FileEntry.getParent, FileEntry.file, and FileReader.readAsDataURL. 177 | */ 178 | function readFile () { 179 | function onFileReadAsDataURL (evt) { 180 | const img = document.getElementById('camera_image'); 181 | img.style.visibility = 'visible'; 182 | img.style.display = 'block'; 183 | img.src = evt.target.result; 184 | log('FileReader.readAsDataURL success'); 185 | } 186 | 187 | function onFileReceived (file) { 188 | log('Got file: ' + JSON.stringify(file)); 189 | fileObj = file; 190 | /* eslint-disable no-undef */ 191 | const reader = new FileReader(); 192 | /* eslint-enable no-undef */ 193 | reader.onload = function () { 194 | log('FileReader.readAsDataURL() - length = ' + reader.result.length); 195 | }; 196 | reader.onerror = logCallback('FileReader.readAsDataURL', false); 197 | reader.onloadend = onFileReadAsDataURL; 198 | reader.readAsDataURL(file); 199 | } 200 | 201 | // Test out onFileReceived when the file object was set via a native elements. 202 | if (fileObj) { 203 | onFileReceived(fileObj); 204 | } else { 205 | fileEntry.file(onFileReceived, logCallback('FileEntry.file', false)); 206 | } 207 | } 208 | 209 | function getFileInfo () { 210 | // Test FileEntry API here. 211 | fileEntry.getMetadata(logCallback('FileEntry.getMetadata', true), logCallback('FileEntry.getMetadata', false)); 212 | fileEntry.setMetadata(logCallback('FileEntry.setMetadata', true), logCallback('FileEntry.setMetadata', false), { 'com.apple.MobileBackup': 1 }); 213 | fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false)); 214 | fileEntry.getParent(logCallback('FileEntry.getParent', true), logCallback('FileEntry.getParent', false)); 215 | } 216 | 217 | /** 218 | * Copy image from library 219 | * This calls FileEntry.copyTo and FileEntry.moveTo. 220 | */ 221 | function copyImage () { 222 | const onFileSystemReceived = function (fileSystem) { 223 | const destDirEntry = fileSystem.root; 224 | const origName = fileEntry.name; 225 | 226 | // Test FileEntry API here. 227 | fileEntry.copyTo(destDirEntry, 'copied_file.png', logCallback('FileEntry.copyTo', true), logCallback('FileEntry.copyTo', false)); 228 | fileEntry.moveTo(destDirEntry, 'moved_file.png', logCallback('FileEntry.moveTo', true), logCallback('FileEntry.moveTo', false)); 229 | 230 | // cleanup 231 | // rename moved file back to original name so other tests can reference image 232 | resolveLocalFileSystemURL(destDirEntry.nativeURL + 'moved_file.png', function (fileEntry) { 233 | fileEntry.moveTo(destDirEntry, origName, logCallback('FileEntry.moveTo', true), logCallback('FileEntry.moveTo', false)); 234 | console.log('Cleanup: successfully renamed file back to original name'); 235 | }, function () { 236 | console.log('Cleanup: failed to rename file back to original name'); 237 | }); 238 | 239 | // remove copied file 240 | resolveLocalFileSystemURL(destDirEntry.nativeURL + 'copied_file.png', function (fileEntry) { 241 | fileEntry.remove(logCallback('FileEntry.remove', true), logCallback('FileEntry.remove', false)); 242 | console.log('Cleanup: successfully removed copied file'); 243 | }, function () { 244 | console.log('Cleanup: failed to remove copied file'); 245 | }); 246 | }; 247 | 248 | window.requestFileSystem(LocalFileSystem.TEMPORARY, 0, onFileSystemReceived, null); 249 | } 250 | 251 | /** 252 | * Write image to library 253 | * This calls FileEntry.createWriter, FileWriter.write, and FileWriter.truncate. 254 | */ 255 | function writeImage () { 256 | const onFileWriterReceived = function (fileWriter) { 257 | fileWriter.onwrite = logCallback('FileWriter.write', true); 258 | fileWriter.onerror = logCallback('FileWriter.write', false); 259 | fileWriter.write('some text!'); 260 | }; 261 | 262 | const onFileTruncateWriterReceived = function (fileWriter) { 263 | fileWriter.onwrite = logCallback('FileWriter.truncate', true); 264 | fileWriter.onerror = logCallback('FileWriter.truncate', false); 265 | fileWriter.truncate(10); 266 | }; 267 | 268 | fileEntry.createWriter(onFileWriterReceived, logCallback('FileEntry.createWriter', false)); 269 | fileEntry.createWriter(onFileTruncateWriterReceived, null); 270 | } 271 | 272 | function displayImageUsingCanvas () { 273 | const canvas = document.getElementById('canvas'); 274 | const img = document.getElementById('camera_image'); 275 | let w = img.width; 276 | let h = img.height; 277 | h = 100 / w * h; 278 | w = 100; 279 | canvas.width = w; 280 | canvas.height = h; 281 | const context = canvas.getContext('2d'); 282 | context.drawImage(img, 0, 0, w, h); 283 | } 284 | 285 | /** 286 | * Remove image from library 287 | * This calls FileEntry.remove. 288 | */ 289 | function removeImage () { 290 | fileEntry.remove(logCallback('FileEntry.remove', true), logCallback('FileEntry.remove', false)); 291 | } 292 | 293 | function testInputTag (inputEl) { 294 | clearStatus(); 295 | // iOS 6 likes to dead-lock in the onchange context if you 296 | // do any alerts or try to remote-debug. 297 | window.setTimeout(function () { 298 | testNativeFile2(inputEl); 299 | }, 0); 300 | } 301 | 302 | function testNativeFile2 (inputEl) { 303 | /* eslint-disable no-undef */ 304 | if (!inputEl.value) { 305 | alert('No file selected.'); 306 | return; 307 | } 308 | fileObj = inputEl.files[0]; 309 | if (!fileObj) { 310 | alert('Got value but no file.'); 311 | return; 312 | } 313 | /* eslint-enable no-undef */ 314 | const URLApi = window.URL || window.webkitURL; 315 | if (URLApi) { 316 | const blobURL = URLApi.createObjectURL(fileObj); 317 | if (blobURL) { 318 | setPicture(blobURL, function () { 319 | URLApi.revokeObjectURL(blobURL); 320 | }); 321 | } else { 322 | log('URL.createObjectURL returned null'); 323 | } 324 | } else { 325 | log('URL.createObjectURL() not supported.'); 326 | } 327 | } 328 | 329 | function extractOptions () { 330 | const els = document.querySelectorAll('#image-options select'); 331 | const ret = {}; 332 | /* eslint-disable no-cond-assign */ 333 | for (let i = 0, el; el = els[i]; ++i) { 334 | let value = el.value; 335 | if (value === '') continue; 336 | value = +value; 337 | 338 | if (el.isBool) { 339 | ret[el.getAttribute('name')] = !!value; 340 | } else { 341 | ret[el.getAttribute('name')] = value; 342 | } 343 | } 344 | /* eslint-enable no-cond-assign */ 345 | return ret; 346 | } 347 | 348 | function createOptionsEl (name, values, selectionDefault) { 349 | const openDiv = '
' + name + ': '; 350 | const select = '
'; 372 | 373 | return openDiv + select + defaultOption + options + closeDiv; 374 | } 375 | 376 | /******************************************************************************/ 377 | 378 | const info_div = '

Camera

' + 379 | '
' + 380 | 'Status:
' + 381 | 'img: ' + 382 | 'canvas: ' + 383 | '
'; 384 | const options_div = '

Cordova Camera API Options

' + 385 | '
' + 386 | createOptionsEl('sourceType', Camera.PictureSourceType, camPictureSourceTypeDefault) + 387 | createOptionsEl('destinationType', Camera.DestinationType, camDestinationTypeDefault) + 388 | createOptionsEl('encodingType', Camera.EncodingType, camEncodingTypeDefault) + 389 | createOptionsEl('mediaType', Camera.MediaType, camMediaTypeDefault) + 390 | createOptionsEl('quality', { 0: 0, 50: 50, 80: 80, 100: 100 }, camQualityDefault) + 391 | createOptionsEl('targetWidth', { 50: 50, 200: 200, 800: 800, 2048: 2048 }) + 392 | createOptionsEl('targetHeight', { 50: 50, 200: 200, 800: 800, 2048: 2048 }) + 393 | createOptionsEl('allowEdit', true, camAllowEditDefault) + 394 | createOptionsEl('correctOrientation', true, camCorrectOrientationDefault) + 395 | createOptionsEl('saveToPhotoAlbum', true, camSaveToPhotoAlbumDefault) + 396 | createOptionsEl('cameraDirection', Camera.Direction) + 397 | '
'; 398 | const getpicture_div = '
'; 399 | const test_procedure = '

Recommended Test Procedure

' + 400 | 'Options not specified should be the default value' + 401 | '
Status box should update with image and info whenever an image is taken or selected from library' + 402 | '

' + 403 | '
  1. All default options. Should be able to edit once picture is taken and will be saved to library.
  2. ' + 404 | '

  3. sourceType=PHOTOLIBRARY
    Should be able to see picture that was just taken in previous test and edit when selected
  4. ' + 405 | '

  5. sourceType=Camera
    allowEdit=false
    saveToPhotoAlbum=false
    Should not be able to edit when taken and will not save to library
  6. ' + 406 | '

  7. encodingType=PNG
    allowEdit=true
    saveToPhotoAlbum=true
    cameraDirection=FRONT
    Should bring up front camera. Verify in status box info URL that image is encoded as PNG.
  8. ' + 407 | '

  9. sourceType=SAVEDPHOTOALBUM
    mediaType=VIDEO
    Should only be able to select a video
  10. ' + 408 | '

  11. sourceType=SAVEDPHOTOALBUM
    mediaType=PICTURE
    allowEdit=false
    Should only be able to select a picture and not edit
  12. ' + 409 | '

  13. sourceType=PHOTOLIBRARY
    mediaType=ALLMEDIA
    allowEdit=true
    Should be able to select pics and videos and edit picture if selected
  14. ' + 410 | '

  15. sourceType=CAMERA
    targetWidth & targetHeight=50
    allowEdit=false
    Do Get File Metadata test below and take note of size
    Repeat test but with width and height=800. Size should be significantly larger.
  16. ' + 411 | '

  17. quality=0
    targetWidth & targetHeight=default
    allowEdit=false
    Do Get File Metadata test below and take note of size
    Repeat test but with quality=80. Size should be significantly larger.
  18. ' + 412 | '
'; 413 | const inputs_div = '

Native File Inputs

' + 414 | 'For the following tests, status box should update with file selected' + 415 | '

input type=file
' + 416 | '
capture=camera
' + 417 | '
capture=camcorder
' + 418 | '
capture=microphone
'; 419 | const actions_div = '

Actions

' + 420 | 'For the following tests, ensure that an image is set in status box' + 421 | '

' + 422 | 'Expected result: Get metadata about file selected.
Status box will show, along with the metadata, "Call to FileEntry.getMetadata success, Call to FileEntry.setMetadata success, Call to FileEntry.getParent success"' + 423 | '

' + 424 | 'Expected result: Read contents of file.
Status box will show "Got file: {some metadata}, FileReader.readAsDataURL() - length = someNumber"' + 425 | '

' + 426 | 'Expected result: Copy image to new location and move file to different location.
Status box will show "Call to FileEntry.copyTo success:{some metadata}, Call to FileEntry.moveTo success:{some metadata}"' + 427 | '

' + 428 | 'Expected result: Write image to library.
Status box will show "Call to FileWriter.write success:{some metadata}, Call to FileWriter.truncate success:{some metadata}"' + 429 | '

' + 430 | 'Expected result: Upload image to server.
Status box may print out progress. Once finished will show "upload complete"' + 431 | '

' + 432 | 'Expected result: Display image using canvas.
Image will be displayed in status box under "canvas:"' + 433 | '

' + 434 | 'Expected result: Remove image from library.
Status box will show "FileEntry.remove success:["OK"]'; 435 | 436 | contentEl.innerHTML = info_div + options_div + getpicture_div + test_procedure + inputs_div + actions_div; 437 | 438 | const elements = document.getElementsByClassName('testInputTag'); 439 | const listener = function (e) { 440 | testInputTag(e.target); 441 | }; 442 | for (let i = 0; i < elements.length; ++i) { 443 | const item = elements[i]; 444 | item.addEventListener('change', listener, false); 445 | } 446 | 447 | createActionButton('Get picture', function () { 448 | getPicture(); 449 | }, 'getpicture'); 450 | 451 | createActionButton('Clear Status', function () { 452 | clearStatus(); 453 | }, 'getpicture'); 454 | 455 | createActionButton('Get File Metadata', function () { 456 | getFileInfo(); 457 | }, 'metadata'); 458 | 459 | createActionButton('Read with FileReader', function () { 460 | readFile(); 461 | }, 'reader'); 462 | 463 | createActionButton('Copy Image', function () { 464 | copyImage(); 465 | }, 'copy'); 466 | 467 | createActionButton('Write Image', function () { 468 | writeImage(); 469 | }, 'write'); 470 | 471 | createActionButton('Draw Using Canvas', function () { 472 | displayImageUsingCanvas(); 473 | }, 'draw_canvas'); 474 | 475 | createActionButton('Remove Image', function () { 476 | removeImage(); 477 | }, 'remove'); 478 | }; 479 | -------------------------------------------------------------------------------- /types/index.d.ts: -------------------------------------------------------------------------------- 1 | // Type definitions for Apache Cordova Camera plugin 2 | // Project: https://github.com/apache/cordova-plugin-camera 3 | // Definitions by: Microsoft Open Technologies Inc 4 | // Definitions: https://github.com/DefinitelyTyped/DefinitelyTyped 5 | // 6 | // Copyright (c) Microsoft Open Technologies Inc 7 | // Licensed under the MIT license. 8 | 9 | interface Navigator { 10 | /** 11 | * This plugin provides an API for taking pictures and for choosing images from the system's image library. 12 | */ 13 | camera: Camera; 14 | } 15 | 16 | /** 17 | * This plugin provides an API for taking pictures and for choosing images from the system's image library. 18 | */ 19 | interface Camera { 20 | /** 21 | * Removes intermediate photos taken by the camera from temporary storage. 22 | * @param onSuccess Success callback, that called when cleanup succeeds. 23 | * @param onError Error callback, that get an error message. 24 | */ 25 | cleanup( 26 | onSuccess: () => void, 27 | onError: (message: string) => void): void; 28 | /** 29 | * Takes a photo using the camera, or retrieves a photo from the device's image gallery. 30 | * @param cameraSuccess Success callback, that get the image 31 | * as a base64-encoded String, or as the URI for the image file. 32 | * @param cameraError Error callback, that get an error message. 33 | * @param cameraOptions Optional parameters to customize the camera settings. 34 | */ 35 | getPicture( 36 | cameraSuccess: (data: string) => void, 37 | cameraError: (message: string) => void, 38 | cameraOptions?: CameraOptions): void; 39 | // Next will work only on iOS 40 | //getPicture( 41 | // cameraSuccess: (data: string) => void, 42 | // cameraError: (message: string) => void, 43 | // cameraOptions?: CameraOptions): CameraPopoverHandle; 44 | } 45 | 46 | interface CameraOptions { 47 | /** Picture quality in range 0-100. Default is 50 */ 48 | quality?: number; 49 | /** 50 | * Choose the format of the return value. 51 | * Defined in navigator.camera.DestinationType. Default is FILE_URI. 52 | * DATA_URL : 0, Return image as base64-encoded string 53 | * FILE_URI : 1, Return image file URI 54 | */ 55 | destinationType?: number; 56 | /** 57 | * Set the source of the picture. 58 | * Defined in navigator.camera.PictureSourceType. Default is CAMERA. 59 | * PHOTOLIBRARY : 0, 60 | * CAMERA : 1, 61 | * SAVEDPHOTOALBUM : 2 62 | */ 63 | sourceType?: number; 64 | /** Allow simple editing of image before selection. */ 65 | allowEdit?: boolean; 66 | /** 67 | * Choose the returned image file's encoding. 68 | * Defined in navigator.camera.EncodingType. Default is JPEG 69 | * JPEG : 0 Return JPEG encoded image 70 | * PNG : 1 Return PNG encoded image 71 | */ 72 | encodingType?: number; 73 | /** 74 | * Width in pixels to scale image. Must be used with targetHeight. 75 | * Aspect ratio remains constant. 76 | */ 77 | targetWidth?: number; 78 | /** 79 | * Height in pixels to scale image. Must be used with targetWidth. 80 | * Aspect ratio remains constant. 81 | */ 82 | targetHeight?: number; 83 | /** 84 | * Set the type of media to select from. Only works when PictureSourceType 85 | * is PHOTOLIBRARY or SAVEDPHOTOALBUM. Defined in nagivator.camera.MediaType 86 | * PICTURE: 0 allow selection of still pictures only. DEFAULT. 87 | * Will return format specified via DestinationType 88 | * VIDEO: 1 allow selection of video only, WILL ALWAYS RETURN FILE_URI 89 | * ALLMEDIA : 2 allow selection from all media types 90 | */ 91 | mediaType?: number; 92 | /** Rotate the image to correct for the orientation of the device during capture. */ 93 | correctOrientation?: boolean; 94 | /** Save the image to the photo album on the device after capture. */ 95 | saveToPhotoAlbum?: boolean; 96 | /** 97 | * Choose the camera to use (front- or back-facing). 98 | * Defined in navigator.camera.Direction. Default is BACK. 99 | * FRONT: 0 100 | * BACK: 1 101 | */ 102 | cameraDirection?: number; 103 | /** iOS-only options that specify popover location in iPad. Defined in CameraPopoverOptions. */ 104 | popoverOptions?: CameraPopoverOptions; 105 | } 106 | 107 | /** 108 | * A handle to the popover dialog created by navigator.camera.getPicture. Used on iOS only. 109 | */ 110 | interface CameraPopoverHandle { 111 | /** 112 | * Set the position of the popover. 113 | * @param popoverOptions the CameraPopoverOptions that specify the new position. 114 | */ 115 | setPosition(popoverOptions: CameraPopoverOptions): void; 116 | } 117 | 118 | /** 119 | * iOS-only parameters that specify the anchor element location and arrow direction 120 | * of the popover when selecting images from an iPad's library or album. 121 | */ 122 | interface CameraPopoverOptions { 123 | x: number; 124 | y: number; 125 | width: number; 126 | height: number; 127 | /** 128 | * Direction the arrow on the popover should point. Defined in Camera.PopoverArrowDirection 129 | * Matches iOS UIPopoverArrowDirection constants. 130 | * ARROW_UP : 1, 131 | * ARROW_DOWN : 2, 132 | * ARROW_LEFT : 4, 133 | * ARROW_RIGHT : 8, 134 | * ARROW_ANY : 15 135 | */ 136 | arrowDir : number; 137 | popoverWidth: number; 138 | popoverHeight: number; 139 | } 140 | 141 | declare class CameraPopoverOptions implements CameraPopoverOptions { 142 | constructor(x?: number, y?: number, width?: number, height?: number, arrowDir?: number); 143 | } 144 | 145 | declare var Camera: { 146 | // Camera constants, defined in Camera plugin 147 | DestinationType: { 148 | DATA_URL: number; 149 | FILE_URI: number; 150 | } 151 | Direction: { 152 | BACK: number; 153 | FRONT: number; 154 | } 155 | EncodingType: { 156 | JPEG: number; 157 | PNG: number; 158 | } 159 | MediaType: { 160 | PICTURE: number; 161 | VIDEO: number; 162 | ALLMEDIA: number; 163 | } 164 | PictureSourceType: { 165 | PHOTOLIBRARY: number; 166 | CAMERA: number; 167 | SAVEDPHOTOALBUM: number; 168 | } 169 | // Used only on iOS 170 | PopoverArrowDirection: { 171 | ARROW_UP: number; 172 | ARROW_DOWN: number; 173 | ARROW_LEFT: number; 174 | ARROW_RIGHT: number; 175 | ARROW_ANY: number; 176 | } 177 | }; 178 | -------------------------------------------------------------------------------- /www/Camera.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on an 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | * KIND, either express or implied. See the License for the 17 | * specific language governing permissions and limitations 18 | * under the License. 19 | * 20 | */ 21 | 22 | const argscheck = require('cordova/argscheck'); 23 | const exec = require('cordova/exec'); 24 | const Camera = require('./Camera'); 25 | // XXX: commented out 26 | // CameraPopoverHandle = require('./CameraPopoverHandle'); 27 | 28 | /** 29 | * @namespace navigator 30 | */ 31 | 32 | /** 33 | * @exports camera 34 | */ 35 | const cameraExport = {}; 36 | 37 | // Tack on the Camera Constants to the base camera plugin. 38 | for (const key in Camera) { 39 | cameraExport[key] = Camera[key]; 40 | } 41 | 42 | /** 43 | * Callback function that provides an error message. 44 | * @callback module:camera.onError 45 | * @param {string} message - The message is provided by the device's native code. 46 | */ 47 | 48 | /** 49 | * Callback function that provides the image data. 50 | * @callback module:camera.onSuccess 51 | * @param {string} imageData - Base64 encoding of the image data, _or_ the image file URI, depending on [`cameraOptions`]{@link module:camera.CameraOptions} in effect. 52 | * @example 53 | * // Show image 54 | * // 55 | * function cameraCallback(imageData) { 56 | * var image = document.getElementById('myImage'); 57 | * image.src = "data:image/jpeg;base64," + imageData; 58 | * } 59 | */ 60 | 61 | /** 62 | * Optional parameters to customize the camera settings. 63 | * * [Quirks](#CameraOptions-quirks) 64 | * @typedef module:camera.CameraOptions 65 | * @type {Object} 66 | * @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.) 67 | * @property {module:Camera.DestinationType} [destinationType=FILE_URI] - Choose the format of the return value. 68 | * @property {module:Camera.PictureSourceType} [sourceType=CAMERA] - Set the source of the picture. 69 | * @property {Boolean} [allowEdit=false] - Allow simple editing of image before selection. 70 | * @property {module:Camera.EncodingType} [encodingType=JPEG] - Choose the returned image file's encoding. 71 | * @property {number} [targetWidth] - Width in pixels to scale image. Must be used with `targetHeight`. Aspect ratio remains constant. 72 | * @property {number} [targetHeight] - Height in pixels to scale image. Must be used with `targetWidth`. Aspect ratio remains constant. 73 | * @property {module:Camera.MediaType} [mediaType=PICTURE] - Set the type of media to select from. Only works when `PictureSourceType` is `PHOTOLIBRARY` or `SAVEDPHOTOALBUM`. 74 | * @property {Boolean} [correctOrientation] - Rotate the image to correct for the orientation of the device during capture. 75 | * @property {Boolean} [saveToPhotoAlbum] - Save the image to the photo album on the device after capture. 76 | * @property {module:CameraPopoverOptions} [popoverOptions] - iOS-only options that specify popover location in iPad. 77 | * @property {module:Camera.Direction} [cameraDirection=BACK] - Choose the camera to use (front- or back-facing). 78 | */ 79 | 80 | /** 81 | * @description Takes a photo using the camera, or retrieves a photo from the device's 82 | * image gallery. The image is passed to the success callback as a 83 | * Base64-encoded `String`, or as the URI for the image file. 84 | * 85 | * The `camera.getPicture` function opens the device's default camera 86 | * application that allows users to snap pictures by default - this behavior occurs, 87 | * when `Camera.sourceType` equals [`Camera.PictureSourceType.CAMERA`]{@link module:Camera.PictureSourceType}. 88 | * Once the user snaps the photo, the camera application closes and the application is restored. 89 | * 90 | * If `Camera.sourceType` is `Camera.PictureSourceType.PHOTOLIBRARY` or 91 | * `Camera.PictureSourceType.SAVEDPHOTOALBUM`, then a dialog displays 92 | * that allows users to select an existing image. 93 | * 94 | * The return value is sent to the [`cameraSuccess`]{@link module:camera.onSuccess} callback function, in 95 | * one of the following formats, depending on the specified 96 | * `cameraOptions`: 97 | * 98 | * - A `String` containing the Base64-encoded photo image. 99 | * - A `String` representing the image file location on local storage (default). 100 | * 101 | * You can do whatever you want with the encoded image or URI, for 102 | * example: 103 | * 104 | * - Render the image in an `` tag, as in the example below 105 | * - Save the data locally (`LocalStorage`, [Lawnchair](http://brianleroux.github.com/lawnchair/), etc.) 106 | * - Post the data to a remote server 107 | * 108 | * __NOTE__: Photo resolution on newer devices is quite good. Photos 109 | * selected from the device's gallery are not downscaled to a lower 110 | * quality, even if a `quality` parameter is specified. To avoid common 111 | * memory problems, set `Camera.destinationType` to `FILE_URI` rather 112 | * than `DATA_URL`. 113 | * 114 | * __Supported Platforms__ 115 | * 116 | * - Android 117 | * - Browser 118 | * - iOS 119 | * 120 | * More examples [here](#camera-getPicture-examples). Quirks [here](#camera-getPicture-quirks). 121 | * 122 | * @example 123 | * navigator.camera.getPicture(cameraSuccess, cameraError, cameraOptions); 124 | * @param {module:camera.onSuccess} successCallback 125 | * @param {module:camera.onError} errorCallback 126 | * @param {module:camera.CameraOptions} options CameraOptions 127 | */ 128 | cameraExport.getPicture = function (successCallback, errorCallback, options) { 129 | argscheck.checkArgs('fFO', 'Camera.getPicture', arguments); 130 | options = options || {}; 131 | const getValue = argscheck.getValue; 132 | 133 | const quality = getValue(options.quality, 50); 134 | const destinationType = getValue(options.destinationType, Camera.DestinationType.FILE_URI); 135 | const sourceType = getValue(options.sourceType, Camera.PictureSourceType.CAMERA); 136 | const targetWidth = getValue(options.targetWidth, -1); 137 | const targetHeight = getValue(options.targetHeight, -1); 138 | const encodingType = getValue(options.encodingType, Camera.EncodingType.JPEG); 139 | const mediaType = getValue(options.mediaType, Camera.MediaType.PICTURE); 140 | const allowEdit = !!options.allowEdit; 141 | const correctOrientation = !!options.correctOrientation; 142 | const saveToPhotoAlbum = !!options.saveToPhotoAlbum; 143 | const popoverOptions = getValue(options.popoverOptions, null); 144 | const cameraDirection = getValue(options.cameraDirection, Camera.Direction.BACK); 145 | 146 | if (allowEdit) { 147 | console.warn('allowEdit is deprecated. It does not work reliably on all platforms. Utilise a dedicated image editing library instead. allowEdit functionality is scheduled to be removed in a future release.'); 148 | } 149 | 150 | const args = [quality, destinationType, sourceType, targetWidth, targetHeight, encodingType, 151 | mediaType, allowEdit, correctOrientation, saveToPhotoAlbum, popoverOptions, cameraDirection]; 152 | 153 | exec(successCallback, errorCallback, 'Camera', 'takePicture', args); 154 | // XXX: commented out 155 | // return new CameraPopoverHandle(); 156 | }; 157 | 158 | /** 159 | * Removes intermediate image files that are kept in temporary storage 160 | * after calling [`camera.getPicture`]{@link module:camera.getPicture}. Applies only when the value of 161 | * `Camera.sourceType` equals `Camera.PictureSourceType.CAMERA` and the 162 | * `Camera.destinationType` equals `Camera.DestinationType.FILE_URI`. 163 | * 164 | * __Supported Platforms__ 165 | * 166 | * - iOS 167 | * 168 | * @example 169 | * navigator.camera.cleanup(onSuccess, onFail); 170 | * 171 | * function onSuccess() { 172 | * console.log("Camera cleanup success.") 173 | * } 174 | * 175 | * function onFail(message) { 176 | * alert('Failed because: ' + message); 177 | * } 178 | */ 179 | cameraExport.cleanup = function (successCallback, errorCallback) { 180 | exec(successCallback, errorCallback, 'Camera', 'cleanup', []); 181 | }; 182 | 183 | module.exports = cameraExport; 184 | -------------------------------------------------------------------------------- /www/CameraConstants.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on an 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | * KIND, either express or implied. See the License for the 17 | * specific language governing permissions and limitations 18 | * under the License. 19 | * 20 | */ 21 | 22 | /** 23 | * @module Camera 24 | */ 25 | module.exports = { 26 | /** 27 | * @description 28 | * Defines the output format of `Camera.getPicture` call. 29 | * 30 | * @enum {number} 31 | */ 32 | DestinationType: { 33 | /** 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 */ 34 | DATA_URL: 0, 35 | /** Return file uri (content://media/external/images/media/2 for Android) */ 36 | FILE_URI: 1 37 | }, 38 | /** 39 | * @enum {number} 40 | */ 41 | EncodingType: { 42 | /** Return JPEG encoded image */ 43 | JPEG: 0, 44 | /** Return PNG encoded image */ 45 | PNG: 1 46 | }, 47 | /** 48 | * @enum {number} 49 | */ 50 | MediaType: { 51 | /** Allow selection of still pictures only. DEFAULT. Will return format specified via DestinationType */ 52 | PICTURE: 0, 53 | /** Allow selection of video only, ONLY RETURNS URL */ 54 | VIDEO: 1, 55 | /** Allow selection from all media types */ 56 | ALLMEDIA: 2 57 | }, 58 | /** 59 | * @description 60 | * Defines the output format of `Camera.getPicture` call. 61 | * 62 | * @enum {number} 63 | */ 64 | PictureSourceType: { 65 | /** Choose image from the device's photo library (same as SAVEDPHOTOALBUM for Android) */ 66 | PHOTOLIBRARY: 0, 67 | /** Take picture from camera */ 68 | CAMERA: 1, 69 | /** Choose image only from the device's Camera Roll album (same as PHOTOLIBRARY for Android) */ 70 | SAVEDPHOTOALBUM: 2 71 | }, 72 | /** 73 | * Matches iOS UIPopoverArrowDirection constants to specify arrow location on popover. 74 | * @enum {number} 75 | */ 76 | PopoverArrowDirection: { 77 | ARROW_UP: 1, 78 | ARROW_DOWN: 2, 79 | ARROW_LEFT: 4, 80 | ARROW_RIGHT: 8, 81 | ARROW_ANY: 15 82 | }, 83 | /** 84 | * @enum {number} 85 | */ 86 | Direction: { 87 | /** Use the back-facing camera */ 88 | BACK: 0, 89 | /** Use the front-facing camera */ 90 | FRONT: 1 91 | } 92 | }; 93 | -------------------------------------------------------------------------------- /www/CameraPopoverHandle.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on an 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | * KIND, either express or implied. See the License for the 17 | * specific language governing permissions and limitations 18 | * under the License. 19 | * 20 | */ 21 | 22 | /** 23 | * @ignore in favour of iOS' one 24 | * A handle to an image picker popover. 25 | */ 26 | const CameraPopoverHandle = function () { 27 | this.setPosition = function (popoverOptions) { 28 | console.log('CameraPopoverHandle.setPosition is only supported on iOS.'); 29 | }; 30 | }; 31 | 32 | module.exports = CameraPopoverHandle; 33 | -------------------------------------------------------------------------------- /www/CameraPopoverOptions.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on an 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | * KIND, either express or implied. See the License for the 17 | * specific language governing permissions and limitations 18 | * under the License. 19 | * 20 | */ 21 | 22 | const Camera = require('./Camera'); 23 | 24 | /** 25 | * @namespace navigator 26 | */ 27 | 28 | /** 29 | * iOS-only parameters that specify the anchor element location and arrow 30 | * direction of the popover when selecting images from an iPad's library 31 | * or album. 32 | * Note that the size of the popover may change to adjust to the 33 | * direction of the arrow and orientation of the screen. Make sure to 34 | * account for orientation changes when specifying the anchor element 35 | * location. 36 | * @module CameraPopoverOptions 37 | * @param {Number} [x=0] - x pixel coordinate of screen element onto which to anchor the popover. 38 | * @param {Number} [y=32] - y pixel coordinate of screen element onto which to anchor the popover. 39 | * @param {Number} [width=320] - width, in pixels, of the screen element onto which to anchor the popover. 40 | * @param {Number} [height=480] - height, in pixels, of the screen element onto which to anchor the popover. 41 | * @param {module:Camera.PopoverArrowDirection} [arrowDir=ARROW_ANY] - Direction the arrow on the popover should point. 42 | * @param {Number} [popoverWidth=0] - width of the popover (0 or not specified will use apple's default width). 43 | * @param {Number} [popoverHeight=0] - height of the popover (0 or not specified will use apple's default height). 44 | */ 45 | const CameraPopoverOptions = function (x, y, width, height, arrowDir, popoverWidth, popoverHeight) { 46 | // information of rectangle that popover should be anchored to 47 | this.x = x || 0; 48 | this.y = y || 32; 49 | this.width = width || 320; 50 | this.height = height || 480; 51 | this.arrowDir = arrowDir || Camera.PopoverArrowDirection.ARROW_ANY; 52 | this.popoverWidth = popoverWidth || 0; 53 | this.popoverHeight = popoverHeight || 0; 54 | }; 55 | 56 | module.exports = CameraPopoverOptions; 57 | -------------------------------------------------------------------------------- /www/ios/CameraPopoverHandle.js: -------------------------------------------------------------------------------- 1 | /* 2 | * 3 | * Licensed to the Apache Software Foundation (ASF) under one 4 | * or more contributor license agreements. See the NOTICE file 5 | * distributed with this work for additional information 6 | * regarding copyright ownership. The ASF licenses this file 7 | * to you under the Apache License, Version 2.0 (the 8 | * "License"); you may not use this file except in compliance 9 | * with the License. You may obtain a copy of the License at 10 | * 11 | * http://www.apache.org/licenses/LICENSE-2.0 12 | * 13 | * Unless required by applicable law or agreed to in writing, 14 | * software distributed under the License is distributed on an 15 | * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 16 | * KIND, either express or implied. See the License for the 17 | * specific language governing permissions and limitations 18 | * under the License. 19 | * 20 | */ 21 | 22 | const exec = require('cordova/exec'); 23 | 24 | /** 25 | * @namespace navigator 26 | */ 27 | 28 | /** 29 | * A handle to an image picker popover. 30 | * 31 | * __Supported Platforms__ 32 | * 33 | * - iOS 34 | * 35 | * @example 36 | * navigator.camera.getPicture(onSuccess, onFail, 37 | * { 38 | * destinationType: Camera.DestinationType.FILE_URI, 39 | * sourceType: Camera.PictureSourceType.PHOTOLIBRARY, 40 | * popoverOptions: new CameraPopoverOptions(300, 300, 100, 100, Camera.PopoverArrowDirection.ARROW_ANY, 300, 600) 41 | * }); 42 | * 43 | * // Reposition the popover if the orientation changes. 44 | * window.onorientationchange = function() { 45 | * var cameraPopoverHandle = new CameraPopoverHandle(); 46 | * var cameraPopoverOptions = new CameraPopoverOptions(0, 0, 100, 100, Camera.PopoverArrowDirection.ARROW_ANY, 400, 500); 47 | * cameraPopoverHandle.setPosition(cameraPopoverOptions); 48 | * } 49 | * @module CameraPopoverHandle 50 | */ 51 | const CameraPopoverHandle = function () { 52 | /** 53 | * Can be used to reposition the image selection dialog, 54 | * for example, when the device orientation changes. 55 | * @memberof CameraPopoverHandle 56 | * @instance 57 | * @method setPosition 58 | * @param {module:CameraPopoverOptions} popoverOptions 59 | */ 60 | this.setPosition = function (popoverOptions) { 61 | const args = [popoverOptions]; 62 | exec(null, null, 'Camera', 'repositionPopover', args); 63 | }; 64 | }; 65 | 66 | module.exports = CameraPopoverHandle; 67 | --------------------------------------------------------------------------------