init
This commit is contained in:
17
node_modules/@capacitor/camera/CapacitorCamera.podspec
generated
vendored
Normal file
17
node_modules/@capacitor/camera/CapacitorCamera.podspec
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
require 'json'
|
||||
|
||||
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'CapacitorCamera'
|
||||
s.version = package['version']
|
||||
s.summary = package['description']
|
||||
s.license = package['license']
|
||||
s.homepage = 'https://capacitorjs.com'
|
||||
s.author = package['author']
|
||||
s.source = { :git => 'https://github.com/ionic-team/capacitor-plugins.git', :tag => package['name'] + '@' + package['version'] }
|
||||
s.source_files = 'ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}', 'camera/ios/Sources/**/*.{swift,h,m,c,cc,mm,cpp}'
|
||||
s.ios.deployment_target = '14.0'
|
||||
s.dependency 'Capacitor'
|
||||
s.swift_version = '5.1'
|
||||
end
|
||||
23
node_modules/@capacitor/camera/LICENSE
generated
vendored
Normal file
23
node_modules/@capacitor/camera/LICENSE
generated
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
Copyright 2020-present Ionic
|
||||
https://ionic.io
|
||||
|
||||
MIT License
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
28
node_modules/@capacitor/camera/Package.swift
generated
vendored
Normal file
28
node_modules/@capacitor/camera/Package.swift
generated
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
// swift-tools-version: 5.9
|
||||
import PackageDescription
|
||||
|
||||
let package = Package(
|
||||
name: "CapacitorCamera",
|
||||
platforms: [.iOS(.v14)],
|
||||
products: [
|
||||
.library(
|
||||
name: "CapacitorCamera",
|
||||
targets: ["CameraPlugin"])
|
||||
],
|
||||
dependencies: [
|
||||
.package(url: "https://github.com/ionic-team/capacitor-swift-pm.git", from: "7.0.0")
|
||||
],
|
||||
targets: [
|
||||
.target(
|
||||
name: "CameraPlugin",
|
||||
dependencies: [
|
||||
.product(name: "Capacitor", package: "capacitor-swift-pm"),
|
||||
.product(name: "Cordova", package: "capacitor-swift-pm")
|
||||
],
|
||||
path: "ios/Sources/CameraPlugin"),
|
||||
.testTarget(
|
||||
name: "CameraPluginTests",
|
||||
dependencies: ["CameraPlugin"],
|
||||
path: "ios/Tests/CameraPluginTests")
|
||||
]
|
||||
)
|
||||
353
node_modules/@capacitor/camera/README.md
generated
vendored
Normal file
353
node_modules/@capacitor/camera/README.md
generated
vendored
Normal file
@@ -0,0 +1,353 @@
|
||||
# @capacitor/camera
|
||||
|
||||
The Camera API provides the ability to take a photo with the camera or choose an existing one from the photo album.
|
||||
|
||||
## Install
|
||||
|
||||
```bash
|
||||
npm install @capacitor/camera
|
||||
npx cap sync
|
||||
```
|
||||
|
||||
## iOS
|
||||
|
||||
iOS requires the following usage description be added and filled out for your app in `Info.plist`:
|
||||
|
||||
- `NSCameraUsageDescription` (`Privacy - Camera Usage Description`)
|
||||
- `NSPhotoLibraryAddUsageDescription` (`Privacy - Photo Library Additions Usage Description`)
|
||||
- `NSPhotoLibraryUsageDescription` (`Privacy - Photo Library Usage Description`)
|
||||
|
||||
Read about [Configuring `Info.plist`](https://capacitorjs.com/docs/ios/configuration#configuring-infoplist) in the [iOS Guide](https://capacitorjs.com/docs/ios) for more information on setting iOS permissions in Xcode
|
||||
|
||||
## Android
|
||||
|
||||
When picking existing images from the device gallery, the Android Photo Picker component is now used. The Photo Picker is available on devices that meet the following criteria:
|
||||
|
||||
- Run Android 11 (API level 30) or higher
|
||||
- Receive changes to Modular System Components through Google System Updates
|
||||
|
||||
Older devices and Android Go devices running Android 11 or 12 that support Google Play services can install a backported version of the photo picker. To enable the automatic installation of the backported photo picker module through Google Play services, add the following entry to the `<application>` tag in your `AndroidManifest.xml` file:
|
||||
|
||||
```xml
|
||||
<!-- Trigger Google Play services to install the backported photo picker module. -->
|
||||
<!--suppress AndroidDomInspection -->
|
||||
<service android:name="com.google.android.gms.metadata.ModuleDependencies"
|
||||
android:enabled="false"
|
||||
android:exported="false"
|
||||
tools:ignore="MissingClass">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.metadata.MODULE_DEPENDENCIES" />
|
||||
</intent-filter>
|
||||
<meta-data android:name="photopicker_activity:0:required" android:value="" />
|
||||
</service>
|
||||
```
|
||||
|
||||
If that entry is not added, the devices that don't support the Photo Picker, the Photo Picker component fallbacks to `Intent.ACTION_OPEN_DOCUMENT`.
|
||||
|
||||
The Camera plugin requires no permissions, unless using `saveToGallery: true`, in that case the following permissions should be added to your `AndroidManifest.xml`:
|
||||
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
```
|
||||
|
||||
You can also specify those permissions only for the Android versions where they will be requested:
|
||||
|
||||
```xml
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" android:maxSdkVersion="32"/>
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" android:maxSdkVersion="29"/>
|
||||
```
|
||||
|
||||
The storage permissions are for reading/saving photo files.
|
||||
|
||||
Read about [Setting Permissions](https://capacitorjs.com/docs/android/configuration#setting-permissions) in the [Android Guide](https://capacitorjs.com/docs/android) for more information on setting Android permissions.
|
||||
|
||||
Additionally, because the Camera API launches a separate Activity to handle taking the photo, you should listen for `appRestoredResult` in the `App` plugin to handle any camera data that was sent in the case your app was terminated by the operating system while the Activity was running.
|
||||
|
||||
### Variables
|
||||
|
||||
This plugin will use the following project variables (defined in your app's `variables.gradle` file):
|
||||
|
||||
- `androidxExifInterfaceVersion`: version of `androidx.exifinterface:exifinterface` (default: `1.3.7`)
|
||||
- `androidxMaterialVersion`: version of `com.google.android.material:material` (default: `1.12.0`)
|
||||
|
||||
## PWA Notes
|
||||
|
||||
[PWA Elements](https://capacitorjs.com/docs/web/pwa-elements) are required for Camera plugin to work.
|
||||
|
||||
## Example
|
||||
|
||||
```typescript
|
||||
import { Camera, CameraResultType } from '@capacitor/camera';
|
||||
|
||||
const takePicture = async () => {
|
||||
const image = await Camera.getPhoto({
|
||||
quality: 90,
|
||||
allowEditing: true,
|
||||
resultType: CameraResultType.Uri
|
||||
});
|
||||
|
||||
// image.webPath will contain a path that can be set as an image src.
|
||||
// You can access the original file using image.path, which can be
|
||||
// passed to the Filesystem API to read the raw data of the image,
|
||||
// if desired (or pass resultType: CameraResultType.Base64 to getPhoto)
|
||||
var imageUrl = image.webPath;
|
||||
|
||||
// Can be set to the src of an image now
|
||||
imageElement.src = imageUrl;
|
||||
};
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
<docgen-index>
|
||||
|
||||
* [`getPhoto(...)`](#getphoto)
|
||||
* [`pickImages(...)`](#pickimages)
|
||||
* [`pickLimitedLibraryPhotos()`](#picklimitedlibraryphotos)
|
||||
* [`getLimitedLibraryPhotos()`](#getlimitedlibraryphotos)
|
||||
* [`checkPermissions()`](#checkpermissions)
|
||||
* [`requestPermissions(...)`](#requestpermissions)
|
||||
* [Interfaces](#interfaces)
|
||||
* [Type Aliases](#type-aliases)
|
||||
* [Enums](#enums)
|
||||
|
||||
</docgen-index>
|
||||
|
||||
<docgen-api>
|
||||
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
||||
|
||||
### getPhoto(...)
|
||||
|
||||
```typescript
|
||||
getPhoto(options: ImageOptions) => Promise<Photo>
|
||||
```
|
||||
|
||||
Prompt the user to pick a photo from an album, or take a new photo
|
||||
with the camera.
|
||||
|
||||
| Param | Type |
|
||||
| ------------- | ----------------------------------------------------- |
|
||||
| **`options`** | <code><a href="#imageoptions">ImageOptions</a></code> |
|
||||
|
||||
**Returns:** <code>Promise<<a href="#photo">Photo</a>></code>
|
||||
|
||||
**Since:** 1.0.0
|
||||
|
||||
--------------------
|
||||
|
||||
|
||||
### pickImages(...)
|
||||
|
||||
```typescript
|
||||
pickImages(options: GalleryImageOptions) => Promise<GalleryPhotos>
|
||||
```
|
||||
|
||||
Allows the user to pick multiple pictures from the photo gallery.
|
||||
On iOS 13 and older it only allows to pick one picture.
|
||||
|
||||
| Param | Type |
|
||||
| ------------- | ------------------------------------------------------------------- |
|
||||
| **`options`** | <code><a href="#galleryimageoptions">GalleryImageOptions</a></code> |
|
||||
|
||||
**Returns:** <code>Promise<<a href="#galleryphotos">GalleryPhotos</a>></code>
|
||||
|
||||
**Since:** 1.2.0
|
||||
|
||||
--------------------
|
||||
|
||||
|
||||
### pickLimitedLibraryPhotos()
|
||||
|
||||
```typescript
|
||||
pickLimitedLibraryPhotos() => Promise<GalleryPhotos>
|
||||
```
|
||||
|
||||
iOS 14+ Only: Allows the user to update their limited photo library selection.
|
||||
On iOS 15+ returns all the limited photos after the picker dismissal.
|
||||
On iOS 14 or if the user gave full access to the photos it returns an empty array.
|
||||
|
||||
**Returns:** <code>Promise<<a href="#galleryphotos">GalleryPhotos</a>></code>
|
||||
|
||||
**Since:** 4.1.0
|
||||
|
||||
--------------------
|
||||
|
||||
|
||||
### getLimitedLibraryPhotos()
|
||||
|
||||
```typescript
|
||||
getLimitedLibraryPhotos() => Promise<GalleryPhotos>
|
||||
```
|
||||
|
||||
iOS 14+ Only: Return an array of photos selected from the limited photo library.
|
||||
|
||||
**Returns:** <code>Promise<<a href="#galleryphotos">GalleryPhotos</a>></code>
|
||||
|
||||
**Since:** 4.1.0
|
||||
|
||||
--------------------
|
||||
|
||||
|
||||
### checkPermissions()
|
||||
|
||||
```typescript
|
||||
checkPermissions() => Promise<PermissionStatus>
|
||||
```
|
||||
|
||||
Check camera and photo album permissions
|
||||
|
||||
**Returns:** <code>Promise<<a href="#permissionstatus">PermissionStatus</a>></code>
|
||||
|
||||
**Since:** 1.0.0
|
||||
|
||||
--------------------
|
||||
|
||||
|
||||
### requestPermissions(...)
|
||||
|
||||
```typescript
|
||||
requestPermissions(permissions?: CameraPluginPermissions | undefined) => Promise<PermissionStatus>
|
||||
```
|
||||
|
||||
Request camera and photo album permissions
|
||||
|
||||
| Param | Type |
|
||||
| ----------------- | --------------------------------------------------------------------------- |
|
||||
| **`permissions`** | <code><a href="#camerapluginpermissions">CameraPluginPermissions</a></code> |
|
||||
|
||||
**Returns:** <code>Promise<<a href="#permissionstatus">PermissionStatus</a>></code>
|
||||
|
||||
**Since:** 1.0.0
|
||||
|
||||
--------------------
|
||||
|
||||
|
||||
### Interfaces
|
||||
|
||||
|
||||
#### Photo
|
||||
|
||||
| Prop | Type | Description | Since |
|
||||
| ------------------ | -------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ | ----- |
|
||||
| **`base64String`** | <code>string</code> | The base64 encoded string representation of the image, if using <a href="#cameraresulttype">CameraResultType.Base64</a>. | 1.0.0 |
|
||||
| **`dataUrl`** | <code>string</code> | The url starting with 'data:image/jpeg;base64,' and the base64 encoded string representation of the image, if using <a href="#cameraresulttype">CameraResultType.DataUrl</a>. Note: On web, the file format could change depending on the browser. | 1.0.0 |
|
||||
| **`path`** | <code>string</code> | If using <a href="#cameraresulttype">CameraResultType.Uri</a>, the path will contain a full, platform-specific file URL that can be read later using the Filesystem API. | 1.0.0 |
|
||||
| **`webPath`** | <code>string</code> | webPath returns a path that can be used to set the src attribute of an image for efficient loading and rendering. | 1.0.0 |
|
||||
| **`exif`** | <code>any</code> | Exif data, if any, retrieved from the image | 1.0.0 |
|
||||
| **`format`** | <code>string</code> | The format of the image, ex: jpeg, png, gif. iOS and Android only support jpeg. Web supports jpeg, png and gif, but the exact availability may vary depending on the browser. gif is only supported if `webUseInput` is set to `true` or if `source` is set to `Photos`. | 1.0.0 |
|
||||
| **`saved`** | <code>boolean</code> | Whether if the image was saved to the gallery or not. On Android and iOS, saving to the gallery can fail if the user didn't grant the required permissions. On Web there is no gallery, so always returns false. | 1.1.0 |
|
||||
|
||||
|
||||
#### ImageOptions
|
||||
|
||||
| Prop | Type | Description | Default | Since |
|
||||
| ------------------------ | ------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------- | ----- |
|
||||
| **`quality`** | <code>number</code> | The quality of image to return as JPEG, from 0-100 Note: This option is only supported on Android and iOS | | 1.0.0 |
|
||||
| **`allowEditing`** | <code>boolean</code> | Whether to allow the user to crop or make small edits (platform specific). On iOS 14+ it's only supported for <a href="#camerasource">CameraSource.Camera</a>, but not for <a href="#camerasource">CameraSource.Photos</a>. | | 1.0.0 |
|
||||
| **`resultType`** | <code><a href="#cameraresulttype">CameraResultType</a></code> | How the data should be returned. Currently, only 'Base64', 'DataUrl' or 'Uri' is supported | | 1.0.0 |
|
||||
| **`saveToGallery`** | <code>boolean</code> | Whether to save the photo to the gallery. If the photo was picked from the gallery, it will only be saved if edited. | <code>: false</code> | 1.0.0 |
|
||||
| **`width`** | <code>number</code> | The desired maximum width of the saved image. The aspect ratio is respected. | | 1.0.0 |
|
||||
| **`height`** | <code>number</code> | The desired maximum height of the saved image. The aspect ratio is respected. | | 1.0.0 |
|
||||
| **`correctOrientation`** | <code>boolean</code> | Whether to automatically rotate the image "up" to correct for orientation in portrait mode | <code>: true</code> | 1.0.0 |
|
||||
| **`source`** | <code><a href="#camerasource">CameraSource</a></code> | The source to get the photo from. By default this prompts the user to select either the photo album or take a photo. | <code>: CameraSource.Prompt</code> | 1.0.0 |
|
||||
| **`direction`** | <code><a href="#cameradirection">CameraDirection</a></code> | iOS and Web only: The camera direction. | <code>: CameraDirection.Rear</code> | 1.0.0 |
|
||||
| **`presentationStyle`** | <code>'fullscreen' \| 'popover'</code> | iOS only: The presentation style of the Camera. | <code>: 'fullscreen'</code> | 1.0.0 |
|
||||
| **`webUseInput`** | <code>boolean</code> | Web only: Whether to use the PWA Element experience or file input. The default is to use PWA Elements if installed and fall back to file input. To always use file input, set this to `true`. Learn more about PWA Elements: https://capacitorjs.com/docs/web/pwa-elements | | 1.0.0 |
|
||||
| **`promptLabelHeader`** | <code>string</code> | Text value to use when displaying the prompt. | <code>: 'Photo'</code> | 1.0.0 |
|
||||
| **`promptLabelCancel`** | <code>string</code> | Text value to use when displaying the prompt. iOS only: The label of the 'cancel' button. | <code>: 'Cancel'</code> | 1.0.0 |
|
||||
| **`promptLabelPhoto`** | <code>string</code> | Text value to use when displaying the prompt. The label of the button to select a saved image. | <code>: 'From Photos'</code> | 1.0.0 |
|
||||
| **`promptLabelPicture`** | <code>string</code> | Text value to use when displaying the prompt. The label of the button to open the camera. | <code>: 'Take Picture'</code> | 1.0.0 |
|
||||
|
||||
|
||||
#### GalleryPhotos
|
||||
|
||||
| Prop | Type | Description | Since |
|
||||
| ------------ | --------------------------- | ------------------------------- | ----- |
|
||||
| **`photos`** | <code>GalleryPhoto[]</code> | Array of all the picked photos. | 1.2.0 |
|
||||
|
||||
|
||||
#### GalleryPhoto
|
||||
|
||||
| Prop | Type | Description | Since |
|
||||
| ------------- | ------------------- | ----------------------------------------------------------------------------------------------------------------- | ----- |
|
||||
| **`path`** | <code>string</code> | Full, platform-specific file URL that can be read later using the Filesystem API. | 1.2.0 |
|
||||
| **`webPath`** | <code>string</code> | webPath returns a path that can be used to set the src attribute of an image for efficient loading and rendering. | 1.2.0 |
|
||||
| **`exif`** | <code>any</code> | Exif data, if any, retrieved from the image | 1.2.0 |
|
||||
| **`format`** | <code>string</code> | The format of the image, ex: jpeg, png, gif. iOS and Android only support jpeg. Web supports jpeg, png and gif. | 1.2.0 |
|
||||
|
||||
|
||||
#### GalleryImageOptions
|
||||
|
||||
| Prop | Type | Description | Default | Since |
|
||||
| ------------------------ | -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- | --------------------------- | ----- |
|
||||
| **`quality`** | <code>number</code> | The quality of image to return as JPEG, from 0-100 Note: This option is only supported on Android and iOS. | | 1.2.0 |
|
||||
| **`width`** | <code>number</code> | The desired maximum width of the saved image. The aspect ratio is respected. | | 1.2.0 |
|
||||
| **`height`** | <code>number</code> | The desired maximum height of the saved image. The aspect ratio is respected. | | 1.2.0 |
|
||||
| **`correctOrientation`** | <code>boolean</code> | Whether to automatically rotate the image "up" to correct for orientation in portrait mode | <code>: true</code> | 1.2.0 |
|
||||
| **`presentationStyle`** | <code>'fullscreen' \| 'popover'</code> | iOS only: The presentation style of the Camera. | <code>: 'fullscreen'</code> | 1.2.0 |
|
||||
| **`limit`** | <code>number</code> | Maximum number of pictures the user will be able to choose. Note: This option is only supported on Android 13+ and iOS. | <code>0 (unlimited)</code> | 1.2.0 |
|
||||
|
||||
|
||||
#### PermissionStatus
|
||||
|
||||
| Prop | Type |
|
||||
| ------------ | ----------------------------------------------------------------------- |
|
||||
| **`camera`** | <code><a href="#camerapermissionstate">CameraPermissionState</a></code> |
|
||||
| **`photos`** | <code><a href="#camerapermissionstate">CameraPermissionState</a></code> |
|
||||
|
||||
|
||||
#### CameraPluginPermissions
|
||||
|
||||
| Prop | Type |
|
||||
| ----------------- | ----------------------------------- |
|
||||
| **`permissions`** | <code>CameraPermissionType[]</code> |
|
||||
|
||||
|
||||
### Type Aliases
|
||||
|
||||
|
||||
#### CameraPermissionState
|
||||
|
||||
<code><a href="#permissionstate">PermissionState</a> | 'limited'</code>
|
||||
|
||||
|
||||
#### PermissionState
|
||||
|
||||
<code>'prompt' | 'prompt-with-rationale' | 'granted' | 'denied'</code>
|
||||
|
||||
|
||||
#### CameraPermissionType
|
||||
|
||||
<code>'camera' | 'photos'</code>
|
||||
|
||||
|
||||
### Enums
|
||||
|
||||
|
||||
#### CameraResultType
|
||||
|
||||
| Members | Value |
|
||||
| ------------- | ---------------------- |
|
||||
| **`Uri`** | <code>'uri'</code> |
|
||||
| **`Base64`** | <code>'base64'</code> |
|
||||
| **`DataUrl`** | <code>'dataUrl'</code> |
|
||||
|
||||
|
||||
#### CameraSource
|
||||
|
||||
| Members | Value | Description |
|
||||
| ------------ | --------------------- | ------------------------------------------------------------------ |
|
||||
| **`Prompt`** | <code>'PROMPT'</code> | Prompts the user to select either the photo album or take a photo. |
|
||||
| **`Camera`** | <code>'CAMERA'</code> | Take a new photo using the camera. |
|
||||
| **`Photos`** | <code>'PHOTOS'</code> | Pick an existing photo from the gallery or photo album. |
|
||||
|
||||
|
||||
#### CameraDirection
|
||||
|
||||
| Members | Value |
|
||||
| ----------- | -------------------- |
|
||||
| **`Rear`** | <code>'REAR'</code> |
|
||||
| **`Front`** | <code>'FRONT'</code> |
|
||||
|
||||
</docgen-api>
|
||||
83
node_modules/@capacitor/camera/android/build.gradle
generated
vendored
Normal file
83
node_modules/@capacitor/camera/android/build.gradle
generated
vendored
Normal file
@@ -0,0 +1,83 @@
|
||||
ext {
|
||||
capacitorVersion = System.getenv('CAPACITOR_VERSION')
|
||||
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.2'
|
||||
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.7.0'
|
||||
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.6.1'
|
||||
androidxExifInterfaceVersion = project.hasProperty('androidxExifInterfaceVersion') ? rootProject.ext.androidxExifInterfaceVersion : '1.3.7'
|
||||
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.2.1'
|
||||
androidxMaterialVersion = project.hasProperty('androidxMaterialVersion') ? rootProject.ext.androidxMaterialVersion : '1.12.0'
|
||||
}
|
||||
|
||||
buildscript {
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
maven {
|
||||
url "https://plugins.gradle.org/m2/"
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.7.2'
|
||||
if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") {
|
||||
classpath 'io.github.gradle-nexus:publish-plugin:1.3.0'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'com.android.library'
|
||||
if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") {
|
||||
apply plugin: 'io.github.gradle-nexus.publish-plugin'
|
||||
apply from: file('../../scripts/android/publish-root.gradle')
|
||||
apply from: file('../../scripts/android/publish-module.gradle')
|
||||
}
|
||||
|
||||
android {
|
||||
namespace "com.capacitorjs.plugins.camera"
|
||||
compileSdk project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 35
|
||||
defaultConfig {
|
||||
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 23
|
||||
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 35
|
||||
versionCode 1
|
||||
versionName "1.0"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
release {
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||
}
|
||||
}
|
||||
lintOptions {
|
||||
abortOnError false
|
||||
}
|
||||
compileOptions {
|
||||
sourceCompatibility JavaVersion.VERSION_21
|
||||
targetCompatibility JavaVersion.VERSION_21
|
||||
}
|
||||
publishing {
|
||||
singleVariant("release")
|
||||
}
|
||||
}
|
||||
|
||||
repositories {
|
||||
google()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
|
||||
dependencies {
|
||||
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
||||
|
||||
if (System.getenv("CAP_PLUGIN_PUBLISH") == "true") {
|
||||
implementation "com.capacitorjs:core:$capacitorVersion"
|
||||
} else {
|
||||
implementation project(':capacitor-android')
|
||||
}
|
||||
|
||||
implementation "androidx.exifinterface:exifinterface:$androidxExifInterfaceVersion"
|
||||
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
||||
implementation "com.google.android.material:material:$androidxMaterialVersion"
|
||||
testImplementation "junit:junit:$junitVersion"
|
||||
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
||||
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
||||
}
|
||||
7
node_modules/@capacitor/camera/android/src/main/AndroidManifest.xml
generated
vendored
Normal file
7
node_modules/@capacitor/camera/android/src/main/AndroidManifest.xml
generated
vendored
Normal file
@@ -0,0 +1,7 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<queries>
|
||||
<intent>
|
||||
<action android:name="android.media.action.IMAGE_CAPTURE" />
|
||||
</intent>
|
||||
</queries>
|
||||
</manifest>
|
||||
124
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraBottomSheetDialogFragment.java
generated
vendored
Normal file
124
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraBottomSheetDialogFragment.java
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
package com.capacitorjs.plugins.camera;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Dialog;
|
||||
import android.content.DialogInterface;
|
||||
import android.graphics.Color;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.coordinatorlayout.widget.CoordinatorLayout;
|
||||
import com.google.android.material.bottomsheet.BottomSheetBehavior;
|
||||
import com.google.android.material.bottomsheet.BottomSheetDialogFragment;
|
||||
import java.util.List;
|
||||
|
||||
public class CameraBottomSheetDialogFragment extends BottomSheetDialogFragment {
|
||||
|
||||
interface BottomSheetOnSelectedListener {
|
||||
void onSelected(int index);
|
||||
}
|
||||
|
||||
interface BottomSheetOnCanceledListener {
|
||||
void onCanceled();
|
||||
}
|
||||
|
||||
private BottomSheetOnSelectedListener selectedListener;
|
||||
private BottomSheetOnCanceledListener canceledListener;
|
||||
private List<String> options;
|
||||
private String title;
|
||||
|
||||
void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
void setOptions(List<String> options, BottomSheetOnSelectedListener selectedListener, BottomSheetOnCanceledListener canceledListener) {
|
||||
this.options = options;
|
||||
this.selectedListener = selectedListener;
|
||||
this.canceledListener = canceledListener;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
super.onCancel(dialog);
|
||||
if (canceledListener != null) {
|
||||
this.canceledListener.onCanceled();
|
||||
}
|
||||
}
|
||||
|
||||
private BottomSheetBehavior.BottomSheetCallback mBottomSheetBehaviorCallback = new BottomSheetBehavior.BottomSheetCallback() {
|
||||
@Override
|
||||
public void onStateChanged(@NonNull View bottomSheet, int newState) {
|
||||
if (newState == BottomSheetBehavior.STATE_HIDDEN) {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSlide(@NonNull View bottomSheet, float slideOffset) {}
|
||||
};
|
||||
|
||||
@Override
|
||||
@SuppressLint("RestrictedApi")
|
||||
public void setupDialog(Dialog dialog, int style) {
|
||||
super.setupDialog(dialog, style);
|
||||
|
||||
if (options == null || options.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
Window w = dialog.getWindow();
|
||||
|
||||
final float scale = getResources().getDisplayMetrics().density;
|
||||
|
||||
float layoutPaddingDp16 = 16.0f;
|
||||
float layoutPaddingDp12 = 12.0f;
|
||||
float layoutPaddingDp8 = 8.0f;
|
||||
int layoutPaddingPx16 = (int) (layoutPaddingDp16 * scale + 0.5f);
|
||||
int layoutPaddingPx12 = (int) (layoutPaddingDp12 * scale + 0.5f);
|
||||
int layoutPaddingPx8 = (int) (layoutPaddingDp8 * scale + 0.5f);
|
||||
|
||||
CoordinatorLayout parentLayout = new CoordinatorLayout(getContext());
|
||||
|
||||
LinearLayout layout = new LinearLayout(getContext());
|
||||
layout.setOrientation(LinearLayout.VERTICAL);
|
||||
layout.setPadding(layoutPaddingPx16, layoutPaddingPx16, layoutPaddingPx16, layoutPaddingPx16);
|
||||
TextView ttv = new TextView(getContext());
|
||||
ttv.setTextColor(Color.parseColor("#757575"));
|
||||
ttv.setPadding(layoutPaddingPx8, layoutPaddingPx8, layoutPaddingPx8, layoutPaddingPx8);
|
||||
ttv.setText(title);
|
||||
layout.addView(ttv);
|
||||
|
||||
for (int i = 0; i < options.size(); i++) {
|
||||
final int optionIndex = i;
|
||||
|
||||
TextView tv = new TextView(getContext());
|
||||
tv.setTextColor(Color.parseColor("#000000"));
|
||||
tv.setPadding(layoutPaddingPx12, layoutPaddingPx12, layoutPaddingPx12, layoutPaddingPx12);
|
||||
tv.setText(options.get(i));
|
||||
tv.setOnClickListener(
|
||||
view -> {
|
||||
if (selectedListener != null) {
|
||||
selectedListener.onSelected(optionIndex);
|
||||
}
|
||||
dismiss();
|
||||
}
|
||||
);
|
||||
layout.addView(tv);
|
||||
}
|
||||
|
||||
parentLayout.addView(layout.getRootView());
|
||||
|
||||
dialog.setContentView(parentLayout.getRootView());
|
||||
|
||||
CoordinatorLayout.LayoutParams params = (CoordinatorLayout.LayoutParams) ((View) parentLayout.getParent()).getLayoutParams();
|
||||
CoordinatorLayout.Behavior<View> behavior = params.getBehavior();
|
||||
|
||||
if (behavior instanceof BottomSheetBehavior) {
|
||||
BottomSheetBehavior<View> bottomSheetBehavior = (BottomSheetBehavior<View>) behavior;
|
||||
bottomSheetBehavior.addBottomSheetCallback(mBottomSheetBehaviorCallback);
|
||||
bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
|
||||
}
|
||||
}
|
||||
}
|
||||
923
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.java
generated
vendored
Normal file
923
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraPlugin.java
generated
vendored
Normal file
@@ -0,0 +1,923 @@
|
||||
package com.capacitorjs.plugins.camera;
|
||||
|
||||
import android.Manifest;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.app.Activity;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Environment;
|
||||
import android.os.Parcelable;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Base64;
|
||||
import androidx.activity.result.ActivityResult;
|
||||
import androidx.activity.result.ActivityResultCallback;
|
||||
import androidx.activity.result.ActivityResultLauncher;
|
||||
import androidx.activity.result.ActivityResultRegistryOwner;
|
||||
import androidx.activity.result.PickVisualMediaRequest;
|
||||
import androidx.activity.result.contract.ActivityResultContract;
|
||||
import androidx.activity.result.contract.ActivityResultContracts;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.core.content.FileProvider;
|
||||
import com.getcapacitor.FileUtils;
|
||||
import com.getcapacitor.JSArray;
|
||||
import com.getcapacitor.JSObject;
|
||||
import com.getcapacitor.Logger;
|
||||
import com.getcapacitor.PermissionState;
|
||||
import com.getcapacitor.Plugin;
|
||||
import com.getcapacitor.PluginCall;
|
||||
import com.getcapacitor.PluginMethod;
|
||||
import com.getcapacitor.annotation.ActivityCallback;
|
||||
import com.getcapacitor.annotation.CapacitorPlugin;
|
||||
import com.getcapacitor.annotation.Permission;
|
||||
import com.getcapacitor.annotation.PermissionCallback;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import org.json.JSONException;
|
||||
|
||||
/**
|
||||
* The Camera plugin makes it easy to take a photo or have the user select a photo
|
||||
* from their albums.
|
||||
*
|
||||
* On Android, this plugin sends an intent that opens the stock Camera app.
|
||||
*
|
||||
* Adapted from https://developer.android.com/training/camera/photobasics.html
|
||||
*/
|
||||
@SuppressLint("InlinedApi")
|
||||
@CapacitorPlugin(
|
||||
name = "Camera",
|
||||
permissions = {
|
||||
@Permission(strings = { Manifest.permission.CAMERA }, alias = CameraPlugin.CAMERA),
|
||||
@Permission(strings = {}, alias = CameraPlugin.PHOTOS),
|
||||
// SDK VERSIONS 29 AND BELOW
|
||||
@Permission(
|
||||
strings = { Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE },
|
||||
alias = CameraPlugin.SAVE_GALLERY
|
||||
),
|
||||
/*
|
||||
SDK VERSIONS 30-32
|
||||
This alias is a placeholder and the SAVE_GALLERY alias will be updated to use this permission
|
||||
so that the end user does not need to explicitly use separate aliases depending
|
||||
on the SDK version.
|
||||
*/
|
||||
@Permission(strings = { Manifest.permission.READ_EXTERNAL_STORAGE }, alias = CameraPlugin.READ_EXTERNAL_STORAGE)
|
||||
}
|
||||
)
|
||||
public class CameraPlugin extends Plugin {
|
||||
|
||||
// Permission alias constants
|
||||
static final String CAMERA = "camera";
|
||||
static final String PHOTOS = "photos";
|
||||
static final String SAVE_GALLERY = "saveGallery";
|
||||
static final String READ_EXTERNAL_STORAGE = "readExternalStorage";
|
||||
|
||||
// Message constants
|
||||
private static final String INVALID_RESULT_TYPE_ERROR = "Invalid resultType option";
|
||||
private static final String PERMISSION_DENIED_ERROR_CAMERA = "User denied access to camera";
|
||||
private static final String NO_CAMERA_ERROR = "Device doesn't have a camera available";
|
||||
private static final String NO_CAMERA_ACTIVITY_ERROR = "Unable to resolve camera activity";
|
||||
private static final String NO_PHOTO_ACTIVITY_ERROR = "Unable to resolve photo activity";
|
||||
private static final String IMAGE_FILE_SAVE_ERROR = "Unable to create photo on disk";
|
||||
private static final String IMAGE_PROCESS_NO_FILE_ERROR = "Unable to process image, file not found on disk";
|
||||
private static final String UNABLE_TO_PROCESS_IMAGE = "Unable to process image";
|
||||
private static final String IMAGE_EDIT_ERROR = "Unable to edit image";
|
||||
private static final String IMAGE_GALLERY_SAVE_ERROR = "Unable to save the image in the gallery";
|
||||
private static final String USER_CANCELLED = "User cancelled photos app";
|
||||
|
||||
private String imageFileSavePath;
|
||||
private String imageEditedFileSavePath;
|
||||
private Uri imageFileUri;
|
||||
private Uri imagePickedContentUri;
|
||||
private boolean isEdited = false;
|
||||
private boolean isFirstRequest = true;
|
||||
private boolean isSaved = false;
|
||||
private ActivityResultLauncher<PickVisualMediaRequest> pickMultipleMedia = null;
|
||||
private ActivityResultLauncher<PickVisualMediaRequest> pickMedia = null;
|
||||
|
||||
private final AtomicInteger mNextLocalRequestCode = new AtomicInteger();
|
||||
|
||||
private CameraSettings settings = new CameraSettings();
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
super.load();
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
public void getPhoto(PluginCall call) {
|
||||
isEdited = false;
|
||||
settings = getSettings(call);
|
||||
doShow(call);
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
public void pickImages(PluginCall call) {
|
||||
settings = getSettings(call);
|
||||
openPhotos(call, true);
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
public void pickLimitedLibraryPhotos(PluginCall call) {
|
||||
call.unimplemented("not supported on android");
|
||||
}
|
||||
|
||||
@PluginMethod
|
||||
public void getLimitedLibraryPhotos(PluginCall call) {
|
||||
call.unimplemented("not supported on android");
|
||||
}
|
||||
|
||||
private void doShow(PluginCall call) {
|
||||
switch (settings.getSource()) {
|
||||
case CAMERA:
|
||||
showCamera(call);
|
||||
break;
|
||||
case PHOTOS:
|
||||
showPhotos(call);
|
||||
break;
|
||||
default:
|
||||
showPrompt(call);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void showPrompt(final PluginCall call) {
|
||||
// We have all necessary permissions, open the camera
|
||||
List<String> options = new ArrayList<>();
|
||||
options.add(call.getString("promptLabelPhoto", "From Photos"));
|
||||
options.add(call.getString("promptLabelPicture", "Take Picture"));
|
||||
|
||||
final CameraBottomSheetDialogFragment fragment = new CameraBottomSheetDialogFragment();
|
||||
fragment.setTitle(call.getString("promptLabelHeader", "Photo"));
|
||||
fragment.setOptions(
|
||||
options,
|
||||
index -> {
|
||||
if (index == 0) {
|
||||
settings.setSource(CameraSource.PHOTOS);
|
||||
openPhotos(call);
|
||||
} else if (index == 1) {
|
||||
settings.setSource(CameraSource.CAMERA);
|
||||
openCamera(call);
|
||||
}
|
||||
},
|
||||
() -> call.reject(USER_CANCELLED)
|
||||
);
|
||||
fragment.show(getActivity().getSupportFragmentManager(), "capacitorModalsActionSheet");
|
||||
}
|
||||
|
||||
private void showCamera(final PluginCall call) {
|
||||
if (!getContext().getPackageManager().hasSystemFeature(PackageManager.FEATURE_CAMERA_ANY)) {
|
||||
call.reject(NO_CAMERA_ERROR);
|
||||
return;
|
||||
}
|
||||
openCamera(call);
|
||||
}
|
||||
|
||||
private void showPhotos(final PluginCall call) {
|
||||
openPhotos(call);
|
||||
}
|
||||
|
||||
private boolean checkCameraPermissions(PluginCall call) {
|
||||
// if the manifest does not contain the camera permissions key, we don't need to ask the user
|
||||
boolean needCameraPerms = isPermissionDeclared(CAMERA);
|
||||
boolean hasCameraPerms = !needCameraPerms || getPermissionState(CAMERA) == PermissionState.GRANTED;
|
||||
boolean hasGalleryPerms = getPermissionState(SAVE_GALLERY) == PermissionState.GRANTED;
|
||||
|
||||
// If we want to save to the gallery, we need two permissions
|
||||
// actually we only need permissions to save to gallery for Android <= 9 (API 28)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
// we might still need to request permission for the camera
|
||||
if (!hasCameraPerms) {
|
||||
requestPermissionForAlias(CAMERA, call, "cameraPermissionsCallback");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// we need to request permissions to save to gallery for Android <= 9
|
||||
if (settings.isSaveToGallery() && !(hasCameraPerms && hasGalleryPerms) && isFirstRequest) {
|
||||
isFirstRequest = false;
|
||||
String[] aliases;
|
||||
if (needCameraPerms) {
|
||||
aliases = new String[] { CAMERA, SAVE_GALLERY };
|
||||
} else {
|
||||
aliases = new String[] { SAVE_GALLERY };
|
||||
}
|
||||
requestPermissionForAliases(aliases, call, "cameraPermissionsCallback");
|
||||
return false;
|
||||
}
|
||||
// If we don't need to save to the gallery, we can just ask for camera permissions
|
||||
else if (!hasCameraPerms) {
|
||||
requestPermissionForAlias(CAMERA, call, "cameraPermissionsCallback");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes the plugin call after a camera permission request
|
||||
*
|
||||
* @see #getPhoto(PluginCall)
|
||||
* @param call the plugin call
|
||||
*/
|
||||
@PermissionCallback
|
||||
private void cameraPermissionsCallback(PluginCall call) {
|
||||
if (call.getMethodName().equals("pickImages")) {
|
||||
openPhotos(call, true);
|
||||
} else {
|
||||
if (settings.getSource() == CameraSource.CAMERA && getPermissionState(CAMERA) != PermissionState.GRANTED) {
|
||||
Logger.debug(getLogTag(), "User denied camera permission: " + getPermissionState(CAMERA).toString());
|
||||
call.reject(PERMISSION_DENIED_ERROR_CAMERA);
|
||||
return;
|
||||
}
|
||||
doShow(call);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void requestPermissionForAliases(@NonNull String[] aliases, @NonNull PluginCall call, @NonNull String callbackName) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
for (int i = 0; i < aliases.length; i++) {
|
||||
if (aliases[i].equals(SAVE_GALLERY)) {
|
||||
aliases[i] = READ_EXTERNAL_STORAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.requestPermissionForAliases(aliases, call, callbackName);
|
||||
}
|
||||
|
||||
private CameraSettings getSettings(PluginCall call) {
|
||||
CameraSettings settings = new CameraSettings();
|
||||
settings.setResultType(getResultType(call.getString("resultType")));
|
||||
settings.setSaveToGallery(call.getBoolean("saveToGallery", CameraSettings.DEFAULT_SAVE_IMAGE_TO_GALLERY));
|
||||
settings.setAllowEditing(call.getBoolean("allowEditing", false));
|
||||
settings.setQuality(call.getInt("quality", CameraSettings.DEFAULT_QUALITY));
|
||||
settings.setWidth(call.getInt("width", 0));
|
||||
settings.setHeight(call.getInt("height", 0));
|
||||
settings.setShouldResize(settings.getWidth() > 0 || settings.getHeight() > 0);
|
||||
settings.setShouldCorrectOrientation(call.getBoolean("correctOrientation", CameraSettings.DEFAULT_CORRECT_ORIENTATION));
|
||||
try {
|
||||
settings.setSource(CameraSource.valueOf(call.getString("source", CameraSource.PROMPT.getSource())));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
settings.setSource(CameraSource.PROMPT);
|
||||
}
|
||||
return settings;
|
||||
}
|
||||
|
||||
private CameraResultType getResultType(String resultType) {
|
||||
if (resultType == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return CameraResultType.valueOf(resultType.toUpperCase(Locale.ROOT));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
Logger.debug(getLogTag(), "Invalid result type \"" + resultType + "\", defaulting to base64");
|
||||
return CameraResultType.BASE64;
|
||||
}
|
||||
}
|
||||
|
||||
public void openCamera(final PluginCall call) {
|
||||
if (checkCameraPermissions(call)) {
|
||||
Intent takePictureIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);
|
||||
if (takePictureIntent.resolveActivity(getContext().getPackageManager()) != null) {
|
||||
// If we will be saving the photo, send the target file along
|
||||
try {
|
||||
String appId = getAppId();
|
||||
File photoFile = CameraUtils.createImageFile(getActivity());
|
||||
imageFileSavePath = photoFile.getAbsolutePath();
|
||||
// TODO: Verify provider config exists
|
||||
imageFileUri = FileProvider.getUriForFile(getActivity(), appId + ".fileprovider", photoFile);
|
||||
takePictureIntent.putExtra(MediaStore.EXTRA_OUTPUT, imageFileUri);
|
||||
} catch (Exception ex) {
|
||||
call.reject(IMAGE_FILE_SAVE_ERROR, ex);
|
||||
return;
|
||||
}
|
||||
|
||||
startActivityForResult(call, takePictureIntent, "processCameraImage");
|
||||
} else {
|
||||
call.reject(NO_CAMERA_ACTIVITY_ERROR);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void openPhotos(final PluginCall call) {
|
||||
openPhotos(call, false);
|
||||
}
|
||||
|
||||
private <I, O> ActivityResultLauncher<I> registerActivityResultLauncher(
|
||||
ActivityResultContract<I, O> contract,
|
||||
ActivityResultCallback<O> callback
|
||||
) {
|
||||
String key = "cap_activity_rq#" + mNextLocalRequestCode.getAndIncrement();
|
||||
if (bridge.getFragment() != null) {
|
||||
Object host = bridge.getFragment().getHost();
|
||||
if (host instanceof ActivityResultRegistryOwner) {
|
||||
return ((ActivityResultRegistryOwner) host).getActivityResultRegistry().register(key, contract, callback);
|
||||
}
|
||||
return bridge.getFragment().requireActivity().getActivityResultRegistry().register(key, contract, callback);
|
||||
}
|
||||
return bridge.getActivity().getActivityResultRegistry().register(key, contract, callback);
|
||||
}
|
||||
|
||||
private ActivityResultContract<PickVisualMediaRequest, List<Uri>> getContractForCall(final PluginCall call) {
|
||||
int limit = call.getInt("limit", 0);
|
||||
if (limit > 1) {
|
||||
return new ActivityResultContracts.PickMultipleVisualMedia(limit);
|
||||
} else {
|
||||
return new ActivityResultContracts.PickMultipleVisualMedia();
|
||||
}
|
||||
}
|
||||
|
||||
private void openPhotos(final PluginCall call, boolean multiple) {
|
||||
try {
|
||||
if (multiple) {
|
||||
pickMultipleMedia =
|
||||
registerActivityResultLauncher(
|
||||
getContractForCall(call),
|
||||
uris -> {
|
||||
if (!uris.isEmpty()) {
|
||||
Executor executor = Executors.newSingleThreadExecutor();
|
||||
executor.execute(
|
||||
() -> {
|
||||
JSObject ret = new JSObject();
|
||||
JSArray photos = new JSArray();
|
||||
for (Uri imageUri : uris) {
|
||||
try {
|
||||
JSObject processResult = processPickedImages(imageUri);
|
||||
if (
|
||||
processResult.getString("error") != null && !processResult.getString("error").isEmpty()
|
||||
) {
|
||||
call.reject(processResult.getString("error"));
|
||||
return;
|
||||
} else {
|
||||
photos.put(processResult);
|
||||
}
|
||||
} catch (SecurityException ex) {
|
||||
call.reject("SecurityException");
|
||||
}
|
||||
}
|
||||
ret.put("photos", photos);
|
||||
call.resolve(ret);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
call.reject(USER_CANCELLED);
|
||||
}
|
||||
pickMultipleMedia.unregister();
|
||||
}
|
||||
);
|
||||
pickMultipleMedia.launch(
|
||||
new PickVisualMediaRequest.Builder().setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE).build()
|
||||
);
|
||||
} else {
|
||||
pickMedia =
|
||||
registerActivityResultLauncher(
|
||||
new ActivityResultContracts.PickVisualMedia(),
|
||||
uri -> {
|
||||
if (uri != null) {
|
||||
imagePickedContentUri = uri;
|
||||
processPickedImage(uri, call);
|
||||
} else {
|
||||
call.reject(USER_CANCELLED);
|
||||
}
|
||||
pickMedia.unregister();
|
||||
}
|
||||
);
|
||||
pickMedia.launch(
|
||||
new PickVisualMediaRequest.Builder().setMediaType(ActivityResultContracts.PickVisualMedia.ImageOnly.INSTANCE).build()
|
||||
);
|
||||
}
|
||||
} catch (ActivityNotFoundException ex) {
|
||||
call.reject(NO_PHOTO_ACTIVITY_ERROR);
|
||||
}
|
||||
}
|
||||
|
||||
@ActivityCallback
|
||||
public void processCameraImage(PluginCall call, ActivityResult result) {
|
||||
settings = getSettings(call);
|
||||
if (imageFileSavePath == null) {
|
||||
call.reject(IMAGE_PROCESS_NO_FILE_ERROR);
|
||||
return;
|
||||
}
|
||||
// Load the image as a Bitmap
|
||||
File f = new File(imageFileSavePath);
|
||||
BitmapFactory.Options bmOptions = new BitmapFactory.Options();
|
||||
Uri contentUri = Uri.fromFile(f);
|
||||
Bitmap bitmap = BitmapFactory.decodeFile(imageFileSavePath, bmOptions);
|
||||
|
||||
if (bitmap == null) {
|
||||
call.reject(USER_CANCELLED);
|
||||
return;
|
||||
}
|
||||
|
||||
returnResult(call, bitmap, contentUri);
|
||||
}
|
||||
|
||||
public void processPickedImage(PluginCall call, ActivityResult result) {
|
||||
settings = getSettings(call);
|
||||
Intent data = result.getData();
|
||||
if (data == null) {
|
||||
call.reject(USER_CANCELLED);
|
||||
return;
|
||||
}
|
||||
|
||||
Uri u = data.getData();
|
||||
|
||||
imagePickedContentUri = u;
|
||||
|
||||
processPickedImage(u, call);
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private ArrayList<Parcelable> getLegacyParcelableArrayList(Bundle bundle, String key) {
|
||||
return bundle.getParcelableArrayList(key);
|
||||
}
|
||||
|
||||
private void processPickedImage(Uri imageUri, PluginCall call) {
|
||||
InputStream imageStream = null;
|
||||
|
||||
try {
|
||||
imageStream = getContext().getContentResolver().openInputStream(imageUri);
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
|
||||
|
||||
if (bitmap == null) {
|
||||
call.reject("Unable to process bitmap");
|
||||
return;
|
||||
}
|
||||
|
||||
returnResult(call, bitmap, imageUri);
|
||||
} catch (OutOfMemoryError err) {
|
||||
call.reject("Out of memory");
|
||||
} catch (FileNotFoundException ex) {
|
||||
call.reject("No such image found", ex);
|
||||
} finally {
|
||||
if (imageStream != null) {
|
||||
try {
|
||||
imageStream.close();
|
||||
} catch (IOException e) {
|
||||
Logger.error(getLogTag(), UNABLE_TO_PROCESS_IMAGE, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private JSObject processPickedImages(Uri imageUri) {
|
||||
InputStream imageStream = null;
|
||||
JSObject ret = new JSObject();
|
||||
try {
|
||||
imageStream = getContext().getContentResolver().openInputStream(imageUri);
|
||||
Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
|
||||
|
||||
if (bitmap == null) {
|
||||
ret.put("error", "Unable to process bitmap");
|
||||
return ret;
|
||||
}
|
||||
|
||||
ExifWrapper exif = ImageUtils.getExifData(getContext(), bitmap, imageUri);
|
||||
try {
|
||||
bitmap = prepareBitmap(bitmap, imageUri, exif);
|
||||
} catch (IOException e) {
|
||||
ret.put("error", UNABLE_TO_PROCESS_IMAGE);
|
||||
return ret;
|
||||
}
|
||||
// Compress the final image and prepare for output to client
|
||||
ByteArrayOutputStream bitmapOutputStream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, settings.getQuality(), bitmapOutputStream);
|
||||
|
||||
Uri newUri = getTempImage(imageUri, bitmapOutputStream);
|
||||
exif.copyExif(newUri.getPath());
|
||||
if (newUri != null) {
|
||||
ret.put("format", "jpeg");
|
||||
ret.put("exif", exif.toJson());
|
||||
ret.put("path", newUri.toString());
|
||||
ret.put("webPath", FileUtils.getPortablePath(getContext(), bridge.getLocalUrl(), newUri));
|
||||
} else {
|
||||
ret.put("error", UNABLE_TO_PROCESS_IMAGE);
|
||||
}
|
||||
return ret;
|
||||
} catch (OutOfMemoryError err) {
|
||||
ret.put("error", "Out of memory");
|
||||
} catch (FileNotFoundException ex) {
|
||||
ret.put("error", "No such image found");
|
||||
Logger.error(getLogTag(), "No such image found", ex);
|
||||
} finally {
|
||||
if (imageStream != null) {
|
||||
try {
|
||||
imageStream.close();
|
||||
} catch (IOException e) {
|
||||
Logger.error(getLogTag(), UNABLE_TO_PROCESS_IMAGE, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ActivityCallback
|
||||
private void processEditedImage(PluginCall call, ActivityResult result) {
|
||||
isEdited = true;
|
||||
settings = getSettings(call);
|
||||
if (result.getResultCode() == Activity.RESULT_CANCELED) {
|
||||
// User cancelled the edit operation, if this file was picked from photos,
|
||||
// process the original picked image, otherwise process it as a camera photo
|
||||
if (imagePickedContentUri != null) {
|
||||
processPickedImage(imagePickedContentUri, call);
|
||||
} else {
|
||||
processCameraImage(call, result);
|
||||
}
|
||||
} else {
|
||||
processPickedImage(call, result);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the modified image on the same path,
|
||||
* or on a temporary location if it's a content url
|
||||
* @param uri
|
||||
* @param is
|
||||
* @return
|
||||
* @throws IOException
|
||||
*/
|
||||
private Uri saveImage(Uri uri, InputStream is) throws IOException {
|
||||
File outFile = null;
|
||||
if (uri.getScheme().equals("content")) {
|
||||
outFile = getTempFile(uri);
|
||||
} else {
|
||||
outFile = new File(uri.getPath());
|
||||
}
|
||||
try {
|
||||
writePhoto(outFile, is);
|
||||
} catch (FileNotFoundException ex) {
|
||||
// Some gallery apps return read only file url, create a temporary file for modifications
|
||||
outFile = getTempFile(uri);
|
||||
writePhoto(outFile, is);
|
||||
}
|
||||
return Uri.fromFile(outFile);
|
||||
}
|
||||
|
||||
private void writePhoto(File outFile, InputStream is) throws IOException {
|
||||
FileOutputStream fos = new FileOutputStream(outFile);
|
||||
byte[] buffer = new byte[1024];
|
||||
int len;
|
||||
while ((len = is.read(buffer)) != -1) {
|
||||
fos.write(buffer, 0, len);
|
||||
}
|
||||
fos.close();
|
||||
}
|
||||
|
||||
private File getTempFile(Uri uri) {
|
||||
String filename = Uri.parse(Uri.decode(uri.toString())).getLastPathSegment();
|
||||
if (!filename.contains(".jpg") && !filename.contains(".jpeg")) {
|
||||
filename += "." + (new java.util.Date()).getTime() + ".jpeg";
|
||||
}
|
||||
File cacheDir = getContext().getCacheDir();
|
||||
return new File(cacheDir, filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* After processing the image, return the final result back to the caller.
|
||||
* @param call
|
||||
* @param bitmap
|
||||
* @param u
|
||||
*/
|
||||
@SuppressWarnings("deprecation")
|
||||
private void returnResult(PluginCall call, Bitmap bitmap, Uri u) {
|
||||
ExifWrapper exif = ImageUtils.getExifData(getContext(), bitmap, u);
|
||||
try {
|
||||
bitmap = prepareBitmap(bitmap, u, exif);
|
||||
} catch (IOException e) {
|
||||
call.reject(UNABLE_TO_PROCESS_IMAGE);
|
||||
return;
|
||||
}
|
||||
// Compress the final image and prepare for output to client
|
||||
ByteArrayOutputStream bitmapOutputStream = new ByteArrayOutputStream();
|
||||
bitmap.compress(Bitmap.CompressFormat.JPEG, settings.getQuality(), bitmapOutputStream);
|
||||
|
||||
if (settings.isAllowEditing() && !isEdited) {
|
||||
editImage(call, u, bitmapOutputStream);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean saveToGallery = call.getBoolean("saveToGallery", CameraSettings.DEFAULT_SAVE_IMAGE_TO_GALLERY);
|
||||
if (saveToGallery && (imageEditedFileSavePath != null || imageFileSavePath != null)) {
|
||||
isSaved = true;
|
||||
try {
|
||||
String fileToSavePath = imageEditedFileSavePath != null ? imageEditedFileSavePath : imageFileSavePath;
|
||||
File fileToSave = new File(fileToSavePath);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
ContentResolver resolver = getContext().getContentResolver();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(MediaStore.MediaColumns.DISPLAY_NAME, fileToSave.getName());
|
||||
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
|
||||
values.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_DCIM);
|
||||
|
||||
final Uri contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
Uri uri = resolver.insert(contentUri, values);
|
||||
|
||||
if (uri == null) {
|
||||
throw new IOException("Failed to create new MediaStore record.");
|
||||
}
|
||||
|
||||
OutputStream stream = resolver.openOutputStream(uri);
|
||||
if (stream == null) {
|
||||
throw new IOException("Failed to open output stream.");
|
||||
}
|
||||
|
||||
Boolean inserted = bitmap.compress(Bitmap.CompressFormat.JPEG, settings.getQuality(), stream);
|
||||
|
||||
if (!inserted) {
|
||||
isSaved = false;
|
||||
}
|
||||
} else {
|
||||
String inserted = MediaStore.Images.Media.insertImage(
|
||||
getContext().getContentResolver(),
|
||||
fileToSavePath,
|
||||
fileToSave.getName(),
|
||||
""
|
||||
);
|
||||
|
||||
if (inserted == null) {
|
||||
isSaved = false;
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException e) {
|
||||
isSaved = false;
|
||||
Logger.error(getLogTag(), IMAGE_GALLERY_SAVE_ERROR, e);
|
||||
} catch (IOException e) {
|
||||
isSaved = false;
|
||||
Logger.error(getLogTag(), IMAGE_GALLERY_SAVE_ERROR, e);
|
||||
}
|
||||
}
|
||||
|
||||
if (settings.getResultType() == CameraResultType.BASE64) {
|
||||
returnBase64(call, exif, bitmapOutputStream);
|
||||
} else if (settings.getResultType() == CameraResultType.URI) {
|
||||
returnFileURI(call, exif, bitmap, u, bitmapOutputStream);
|
||||
} else if (settings.getResultType() == CameraResultType.DATAURL) {
|
||||
returnDataUrl(call, exif, bitmapOutputStream);
|
||||
} else {
|
||||
call.reject(INVALID_RESULT_TYPE_ERROR);
|
||||
}
|
||||
// Result returned, clear stored paths and images
|
||||
if (settings.getResultType() != CameraResultType.URI) {
|
||||
deleteImageFile();
|
||||
}
|
||||
imageFileSavePath = null;
|
||||
imageFileUri = null;
|
||||
imagePickedContentUri = null;
|
||||
imageEditedFileSavePath = null;
|
||||
}
|
||||
|
||||
private void deleteImageFile() {
|
||||
if (imageFileSavePath != null && !settings.isSaveToGallery()) {
|
||||
File photoFile = new File(imageFileSavePath);
|
||||
if (photoFile.exists()) {
|
||||
photoFile.delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void returnFileURI(PluginCall call, ExifWrapper exif, Bitmap bitmap, Uri u, ByteArrayOutputStream bitmapOutputStream) {
|
||||
Uri newUri = getTempImage(u, bitmapOutputStream);
|
||||
exif.copyExif(newUri.getPath());
|
||||
if (newUri != null) {
|
||||
JSObject ret = new JSObject();
|
||||
ret.put("format", "jpeg");
|
||||
ret.put("exif", exif.toJson());
|
||||
ret.put("path", newUri.toString());
|
||||
ret.put("webPath", FileUtils.getPortablePath(getContext(), bridge.getLocalUrl(), newUri));
|
||||
ret.put("saved", isSaved);
|
||||
call.resolve(ret);
|
||||
} else {
|
||||
call.reject(UNABLE_TO_PROCESS_IMAGE);
|
||||
}
|
||||
}
|
||||
|
||||
private Uri getTempImage(Uri u, ByteArrayOutputStream bitmapOutputStream) {
|
||||
ByteArrayInputStream bis = null;
|
||||
Uri newUri = null;
|
||||
try {
|
||||
bis = new ByteArrayInputStream(bitmapOutputStream.toByteArray());
|
||||
newUri = saveImage(u, bis);
|
||||
} catch (IOException ex) {} finally {
|
||||
if (bis != null) {
|
||||
try {
|
||||
bis.close();
|
||||
} catch (IOException e) {
|
||||
Logger.error(getLogTag(), UNABLE_TO_PROCESS_IMAGE, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
return newUri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply our standard processing of the bitmap, returning a new one and
|
||||
* recycling the old one in the process
|
||||
* @param bitmap
|
||||
* @param imageUri
|
||||
* @param exif
|
||||
* @return
|
||||
*/
|
||||
private Bitmap prepareBitmap(Bitmap bitmap, Uri imageUri, ExifWrapper exif) throws IOException {
|
||||
if (settings.isShouldCorrectOrientation()) {
|
||||
final Bitmap newBitmap = ImageUtils.correctOrientation(getContext(), bitmap, imageUri, exif);
|
||||
bitmap = replaceBitmap(bitmap, newBitmap);
|
||||
}
|
||||
|
||||
if (settings.isShouldResize()) {
|
||||
final Bitmap newBitmap = ImageUtils.resize(bitmap, settings.getWidth(), settings.getHeight());
|
||||
bitmap = replaceBitmap(bitmap, newBitmap);
|
||||
}
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private Bitmap replaceBitmap(Bitmap bitmap, final Bitmap newBitmap) {
|
||||
if (bitmap != newBitmap) {
|
||||
bitmap.recycle();
|
||||
}
|
||||
bitmap = newBitmap;
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
private void returnDataUrl(PluginCall call, ExifWrapper exif, ByteArrayOutputStream bitmapOutputStream) {
|
||||
byte[] byteArray = bitmapOutputStream.toByteArray();
|
||||
String encoded = Base64.encodeToString(byteArray, Base64.NO_WRAP);
|
||||
|
||||
JSObject data = new JSObject();
|
||||
data.put("format", "jpeg");
|
||||
data.put("dataUrl", "data:image/jpeg;base64," + encoded);
|
||||
data.put("exif", exif.toJson());
|
||||
call.resolve(data);
|
||||
}
|
||||
|
||||
private void returnBase64(PluginCall call, ExifWrapper exif, ByteArrayOutputStream bitmapOutputStream) {
|
||||
byte[] byteArray = bitmapOutputStream.toByteArray();
|
||||
String encoded = Base64.encodeToString(byteArray, Base64.NO_WRAP);
|
||||
|
||||
JSObject data = new JSObject();
|
||||
data.put("format", "jpeg");
|
||||
data.put("base64String", encoded);
|
||||
data.put("exif", exif.toJson());
|
||||
call.resolve(data);
|
||||
}
|
||||
|
||||
@Override
|
||||
@PluginMethod
|
||||
public void requestPermissions(PluginCall call) {
|
||||
// If the camera permission is defined in the manifest, then we have to prompt the user
|
||||
// or else we will get a security exception when trying to present the camera. If, however,
|
||||
// it is not defined in the manifest then we don't need to prompt and it will just work.
|
||||
if (isPermissionDeclared(CAMERA)) {
|
||||
// just request normally
|
||||
super.requestPermissions(call);
|
||||
} else {
|
||||
// the manifest does not define camera permissions, so we need to decide what to do
|
||||
// first, extract the permissions being requested
|
||||
JSArray providedPerms = call.getArray("permissions");
|
||||
List<String> permsList = null;
|
||||
if (providedPerms != null) {
|
||||
try {
|
||||
permsList = providedPerms.toList();
|
||||
} catch (JSONException e) {}
|
||||
}
|
||||
|
||||
if (
|
||||
Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU ||
|
||||
(permsList != null && permsList.size() == 1 && (permsList.contains(CAMERA) || permsList.contains(PHOTOS)))
|
||||
) {
|
||||
// either we're on Android 13+ (storage permissions do not apply)
|
||||
// or the only thing being asked for was the camera so we can just return the current state
|
||||
checkPermissions(call);
|
||||
} else {
|
||||
requestPermissionForAlias(SAVE_GALLERY, call, "checkPermissions");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Map<String, PermissionState> getPermissionStates() {
|
||||
Map<String, PermissionState> permissionStates = super.getPermissionStates();
|
||||
|
||||
// If Camera is not in the manifest and therefore not required, say the permission is granted
|
||||
if (!isPermissionDeclared(CAMERA)) {
|
||||
permissionStates.put(CAMERA, PermissionState.GRANTED);
|
||||
}
|
||||
|
||||
if (permissionStates.containsKey(PHOTOS)) {
|
||||
permissionStates.put(PHOTOS, PermissionState.GRANTED);
|
||||
}
|
||||
|
||||
// If the SDK version is 30 or higher, update the SAVE_GALLERY state to match the READ_EXTERNAL_STORAGE state.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
|
||||
String alias = READ_EXTERNAL_STORAGE;
|
||||
if (permissionStates.containsKey(alias)) {
|
||||
permissionStates.put(SAVE_GALLERY, permissionStates.get(alias));
|
||||
}
|
||||
}
|
||||
|
||||
return permissionStates;
|
||||
}
|
||||
|
||||
private void editImage(PluginCall call, Uri uri, ByteArrayOutputStream bitmapOutputStream) {
|
||||
try {
|
||||
Uri tempImage = getTempImage(uri, bitmapOutputStream);
|
||||
Intent editIntent = createEditIntent(tempImage);
|
||||
if (editIntent != null) {
|
||||
startActivityForResult(call, editIntent, "processEditedImage");
|
||||
} else {
|
||||
call.reject(IMAGE_EDIT_ERROR);
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
call.reject(IMAGE_EDIT_ERROR, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private Intent createEditIntent(Uri origPhotoUri) {
|
||||
try {
|
||||
File editFile = new File(origPhotoUri.getPath());
|
||||
Uri editUri = FileProvider.getUriForFile(getActivity(), getContext().getPackageName() + ".fileprovider", editFile);
|
||||
Intent editIntent = new Intent(Intent.ACTION_EDIT);
|
||||
editIntent.setDataAndType(editUri, "image/*");
|
||||
imageEditedFileSavePath = editFile.getAbsolutePath();
|
||||
int flags = Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
|
||||
editIntent.addFlags(flags);
|
||||
editIntent.putExtra(MediaStore.EXTRA_OUTPUT, editUri);
|
||||
|
||||
List<ResolveInfo> resInfoList;
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
resInfoList =
|
||||
getContext()
|
||||
.getPackageManager()
|
||||
.queryIntentActivities(editIntent, PackageManager.ResolveInfoFlags.of(PackageManager.MATCH_DEFAULT_ONLY));
|
||||
} else {
|
||||
resInfoList = legacyQueryIntentActivities(editIntent);
|
||||
}
|
||||
|
||||
for (ResolveInfo resolveInfo : resInfoList) {
|
||||
String packageName = resolveInfo.activityInfo.packageName;
|
||||
getContext().grantUriPermission(packageName, editUri, flags);
|
||||
}
|
||||
return editIntent;
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private List<ResolveInfo> legacyQueryIntentActivities(Intent intent) {
|
||||
return getContext().getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Bundle saveInstanceState() {
|
||||
Bundle bundle = super.saveInstanceState();
|
||||
if (bundle != null) {
|
||||
bundle.putString("cameraImageFileSavePath", imageFileSavePath);
|
||||
}
|
||||
return bundle;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void restoreState(Bundle state) {
|
||||
String storedImageFileSavePath = state.getString("cameraImageFileSavePath");
|
||||
if (storedImageFileSavePath != null) {
|
||||
imageFileSavePath = storedImageFileSavePath;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister activity result launches to prevent leaks.
|
||||
*/
|
||||
@Override
|
||||
protected void handleOnDestroy() {
|
||||
if (pickMedia != null) {
|
||||
pickMedia.unregister();
|
||||
}
|
||||
if (pickMultipleMedia != null) {
|
||||
pickMultipleMedia.unregister();
|
||||
}
|
||||
}
|
||||
}
|
||||
17
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraResultType.java
generated
vendored
Normal file
17
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraResultType.java
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.capacitorjs.plugins.camera;
|
||||
|
||||
public enum CameraResultType {
|
||||
BASE64("base64"),
|
||||
URI("uri"),
|
||||
DATAURL("dataUrl");
|
||||
|
||||
private String type;
|
||||
|
||||
CameraResultType(String type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
90
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraSettings.java
generated
vendored
Normal file
90
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraSettings.java
generated
vendored
Normal file
@@ -0,0 +1,90 @@
|
||||
package com.capacitorjs.plugins.camera;
|
||||
|
||||
public class CameraSettings {
|
||||
|
||||
public static final int DEFAULT_QUALITY = 90;
|
||||
public static final boolean DEFAULT_SAVE_IMAGE_TO_GALLERY = false;
|
||||
public static final boolean DEFAULT_CORRECT_ORIENTATION = true;
|
||||
|
||||
private CameraResultType resultType = CameraResultType.BASE64;
|
||||
private int quality = DEFAULT_QUALITY;
|
||||
private boolean shouldResize = false;
|
||||
private boolean shouldCorrectOrientation = DEFAULT_CORRECT_ORIENTATION;
|
||||
private boolean saveToGallery = DEFAULT_SAVE_IMAGE_TO_GALLERY;
|
||||
private boolean allowEditing = false;
|
||||
private int width = 0;
|
||||
private int height = 0;
|
||||
private CameraSource source = CameraSource.PROMPT;
|
||||
|
||||
public CameraResultType getResultType() {
|
||||
return resultType;
|
||||
}
|
||||
|
||||
public void setResultType(CameraResultType resultType) {
|
||||
this.resultType = resultType;
|
||||
}
|
||||
|
||||
public int getQuality() {
|
||||
return quality;
|
||||
}
|
||||
|
||||
public void setQuality(int quality) {
|
||||
this.quality = quality;
|
||||
}
|
||||
|
||||
public boolean isShouldResize() {
|
||||
return shouldResize;
|
||||
}
|
||||
|
||||
public void setShouldResize(boolean shouldResize) {
|
||||
this.shouldResize = shouldResize;
|
||||
}
|
||||
|
||||
public boolean isShouldCorrectOrientation() {
|
||||
return shouldCorrectOrientation;
|
||||
}
|
||||
|
||||
public void setShouldCorrectOrientation(boolean shouldCorrectOrientation) {
|
||||
this.shouldCorrectOrientation = shouldCorrectOrientation;
|
||||
}
|
||||
|
||||
public boolean isSaveToGallery() {
|
||||
return saveToGallery;
|
||||
}
|
||||
|
||||
public void setSaveToGallery(boolean saveToGallery) {
|
||||
this.saveToGallery = saveToGallery;
|
||||
}
|
||||
|
||||
public boolean isAllowEditing() {
|
||||
return allowEditing;
|
||||
}
|
||||
|
||||
public void setAllowEditing(boolean allowEditing) {
|
||||
this.allowEditing = allowEditing;
|
||||
}
|
||||
|
||||
public int getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
public void setWidth(int width) {
|
||||
this.width = width;
|
||||
}
|
||||
|
||||
public int getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
public void setHeight(int height) {
|
||||
this.height = height;
|
||||
}
|
||||
|
||||
public CameraSource getSource() {
|
||||
return source;
|
||||
}
|
||||
|
||||
public void setSource(CameraSource source) {
|
||||
this.source = source;
|
||||
}
|
||||
}
|
||||
17
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraSource.java
generated
vendored
Normal file
17
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraSource.java
generated
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
package com.capacitorjs.plugins.camera;
|
||||
|
||||
public enum CameraSource {
|
||||
PROMPT("PROMPT"),
|
||||
CAMERA("CAMERA"),
|
||||
PHOTOS("PHOTOS");
|
||||
|
||||
private String source;
|
||||
|
||||
CameraSource(String source) {
|
||||
this.source = source;
|
||||
}
|
||||
|
||||
public String getSource() {
|
||||
return this.source;
|
||||
}
|
||||
}
|
||||
34
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraUtils.java
generated
vendored
Normal file
34
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/CameraUtils.java
generated
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
package com.capacitorjs.plugins.camera;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.net.Uri;
|
||||
import android.os.Environment;
|
||||
import androidx.core.content.FileProvider;
|
||||
import com.getcapacitor.Logger;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
|
||||
public class CameraUtils {
|
||||
|
||||
public static Uri createImageFileUri(Activity activity, String appId) throws IOException {
|
||||
File photoFile = CameraUtils.createImageFile(activity);
|
||||
return FileProvider.getUriForFile(activity, appId + ".fileprovider", photoFile);
|
||||
}
|
||||
|
||||
public static File createImageFile(Activity activity) throws IOException {
|
||||
// Create an image file name
|
||||
String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
|
||||
String imageFileName = "JPEG_" + timeStamp + "_";
|
||||
File storageDir = activity.getExternalFilesDir(Environment.DIRECTORY_PICTURES);
|
||||
|
||||
File image = File.createTempFile(imageFileName, /* prefix */".jpg", /* suffix */storageDir/* directory */);
|
||||
|
||||
return image;
|
||||
}
|
||||
|
||||
protected static String getLogTag() {
|
||||
return Logger.tags("CameraUtils");
|
||||
}
|
||||
}
|
||||
205
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/ExifWrapper.java
generated
vendored
Normal file
205
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/ExifWrapper.java
generated
vendored
Normal file
@@ -0,0 +1,205 @@
|
||||
package com.capacitorjs.plugins.camera;
|
||||
|
||||
import static androidx.exifinterface.media.ExifInterface.*;
|
||||
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import com.getcapacitor.JSObject;
|
||||
|
||||
public class ExifWrapper {
|
||||
|
||||
private final ExifInterface exif;
|
||||
private final String[] attributes = new String[] {
|
||||
TAG_APERTURE_VALUE,
|
||||
TAG_ARTIST,
|
||||
TAG_BITS_PER_SAMPLE,
|
||||
TAG_BODY_SERIAL_NUMBER,
|
||||
TAG_BRIGHTNESS_VALUE,
|
||||
TAG_CAMERA_OWNER_NAME,
|
||||
TAG_CFA_PATTERN,
|
||||
TAG_COLOR_SPACE,
|
||||
TAG_COMPONENTS_CONFIGURATION,
|
||||
TAG_COMPRESSED_BITS_PER_PIXEL,
|
||||
TAG_COMPRESSION,
|
||||
TAG_CONTRAST,
|
||||
TAG_COPYRIGHT,
|
||||
TAG_CUSTOM_RENDERED,
|
||||
TAG_DATETIME,
|
||||
TAG_DATETIME_DIGITIZED,
|
||||
TAG_DATETIME_ORIGINAL,
|
||||
TAG_DEFAULT_CROP_SIZE,
|
||||
TAG_DEVICE_SETTING_DESCRIPTION,
|
||||
TAG_DIGITAL_ZOOM_RATIO,
|
||||
TAG_DNG_VERSION,
|
||||
TAG_EXIF_VERSION,
|
||||
TAG_EXPOSURE_BIAS_VALUE,
|
||||
TAG_EXPOSURE_INDEX,
|
||||
TAG_EXPOSURE_MODE,
|
||||
TAG_EXPOSURE_PROGRAM,
|
||||
TAG_EXPOSURE_TIME,
|
||||
TAG_FILE_SOURCE,
|
||||
TAG_FLASH,
|
||||
TAG_FLASHPIX_VERSION,
|
||||
TAG_FLASH_ENERGY,
|
||||
TAG_FOCAL_LENGTH,
|
||||
TAG_FOCAL_LENGTH_IN_35MM_FILM,
|
||||
TAG_FOCAL_PLANE_RESOLUTION_UNIT,
|
||||
TAG_FOCAL_PLANE_X_RESOLUTION,
|
||||
TAG_FOCAL_PLANE_Y_RESOLUTION,
|
||||
TAG_F_NUMBER,
|
||||
TAG_GAIN_CONTROL,
|
||||
TAG_GAMMA,
|
||||
TAG_GPS_ALTITUDE,
|
||||
TAG_GPS_ALTITUDE_REF,
|
||||
TAG_GPS_AREA_INFORMATION,
|
||||
TAG_GPS_DATESTAMP,
|
||||
TAG_GPS_DEST_BEARING,
|
||||
TAG_GPS_DEST_BEARING_REF,
|
||||
TAG_GPS_DEST_DISTANCE,
|
||||
TAG_GPS_DEST_DISTANCE_REF,
|
||||
TAG_GPS_DEST_LATITUDE,
|
||||
TAG_GPS_DEST_LATITUDE_REF,
|
||||
TAG_GPS_DEST_LONGITUDE,
|
||||
TAG_GPS_DEST_LONGITUDE_REF,
|
||||
TAG_GPS_DIFFERENTIAL,
|
||||
TAG_GPS_DOP,
|
||||
TAG_GPS_H_POSITIONING_ERROR,
|
||||
TAG_GPS_IMG_DIRECTION,
|
||||
TAG_GPS_IMG_DIRECTION_REF,
|
||||
TAG_GPS_LATITUDE,
|
||||
TAG_GPS_LATITUDE_REF,
|
||||
TAG_GPS_LONGITUDE,
|
||||
TAG_GPS_LONGITUDE_REF,
|
||||
TAG_GPS_MAP_DATUM,
|
||||
TAG_GPS_MEASURE_MODE,
|
||||
TAG_GPS_PROCESSING_METHOD,
|
||||
TAG_GPS_SATELLITES,
|
||||
TAG_GPS_SPEED,
|
||||
TAG_GPS_SPEED_REF,
|
||||
TAG_GPS_STATUS,
|
||||
TAG_GPS_TIMESTAMP,
|
||||
TAG_GPS_TRACK,
|
||||
TAG_GPS_TRACK_REF,
|
||||
TAG_GPS_VERSION_ID,
|
||||
TAG_IMAGE_DESCRIPTION,
|
||||
TAG_IMAGE_LENGTH,
|
||||
TAG_IMAGE_UNIQUE_ID,
|
||||
TAG_IMAGE_WIDTH,
|
||||
TAG_INTEROPERABILITY_INDEX,
|
||||
TAG_ISO_SPEED,
|
||||
TAG_ISO_SPEED_LATITUDE_YYY,
|
||||
TAG_ISO_SPEED_LATITUDE_ZZZ,
|
||||
TAG_JPEG_INTERCHANGE_FORMAT,
|
||||
TAG_JPEG_INTERCHANGE_FORMAT_LENGTH,
|
||||
TAG_LENS_MAKE,
|
||||
TAG_LENS_MODEL,
|
||||
TAG_LENS_SERIAL_NUMBER,
|
||||
TAG_LENS_SPECIFICATION,
|
||||
TAG_LIGHT_SOURCE,
|
||||
TAG_MAKE,
|
||||
TAG_MAKER_NOTE,
|
||||
TAG_MAX_APERTURE_VALUE,
|
||||
TAG_METERING_MODE,
|
||||
TAG_MODEL,
|
||||
TAG_NEW_SUBFILE_TYPE,
|
||||
TAG_OECF,
|
||||
TAG_OFFSET_TIME,
|
||||
TAG_OFFSET_TIME_DIGITIZED,
|
||||
TAG_OFFSET_TIME_ORIGINAL,
|
||||
TAG_ORF_ASPECT_FRAME,
|
||||
TAG_ORF_PREVIEW_IMAGE_LENGTH,
|
||||
TAG_ORF_PREVIEW_IMAGE_START,
|
||||
TAG_ORF_THUMBNAIL_IMAGE,
|
||||
TAG_ORIENTATION,
|
||||
TAG_PHOTOGRAPHIC_SENSITIVITY,
|
||||
TAG_PHOTOMETRIC_INTERPRETATION,
|
||||
TAG_PIXEL_X_DIMENSION,
|
||||
TAG_PIXEL_Y_DIMENSION,
|
||||
TAG_PLANAR_CONFIGURATION,
|
||||
TAG_PRIMARY_CHROMATICITIES,
|
||||
TAG_RECOMMENDED_EXPOSURE_INDEX,
|
||||
TAG_REFERENCE_BLACK_WHITE,
|
||||
TAG_RELATED_SOUND_FILE,
|
||||
TAG_RESOLUTION_UNIT,
|
||||
TAG_ROWS_PER_STRIP,
|
||||
TAG_RW2_ISO,
|
||||
TAG_RW2_JPG_FROM_RAW,
|
||||
TAG_RW2_SENSOR_BOTTOM_BORDER,
|
||||
TAG_RW2_SENSOR_LEFT_BORDER,
|
||||
TAG_RW2_SENSOR_RIGHT_BORDER,
|
||||
TAG_RW2_SENSOR_TOP_BORDER,
|
||||
TAG_SAMPLES_PER_PIXEL,
|
||||
TAG_SATURATION,
|
||||
TAG_SCENE_CAPTURE_TYPE,
|
||||
TAG_SCENE_TYPE,
|
||||
TAG_SENSING_METHOD,
|
||||
TAG_SENSITIVITY_TYPE,
|
||||
TAG_SHARPNESS,
|
||||
TAG_SHUTTER_SPEED_VALUE,
|
||||
TAG_SOFTWARE,
|
||||
TAG_SPATIAL_FREQUENCY_RESPONSE,
|
||||
TAG_SPECTRAL_SENSITIVITY,
|
||||
TAG_STANDARD_OUTPUT_SENSITIVITY,
|
||||
TAG_STRIP_BYTE_COUNTS,
|
||||
TAG_STRIP_OFFSETS,
|
||||
TAG_SUBFILE_TYPE,
|
||||
TAG_SUBJECT_AREA,
|
||||
TAG_SUBJECT_DISTANCE,
|
||||
TAG_SUBJECT_DISTANCE_RANGE,
|
||||
TAG_SUBJECT_LOCATION,
|
||||
TAG_SUBSEC_TIME,
|
||||
TAG_SUBSEC_TIME_DIGITIZED,
|
||||
TAG_SUBSEC_TIME_ORIGINAL,
|
||||
TAG_THUMBNAIL_IMAGE_LENGTH,
|
||||
TAG_THUMBNAIL_IMAGE_WIDTH,
|
||||
TAG_TRANSFER_FUNCTION,
|
||||
TAG_USER_COMMENT,
|
||||
TAG_WHITE_BALANCE,
|
||||
TAG_WHITE_POINT,
|
||||
TAG_XMP,
|
||||
TAG_X_RESOLUTION,
|
||||
TAG_Y_CB_CR_COEFFICIENTS,
|
||||
TAG_Y_CB_CR_POSITIONING,
|
||||
TAG_Y_CB_CR_SUB_SAMPLING,
|
||||
TAG_Y_RESOLUTION
|
||||
};
|
||||
|
||||
public ExifWrapper(ExifInterface exif) {
|
||||
this.exif = exif;
|
||||
}
|
||||
|
||||
public JSObject toJson() {
|
||||
JSObject ret = new JSObject();
|
||||
|
||||
if (this.exif == null) {
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (int i = 0; i < attributes.length; i++) {
|
||||
p(ret, attributes[i]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
public void p(JSObject o, String tag) {
|
||||
String val = exif.getAttribute(tag);
|
||||
o.put(tag, val);
|
||||
}
|
||||
|
||||
public void copyExif(String destFile) {
|
||||
try {
|
||||
ExifInterface destExif = new ExifInterface(destFile);
|
||||
for (int i = 0; i < attributes.length; i++) {
|
||||
String value = exif.getAttribute(attributes[i]);
|
||||
if (value != null) {
|
||||
destExif.setAttribute(attributes[i], value);
|
||||
}
|
||||
}
|
||||
destExif.saveAttributes();
|
||||
} catch (Exception ex) {}
|
||||
}
|
||||
|
||||
public void resetOrientation() {
|
||||
exif.resetOrientation();
|
||||
}
|
||||
}
|
||||
124
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/ImageUtils.java
generated
vendored
Normal file
124
node_modules/@capacitor/camera/android/src/main/java/com/capacitorjs/plugins/camera/ImageUtils.java
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
package com.capacitorjs.plugins.camera;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Matrix;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.provider.MediaStore;
|
||||
import androidx.exifinterface.media.ExifInterface;
|
||||
import com.getcapacitor.Logger;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
|
||||
public class ImageUtils {
|
||||
|
||||
/**
|
||||
* Resize an image to the given max width and max height. Constraint can be put
|
||||
* on one dimension, or both. Resize will always preserve aspect ratio.
|
||||
* @param bitmap
|
||||
* @param desiredMaxWidth
|
||||
* @param desiredMaxHeight
|
||||
* @return a new, scaled Bitmap
|
||||
*/
|
||||
public static Bitmap resize(Bitmap bitmap, final int desiredMaxWidth, final int desiredMaxHeight) {
|
||||
return ImageUtils.resizePreservingAspectRatio(bitmap, desiredMaxWidth, desiredMaxHeight);
|
||||
}
|
||||
|
||||
/**
|
||||
* Resize an image to the given max width and max height. Constraint can be put
|
||||
* on one dimension, or both. Resize will always preserve aspect ratio.
|
||||
* @param bitmap
|
||||
* @param desiredMaxWidth
|
||||
* @param desiredMaxHeight
|
||||
* @return a new, scaled Bitmap
|
||||
*/
|
||||
private static Bitmap resizePreservingAspectRatio(Bitmap bitmap, final int desiredMaxWidth, final int desiredMaxHeight) {
|
||||
int width = bitmap.getWidth();
|
||||
int height = bitmap.getHeight();
|
||||
|
||||
// 0 is treated as 'no restriction'
|
||||
int maxHeight = desiredMaxHeight == 0 ? height : desiredMaxHeight;
|
||||
int maxWidth = desiredMaxWidth == 0 ? width : desiredMaxWidth;
|
||||
|
||||
// resize with preserved aspect ratio
|
||||
float newWidth = Math.min(width, maxWidth);
|
||||
float newHeight = (height * newWidth) / width;
|
||||
|
||||
if (newHeight > maxHeight) {
|
||||
newWidth = (width * maxHeight) / height;
|
||||
newHeight = maxHeight;
|
||||
}
|
||||
return Bitmap.createScaledBitmap(bitmap, Math.round(newWidth), Math.round(newHeight), false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform an image with the given matrix
|
||||
* @param bitmap
|
||||
* @param matrix
|
||||
* @return
|
||||
*/
|
||||
private static Bitmap transform(final Bitmap bitmap, final Matrix matrix) {
|
||||
return Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Correct the orientation of an image by reading its exif information and rotating
|
||||
* the appropriate amount for portrait mode
|
||||
* @param bitmap
|
||||
* @param imageUri
|
||||
* @param exif
|
||||
* @return
|
||||
*/
|
||||
public static Bitmap correctOrientation(final Context c, final Bitmap bitmap, final Uri imageUri, ExifWrapper exif) throws IOException {
|
||||
final int orientation = getOrientation(c, imageUri);
|
||||
if (orientation != 0) {
|
||||
Matrix matrix = new Matrix();
|
||||
matrix.postRotate(orientation);
|
||||
exif.resetOrientation();
|
||||
return transform(bitmap, matrix);
|
||||
} else {
|
||||
return bitmap;
|
||||
}
|
||||
}
|
||||
|
||||
private static int getOrientation(final Context c, final Uri imageUri) throws IOException {
|
||||
int result = 0;
|
||||
|
||||
try (InputStream iStream = c.getContentResolver().openInputStream(imageUri)) {
|
||||
final ExifInterface exifInterface = new ExifInterface(iStream);
|
||||
|
||||
final int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
|
||||
|
||||
if (orientation == ExifInterface.ORIENTATION_ROTATE_90) {
|
||||
result = 90;
|
||||
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_180) {
|
||||
result = 180;
|
||||
} else if (orientation == ExifInterface.ORIENTATION_ROTATE_270) {
|
||||
result = 270;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public static ExifWrapper getExifData(final Context c, final Bitmap bitmap, final Uri imageUri) {
|
||||
InputStream stream = null;
|
||||
try {
|
||||
stream = c.getContentResolver().openInputStream(imageUri);
|
||||
final ExifInterface exifInterface = new ExifInterface(stream);
|
||||
|
||||
return new ExifWrapper(exifInterface);
|
||||
} catch (IOException ex) {
|
||||
Logger.error("Error loading exif data from image", ex);
|
||||
} finally {
|
||||
if (stream != null) {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ignored) {}
|
||||
}
|
||||
}
|
||||
return new ExifWrapper(null);
|
||||
}
|
||||
}
|
||||
804
node_modules/@capacitor/camera/dist/docs.json
generated
vendored
Normal file
804
node_modules/@capacitor/camera/dist/docs.json
generated
vendored
Normal file
@@ -0,0 +1,804 @@
|
||||
{
|
||||
"api": {
|
||||
"name": "CameraPlugin",
|
||||
"slug": "cameraplugin",
|
||||
"docs": "",
|
||||
"tags": [],
|
||||
"methods": [
|
||||
{
|
||||
"name": "getPhoto",
|
||||
"signature": "(options: ImageOptions) => Promise<Photo>",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "options",
|
||||
"docs": "",
|
||||
"type": "ImageOptions"
|
||||
}
|
||||
],
|
||||
"returns": "Promise<Photo>",
|
||||
"tags": [
|
||||
{
|
||||
"name": "since",
|
||||
"text": "1.0.0"
|
||||
}
|
||||
],
|
||||
"docs": "Prompt the user to pick a photo from an album, or take a new photo\nwith the camera.",
|
||||
"complexTypes": [
|
||||
"Photo",
|
||||
"ImageOptions"
|
||||
],
|
||||
"slug": "getphoto"
|
||||
},
|
||||
{
|
||||
"name": "pickImages",
|
||||
"signature": "(options: GalleryImageOptions) => Promise<GalleryPhotos>",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "options",
|
||||
"docs": "",
|
||||
"type": "GalleryImageOptions"
|
||||
}
|
||||
],
|
||||
"returns": "Promise<GalleryPhotos>",
|
||||
"tags": [
|
||||
{
|
||||
"name": "since",
|
||||
"text": "1.2.0"
|
||||
}
|
||||
],
|
||||
"docs": "Allows the user to pick multiple pictures from the photo gallery.\nOn iOS 13 and older it only allows to pick one picture.",
|
||||
"complexTypes": [
|
||||
"GalleryPhotos",
|
||||
"GalleryImageOptions"
|
||||
],
|
||||
"slug": "pickimages"
|
||||
},
|
||||
{
|
||||
"name": "pickLimitedLibraryPhotos",
|
||||
"signature": "() => Promise<GalleryPhotos>",
|
||||
"parameters": [],
|
||||
"returns": "Promise<GalleryPhotos>",
|
||||
"tags": [
|
||||
{
|
||||
"name": "since",
|
||||
"text": "4.1.0"
|
||||
}
|
||||
],
|
||||
"docs": "iOS 14+ Only: Allows the user to update their limited photo library selection.\nOn iOS 15+ returns all the limited photos after the picker dismissal.\nOn iOS 14 or if the user gave full access to the photos it returns an empty array.",
|
||||
"complexTypes": [
|
||||
"GalleryPhotos"
|
||||
],
|
||||
"slug": "picklimitedlibraryphotos"
|
||||
},
|
||||
{
|
||||
"name": "getLimitedLibraryPhotos",
|
||||
"signature": "() => Promise<GalleryPhotos>",
|
||||
"parameters": [],
|
||||
"returns": "Promise<GalleryPhotos>",
|
||||
"tags": [
|
||||
{
|
||||
"name": "since",
|
||||
"text": "4.1.0"
|
||||
}
|
||||
],
|
||||
"docs": "iOS 14+ Only: Return an array of photos selected from the limited photo library.",
|
||||
"complexTypes": [
|
||||
"GalleryPhotos"
|
||||
],
|
||||
"slug": "getlimitedlibraryphotos"
|
||||
},
|
||||
{
|
||||
"name": "checkPermissions",
|
||||
"signature": "() => Promise<PermissionStatus>",
|
||||
"parameters": [],
|
||||
"returns": "Promise<PermissionStatus>",
|
||||
"tags": [
|
||||
{
|
||||
"name": "since",
|
||||
"text": "1.0.0"
|
||||
}
|
||||
],
|
||||
"docs": "Check camera and photo album permissions",
|
||||
"complexTypes": [
|
||||
"PermissionStatus"
|
||||
],
|
||||
"slug": "checkpermissions"
|
||||
},
|
||||
{
|
||||
"name": "requestPermissions",
|
||||
"signature": "(permissions?: CameraPluginPermissions | undefined) => Promise<PermissionStatus>",
|
||||
"parameters": [
|
||||
{
|
||||
"name": "permissions",
|
||||
"docs": "",
|
||||
"type": "CameraPluginPermissions | undefined"
|
||||
}
|
||||
],
|
||||
"returns": "Promise<PermissionStatus>",
|
||||
"tags": [
|
||||
{
|
||||
"name": "since",
|
||||
"text": "1.0.0"
|
||||
}
|
||||
],
|
||||
"docs": "Request camera and photo album permissions",
|
||||
"complexTypes": [
|
||||
"PermissionStatus",
|
||||
"CameraPluginPermissions"
|
||||
],
|
||||
"slug": "requestpermissions"
|
||||
}
|
||||
],
|
||||
"properties": []
|
||||
},
|
||||
"interfaces": [
|
||||
{
|
||||
"name": "Photo",
|
||||
"slug": "photo",
|
||||
"docs": "",
|
||||
"tags": [],
|
||||
"methods": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "base64String",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The base64 encoded string representation of the image, if using CameraResultType.Base64.",
|
||||
"complexTypes": [],
|
||||
"type": "string | undefined"
|
||||
},
|
||||
{
|
||||
"name": "dataUrl",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The url starting with 'data:image/jpeg;base64,' and the base64 encoded string representation of the image, if using CameraResultType.DataUrl.\n\nNote: On web, the file format could change depending on the browser.",
|
||||
"complexTypes": [],
|
||||
"type": "string | undefined"
|
||||
},
|
||||
{
|
||||
"name": "path",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "If using CameraResultType.Uri, the path will contain a full,\nplatform-specific file URL that can be read later using the Filesystem API.",
|
||||
"complexTypes": [],
|
||||
"type": "string | undefined"
|
||||
},
|
||||
{
|
||||
"name": "webPath",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "webPath returns a path that can be used to set the src attribute of an image for efficient\nloading and rendering.",
|
||||
"complexTypes": [],
|
||||
"type": "string | undefined"
|
||||
},
|
||||
{
|
||||
"name": "exif",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Exif data, if any, retrieved from the image",
|
||||
"complexTypes": [],
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The format of the image, ex: jpeg, png, gif.\n\niOS and Android only support jpeg.\nWeb supports jpeg, png and gif, but the exact availability may vary depending on the browser.\ngif is only supported if `webUseInput` is set to `true` or if `source` is set to `Photos`.",
|
||||
"complexTypes": [],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "saved",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.1.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Whether if the image was saved to the gallery or not.\n\nOn Android and iOS, saving to the gallery can fail if the user didn't\ngrant the required permissions.\nOn Web there is no gallery, so always returns false.",
|
||||
"complexTypes": [],
|
||||
"type": "boolean"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "ImageOptions",
|
||||
"slug": "imageoptions",
|
||||
"docs": "",
|
||||
"tags": [],
|
||||
"methods": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "quality",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The quality of image to return as JPEG, from 0-100\nNote: This option is only supported on Android and iOS",
|
||||
"complexTypes": [],
|
||||
"type": "number | undefined"
|
||||
},
|
||||
{
|
||||
"name": "allowEditing",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Whether to allow the user to crop or make small edits (platform specific).\nOn iOS 14+ it's only supported for CameraSource.Camera, but not for CameraSource.Photos.",
|
||||
"complexTypes": [],
|
||||
"type": "boolean | undefined"
|
||||
},
|
||||
{
|
||||
"name": "resultType",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "How the data should be returned. Currently, only 'Base64', 'DataUrl' or 'Uri' is supported",
|
||||
"complexTypes": [
|
||||
"CameraResultType"
|
||||
],
|
||||
"type": "CameraResultType"
|
||||
},
|
||||
{
|
||||
"name": "saveToGallery",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": false",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Whether to save the photo to the gallery.\nIf the photo was picked from the gallery, it will only be saved if edited.",
|
||||
"complexTypes": [],
|
||||
"type": "boolean | undefined"
|
||||
},
|
||||
{
|
||||
"name": "width",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The desired maximum width of the saved image. The aspect ratio is respected.",
|
||||
"complexTypes": [],
|
||||
"type": "number | undefined"
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The desired maximum height of the saved image. The aspect ratio is respected.",
|
||||
"complexTypes": [],
|
||||
"type": "number | undefined"
|
||||
},
|
||||
{
|
||||
"name": "correctOrientation",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": true",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Whether to automatically rotate the image \"up\" to correct for orientation\nin portrait mode",
|
||||
"complexTypes": [],
|
||||
"type": "boolean | undefined"
|
||||
},
|
||||
{
|
||||
"name": "source",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": CameraSource.Prompt",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The source to get the photo from. By default this prompts the user to select\neither the photo album or take a photo.",
|
||||
"complexTypes": [
|
||||
"CameraSource"
|
||||
],
|
||||
"type": "CameraSource"
|
||||
},
|
||||
{
|
||||
"name": "direction",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": CameraDirection.Rear",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "iOS and Web only: The camera direction.",
|
||||
"complexTypes": [
|
||||
"CameraDirection"
|
||||
],
|
||||
"type": "CameraDirection"
|
||||
},
|
||||
{
|
||||
"name": "presentationStyle",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": 'fullscreen'",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "iOS only: The presentation style of the Camera.",
|
||||
"complexTypes": [],
|
||||
"type": "'fullscreen' | 'popover' | undefined"
|
||||
},
|
||||
{
|
||||
"name": "webUseInput",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Web only: Whether to use the PWA Element experience or file input. The\ndefault is to use PWA Elements if installed and fall back to file input.\nTo always use file input, set this to `true`.\n\nLearn more about PWA Elements: https://capacitorjs.com/docs/web/pwa-elements",
|
||||
"complexTypes": [],
|
||||
"type": "boolean | undefined"
|
||||
},
|
||||
{
|
||||
"name": "promptLabelHeader",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": 'Photo'",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Text value to use when displaying the prompt.",
|
||||
"complexTypes": [],
|
||||
"type": "string | undefined"
|
||||
},
|
||||
{
|
||||
"name": "promptLabelCancel",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": 'Cancel'",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Text value to use when displaying the prompt.\niOS only: The label of the 'cancel' button.",
|
||||
"complexTypes": [],
|
||||
"type": "string | undefined"
|
||||
},
|
||||
{
|
||||
"name": "promptLabelPhoto",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": 'From Photos'",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Text value to use when displaying the prompt.\nThe label of the button to select a saved image.",
|
||||
"complexTypes": [],
|
||||
"type": "string | undefined"
|
||||
},
|
||||
{
|
||||
"name": "promptLabelPicture",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": 'Take Picture'",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.0.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Text value to use when displaying the prompt.\nThe label of the button to open the camera.",
|
||||
"complexTypes": [],
|
||||
"type": "string | undefined"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GalleryPhotos",
|
||||
"slug": "galleryphotos",
|
||||
"docs": "",
|
||||
"tags": [],
|
||||
"methods": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "photos",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Array of all the picked photos.",
|
||||
"complexTypes": [
|
||||
"GalleryPhoto"
|
||||
],
|
||||
"type": "GalleryPhoto[]"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GalleryPhoto",
|
||||
"slug": "galleryphoto",
|
||||
"docs": "",
|
||||
"tags": [],
|
||||
"methods": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "path",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Full, platform-specific file URL that can be read later using the Filesystem API.",
|
||||
"complexTypes": [],
|
||||
"type": "string | undefined"
|
||||
},
|
||||
{
|
||||
"name": "webPath",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "webPath returns a path that can be used to set the src attribute of an image for efficient\nloading and rendering.",
|
||||
"complexTypes": [],
|
||||
"type": "string"
|
||||
},
|
||||
{
|
||||
"name": "exif",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Exif data, if any, retrieved from the image",
|
||||
"complexTypes": [],
|
||||
"type": "any"
|
||||
},
|
||||
{
|
||||
"name": "format",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The format of the image, ex: jpeg, png, gif.\n\niOS and Android only support jpeg.\nWeb supports jpeg, png and gif.",
|
||||
"complexTypes": [],
|
||||
"type": "string"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "GalleryImageOptions",
|
||||
"slug": "galleryimageoptions",
|
||||
"docs": "",
|
||||
"tags": [],
|
||||
"methods": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "quality",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The quality of image to return as JPEG, from 0-100\nNote: This option is only supported on Android and iOS.",
|
||||
"complexTypes": [],
|
||||
"type": "number | undefined"
|
||||
},
|
||||
{
|
||||
"name": "width",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The desired maximum width of the saved image. The aspect ratio is respected.",
|
||||
"complexTypes": [],
|
||||
"type": "number | undefined"
|
||||
},
|
||||
{
|
||||
"name": "height",
|
||||
"tags": [
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "The desired maximum height of the saved image. The aspect ratio is respected.",
|
||||
"complexTypes": [],
|
||||
"type": "number | undefined"
|
||||
},
|
||||
{
|
||||
"name": "correctOrientation",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": true",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Whether to automatically rotate the image \"up\" to correct for orientation\nin portrait mode",
|
||||
"complexTypes": [],
|
||||
"type": "boolean | undefined"
|
||||
},
|
||||
{
|
||||
"name": "presentationStyle",
|
||||
"tags": [
|
||||
{
|
||||
"text": ": 'fullscreen'",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "iOS only: The presentation style of the Camera.",
|
||||
"complexTypes": [],
|
||||
"type": "'fullscreen' | 'popover' | undefined"
|
||||
},
|
||||
{
|
||||
"name": "limit",
|
||||
"tags": [
|
||||
{
|
||||
"text": "0 (unlimited)",
|
||||
"name": "default"
|
||||
},
|
||||
{
|
||||
"text": "1.2.0",
|
||||
"name": "since"
|
||||
}
|
||||
],
|
||||
"docs": "Maximum number of pictures the user will be able to choose.\nNote: This option is only supported on Android 13+ and iOS.",
|
||||
"complexTypes": [],
|
||||
"type": "number | undefined"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PermissionStatus",
|
||||
"slug": "permissionstatus",
|
||||
"docs": "",
|
||||
"tags": [],
|
||||
"methods": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "camera",
|
||||
"tags": [],
|
||||
"docs": "",
|
||||
"complexTypes": [
|
||||
"CameraPermissionState"
|
||||
],
|
||||
"type": "CameraPermissionState"
|
||||
},
|
||||
{
|
||||
"name": "photos",
|
||||
"tags": [],
|
||||
"docs": "",
|
||||
"complexTypes": [
|
||||
"CameraPermissionState"
|
||||
],
|
||||
"type": "CameraPermissionState"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CameraPluginPermissions",
|
||||
"slug": "camerapluginpermissions",
|
||||
"docs": "",
|
||||
"tags": [],
|
||||
"methods": [],
|
||||
"properties": [
|
||||
{
|
||||
"name": "permissions",
|
||||
"tags": [],
|
||||
"docs": "",
|
||||
"complexTypes": [
|
||||
"CameraPermissionType"
|
||||
],
|
||||
"type": "CameraPermissionType[]"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"enums": [
|
||||
{
|
||||
"name": "CameraResultType",
|
||||
"slug": "cameraresulttype",
|
||||
"members": [
|
||||
{
|
||||
"name": "Uri",
|
||||
"value": "'uri'",
|
||||
"tags": [],
|
||||
"docs": ""
|
||||
},
|
||||
{
|
||||
"name": "Base64",
|
||||
"value": "'base64'",
|
||||
"tags": [],
|
||||
"docs": ""
|
||||
},
|
||||
{
|
||||
"name": "DataUrl",
|
||||
"value": "'dataUrl'",
|
||||
"tags": [],
|
||||
"docs": ""
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CameraSource",
|
||||
"slug": "camerasource",
|
||||
"members": [
|
||||
{
|
||||
"name": "Prompt",
|
||||
"value": "'PROMPT'",
|
||||
"tags": [],
|
||||
"docs": "Prompts the user to select either the photo album or take a photo."
|
||||
},
|
||||
{
|
||||
"name": "Camera",
|
||||
"value": "'CAMERA'",
|
||||
"tags": [],
|
||||
"docs": "Take a new photo using the camera."
|
||||
},
|
||||
{
|
||||
"name": "Photos",
|
||||
"value": "'PHOTOS'",
|
||||
"tags": [],
|
||||
"docs": "Pick an existing photo from the gallery or photo album."
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CameraDirection",
|
||||
"slug": "cameradirection",
|
||||
"members": [
|
||||
{
|
||||
"name": "Rear",
|
||||
"value": "'REAR'",
|
||||
"tags": [],
|
||||
"docs": ""
|
||||
},
|
||||
{
|
||||
"name": "Front",
|
||||
"value": "'FRONT'",
|
||||
"tags": [],
|
||||
"docs": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"typeAliases": [
|
||||
{
|
||||
"name": "CameraPermissionState",
|
||||
"slug": "camerapermissionstate",
|
||||
"docs": "",
|
||||
"types": [
|
||||
{
|
||||
"text": "PermissionState",
|
||||
"complexTypes": [
|
||||
"PermissionState"
|
||||
]
|
||||
},
|
||||
{
|
||||
"text": "'limited'",
|
||||
"complexTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "PermissionState",
|
||||
"slug": "permissionstate",
|
||||
"docs": "",
|
||||
"types": [
|
||||
{
|
||||
"text": "'prompt'",
|
||||
"complexTypes": []
|
||||
},
|
||||
{
|
||||
"text": "'prompt-with-rationale'",
|
||||
"complexTypes": []
|
||||
},
|
||||
{
|
||||
"text": "'granted'",
|
||||
"complexTypes": []
|
||||
},
|
||||
{
|
||||
"text": "'denied'",
|
||||
"complexTypes": []
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "CameraPermissionType",
|
||||
"slug": "camerapermissiontype",
|
||||
"docs": "",
|
||||
"types": [
|
||||
{
|
||||
"text": "'camera'",
|
||||
"complexTypes": []
|
||||
},
|
||||
{
|
||||
"text": "'photos'",
|
||||
"complexTypes": []
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"pluginConfigs": []
|
||||
}
|
||||
337
node_modules/@capacitor/camera/dist/esm/definitions.d.ts
generated
vendored
Normal file
337
node_modules/@capacitor/camera/dist/esm/definitions.d.ts
generated
vendored
Normal file
@@ -0,0 +1,337 @@
|
||||
import type { PermissionState } from '@capacitor/core';
|
||||
export declare type CameraPermissionState = PermissionState | 'limited';
|
||||
export declare type CameraPermissionType = 'camera' | 'photos';
|
||||
export interface PermissionStatus {
|
||||
camera: CameraPermissionState;
|
||||
photos: CameraPermissionState;
|
||||
}
|
||||
export interface CameraPluginPermissions {
|
||||
permissions: CameraPermissionType[];
|
||||
}
|
||||
export interface CameraPlugin {
|
||||
/**
|
||||
* Prompt the user to pick a photo from an album, or take a new photo
|
||||
* with the camera.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
getPhoto(options: ImageOptions): Promise<Photo>;
|
||||
/**
|
||||
* Allows the user to pick multiple pictures from the photo gallery.
|
||||
* On iOS 13 and older it only allows to pick one picture.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
pickImages(options: GalleryImageOptions): Promise<GalleryPhotos>;
|
||||
/**
|
||||
* iOS 14+ Only: Allows the user to update their limited photo library selection.
|
||||
* On iOS 15+ returns all the limited photos after the picker dismissal.
|
||||
* On iOS 14 or if the user gave full access to the photos it returns an empty array.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
pickLimitedLibraryPhotos(): Promise<GalleryPhotos>;
|
||||
/**
|
||||
* iOS 14+ Only: Return an array of photos selected from the limited photo library.
|
||||
*
|
||||
* @since 4.1.0
|
||||
*/
|
||||
getLimitedLibraryPhotos(): Promise<GalleryPhotos>;
|
||||
/**
|
||||
* Check camera and photo album permissions
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
checkPermissions(): Promise<PermissionStatus>;
|
||||
/**
|
||||
* Request camera and photo album permissions
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
requestPermissions(permissions?: CameraPluginPermissions): Promise<PermissionStatus>;
|
||||
}
|
||||
export interface ImageOptions {
|
||||
/**
|
||||
* The quality of image to return as JPEG, from 0-100
|
||||
* Note: This option is only supported on Android and iOS
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
quality?: number;
|
||||
/**
|
||||
* Whether to allow the user to crop or make small edits (platform specific).
|
||||
* On iOS 14+ it's only supported for CameraSource.Camera, but not for CameraSource.Photos.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
allowEditing?: boolean;
|
||||
/**
|
||||
* How the data should be returned. Currently, only 'Base64', 'DataUrl' or 'Uri' is supported
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
resultType: CameraResultType;
|
||||
/**
|
||||
* Whether to save the photo to the gallery.
|
||||
* If the photo was picked from the gallery, it will only be saved if edited.
|
||||
* @default: false
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
saveToGallery?: boolean;
|
||||
/**
|
||||
* The desired maximum width of the saved image. The aspect ratio is respected.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
width?: number;
|
||||
/**
|
||||
* The desired maximum height of the saved image. The aspect ratio is respected.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
height?: number;
|
||||
/**
|
||||
* Whether to automatically rotate the image "up" to correct for orientation
|
||||
* in portrait mode
|
||||
* @default: true
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
correctOrientation?: boolean;
|
||||
/**
|
||||
* The source to get the photo from. By default this prompts the user to select
|
||||
* either the photo album or take a photo.
|
||||
* @default: CameraSource.Prompt
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
source?: CameraSource;
|
||||
/**
|
||||
* iOS and Web only: The camera direction.
|
||||
* @default: CameraDirection.Rear
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
direction?: CameraDirection;
|
||||
/**
|
||||
* iOS only: The presentation style of the Camera.
|
||||
* @default: 'fullscreen'
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
presentationStyle?: 'fullscreen' | 'popover';
|
||||
/**
|
||||
* Web only: Whether to use the PWA Element experience or file input. The
|
||||
* default is to use PWA Elements if installed and fall back to file input.
|
||||
* To always use file input, set this to `true`.
|
||||
*
|
||||
* Learn more about PWA Elements: https://capacitorjs.com/docs/web/pwa-elements
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
webUseInput?: boolean;
|
||||
/**
|
||||
* Text value to use when displaying the prompt.
|
||||
* @default: 'Photo'
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
*/
|
||||
promptLabelHeader?: string;
|
||||
/**
|
||||
* Text value to use when displaying the prompt.
|
||||
* iOS only: The label of the 'cancel' button.
|
||||
* @default: 'Cancel'
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
promptLabelCancel?: string;
|
||||
/**
|
||||
* Text value to use when displaying the prompt.
|
||||
* The label of the button to select a saved image.
|
||||
* @default: 'From Photos'
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
promptLabelPhoto?: string;
|
||||
/**
|
||||
* Text value to use when displaying the prompt.
|
||||
* The label of the button to open the camera.
|
||||
* @default: 'Take Picture'
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
promptLabelPicture?: string;
|
||||
}
|
||||
export interface Photo {
|
||||
/**
|
||||
* The base64 encoded string representation of the image, if using CameraResultType.Base64.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
base64String?: string;
|
||||
/**
|
||||
* The url starting with 'data:image/jpeg;base64,' and the base64 encoded string representation of the image, if using CameraResultType.DataUrl.
|
||||
*
|
||||
* Note: On web, the file format could change depending on the browser.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
dataUrl?: string;
|
||||
/**
|
||||
* If using CameraResultType.Uri, the path will contain a full,
|
||||
* platform-specific file URL that can be read later using the Filesystem API.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
path?: string;
|
||||
/**
|
||||
* webPath returns a path that can be used to set the src attribute of an image for efficient
|
||||
* loading and rendering.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
webPath?: string;
|
||||
/**
|
||||
* Exif data, if any, retrieved from the image
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
exif?: any;
|
||||
/**
|
||||
* The format of the image, ex: jpeg, png, gif.
|
||||
*
|
||||
* iOS and Android only support jpeg.
|
||||
* Web supports jpeg, png and gif, but the exact availability may vary depending on the browser.
|
||||
* gif is only supported if `webUseInput` is set to `true` or if `source` is set to `Photos`.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*/
|
||||
format: string;
|
||||
/**
|
||||
* Whether if the image was saved to the gallery or not.
|
||||
*
|
||||
* On Android and iOS, saving to the gallery can fail if the user didn't
|
||||
* grant the required permissions.
|
||||
* On Web there is no gallery, so always returns false.
|
||||
*
|
||||
* @since 1.1.0
|
||||
*/
|
||||
saved: boolean;
|
||||
}
|
||||
export interface GalleryPhotos {
|
||||
/**
|
||||
* Array of all the picked photos.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
photos: GalleryPhoto[];
|
||||
}
|
||||
export interface GalleryPhoto {
|
||||
/**
|
||||
* Full, platform-specific file URL that can be read later using the Filesystem API.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
path?: string;
|
||||
/**
|
||||
* webPath returns a path that can be used to set the src attribute of an image for efficient
|
||||
* loading and rendering.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
webPath: string;
|
||||
/**
|
||||
* Exif data, if any, retrieved from the image
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
exif?: any;
|
||||
/**
|
||||
* The format of the image, ex: jpeg, png, gif.
|
||||
*
|
||||
* iOS and Android only support jpeg.
|
||||
* Web supports jpeg, png and gif.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
format: string;
|
||||
}
|
||||
export interface GalleryImageOptions {
|
||||
/**
|
||||
* The quality of image to return as JPEG, from 0-100
|
||||
* Note: This option is only supported on Android and iOS.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
quality?: number;
|
||||
/**
|
||||
* The desired maximum width of the saved image. The aspect ratio is respected.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
width?: number;
|
||||
/**
|
||||
* The desired maximum height of the saved image. The aspect ratio is respected.
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
height?: number;
|
||||
/**
|
||||
* Whether to automatically rotate the image "up" to correct for orientation
|
||||
* in portrait mode
|
||||
* @default: true
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
correctOrientation?: boolean;
|
||||
/**
|
||||
* iOS only: The presentation style of the Camera.
|
||||
* @default: 'fullscreen'
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
presentationStyle?: 'fullscreen' | 'popover';
|
||||
/**
|
||||
* Maximum number of pictures the user will be able to choose.
|
||||
* Note: This option is only supported on Android 13+ and iOS.
|
||||
*
|
||||
* @default 0 (unlimited)
|
||||
*
|
||||
* @since 1.2.0
|
||||
*/
|
||||
limit?: number;
|
||||
}
|
||||
export declare enum CameraSource {
|
||||
/**
|
||||
* Prompts the user to select either the photo album or take a photo.
|
||||
*/
|
||||
Prompt = "PROMPT",
|
||||
/**
|
||||
* Take a new photo using the camera.
|
||||
*/
|
||||
Camera = "CAMERA",
|
||||
/**
|
||||
* Pick an existing photo from the gallery or photo album.
|
||||
*/
|
||||
Photos = "PHOTOS"
|
||||
}
|
||||
export declare enum CameraDirection {
|
||||
Rear = "REAR",
|
||||
Front = "FRONT"
|
||||
}
|
||||
export declare enum CameraResultType {
|
||||
Uri = "uri",
|
||||
Base64 = "base64",
|
||||
DataUrl = "dataUrl"
|
||||
}
|
||||
/**
|
||||
* @deprecated Use `Photo`.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
export declare type CameraPhoto = Photo;
|
||||
/**
|
||||
* @deprecated Use `ImageOptions`.
|
||||
* @since 1.0.0
|
||||
*/
|
||||
export declare type CameraOptions = ImageOptions;
|
||||
27
node_modules/@capacitor/camera/dist/esm/definitions.js
generated
vendored
Normal file
27
node_modules/@capacitor/camera/dist/esm/definitions.js
generated
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
export var CameraSource;
|
||||
(function (CameraSource) {
|
||||
/**
|
||||
* Prompts the user to select either the photo album or take a photo.
|
||||
*/
|
||||
CameraSource["Prompt"] = "PROMPT";
|
||||
/**
|
||||
* Take a new photo using the camera.
|
||||
*/
|
||||
CameraSource["Camera"] = "CAMERA";
|
||||
/**
|
||||
* Pick an existing photo from the gallery or photo album.
|
||||
*/
|
||||
CameraSource["Photos"] = "PHOTOS";
|
||||
})(CameraSource || (CameraSource = {}));
|
||||
export var CameraDirection;
|
||||
(function (CameraDirection) {
|
||||
CameraDirection["Rear"] = "REAR";
|
||||
CameraDirection["Front"] = "FRONT";
|
||||
})(CameraDirection || (CameraDirection = {}));
|
||||
export var CameraResultType;
|
||||
(function (CameraResultType) {
|
||||
CameraResultType["Uri"] = "uri";
|
||||
CameraResultType["Base64"] = "base64";
|
||||
CameraResultType["DataUrl"] = "dataUrl";
|
||||
})(CameraResultType || (CameraResultType = {}));
|
||||
//# sourceMappingURL=definitions.js.map
|
||||
1
node_modules/@capacitor/camera/dist/esm/definitions.js.map
generated
vendored
Normal file
1
node_modules/@capacitor/camera/dist/esm/definitions.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
4
node_modules/@capacitor/camera/dist/esm/index.d.ts
generated
vendored
Normal file
4
node_modules/@capacitor/camera/dist/esm/index.d.ts
generated
vendored
Normal file
@@ -0,0 +1,4 @@
|
||||
import type { CameraPlugin } from './definitions';
|
||||
declare const Camera: CameraPlugin;
|
||||
export * from './definitions';
|
||||
export { Camera };
|
||||
8
node_modules/@capacitor/camera/dist/esm/index.js
generated
vendored
Normal file
8
node_modules/@capacitor/camera/dist/esm/index.js
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
import { registerPlugin } from '@capacitor/core';
|
||||
import { CameraWeb } from './web';
|
||||
const Camera = registerPlugin('Camera', {
|
||||
web: () => new CameraWeb(),
|
||||
});
|
||||
export * from './definitions';
|
||||
export { Camera };
|
||||
//# sourceMappingURL=index.js.map
|
||||
1
node_modules/@capacitor/camera/dist/esm/index.js.map
generated
vendored
Normal file
1
node_modules/@capacitor/camera/dist/esm/index.js.map
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAGjD,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAElC,MAAM,MAAM,GAAG,cAAc,CAAe,QAAQ,EAAE;IACpD,GAAG,EAAE,GAAG,EAAE,CAAC,IAAI,SAAS,EAAE;CAC3B,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,MAAM,EAAE,CAAC","sourcesContent":["import { registerPlugin } from '@capacitor/core';\n\nimport type { CameraPlugin } from './definitions';\nimport { CameraWeb } from './web';\n\nconst Camera = registerPlugin<CameraPlugin>('Camera', {\n web: () => new CameraWeb(),\n});\n\nexport * from './definitions';\nexport { Camera };\n"]}
|
||||
16
node_modules/@capacitor/camera/dist/esm/web.d.ts
generated
vendored
Normal file
16
node_modules/@capacitor/camera/dist/esm/web.d.ts
generated
vendored
Normal file
@@ -0,0 +1,16 @@
|
||||
import { WebPlugin } from '@capacitor/core';
|
||||
import type { CameraPlugin, GalleryImageOptions, GalleryPhotos, ImageOptions, PermissionStatus, Photo } from './definitions';
|
||||
export declare class CameraWeb extends WebPlugin implements CameraPlugin {
|
||||
getPhoto(options: ImageOptions): Promise<Photo>;
|
||||
pickImages(_options: GalleryImageOptions): Promise<GalleryPhotos>;
|
||||
private cameraExperience;
|
||||
private fileInputExperience;
|
||||
private multipleFileInputExperience;
|
||||
private _getCameraPhoto;
|
||||
checkPermissions(): Promise<PermissionStatus>;
|
||||
requestPermissions(): Promise<PermissionStatus>;
|
||||
pickLimitedLibraryPhotos(): Promise<GalleryPhotos>;
|
||||
getLimitedLibraryPhotos(): Promise<GalleryPhotos>;
|
||||
}
|
||||
declare const Camera: CameraWeb;
|
||||
export { Camera };
|
||||
254
node_modules/@capacitor/camera/dist/esm/web.js
generated
vendored
Normal file
254
node_modules/@capacitor/camera/dist/esm/web.js
generated
vendored
Normal file
@@ -0,0 +1,254 @@
|
||||
import { WebPlugin, CapacitorException } from '@capacitor/core';
|
||||
import { CameraSource, CameraDirection } from './definitions';
|
||||
export class CameraWeb extends WebPlugin {
|
||||
async getPhoto(options) {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (options.webUseInput || options.source === CameraSource.Photos) {
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
else if (options.source === CameraSource.Prompt) {
|
||||
let actionSheet = document.querySelector('pwa-action-sheet');
|
||||
if (!actionSheet) {
|
||||
actionSheet = document.createElement('pwa-action-sheet');
|
||||
document.body.appendChild(actionSheet);
|
||||
}
|
||||
actionSheet.header = options.promptLabelHeader || 'Photo';
|
||||
actionSheet.cancelable = false;
|
||||
actionSheet.options = [
|
||||
{ title: options.promptLabelPhoto || 'From Photos' },
|
||||
{ title: options.promptLabelPicture || 'Take Picture' },
|
||||
];
|
||||
actionSheet.addEventListener('onSelection', async (e) => {
|
||||
const selection = e.detail;
|
||||
if (selection === 0) {
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
else {
|
||||
this.cameraExperience(options, resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.cameraExperience(options, resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
async pickImages(_options) {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
return new Promise(async (resolve, reject) => {
|
||||
this.multipleFileInputExperience(resolve, reject);
|
||||
});
|
||||
}
|
||||
async cameraExperience(options, resolve, reject) {
|
||||
if (customElements.get('pwa-camera-modal')) {
|
||||
const cameraModal = document.createElement('pwa-camera-modal');
|
||||
cameraModal.facingMode =
|
||||
options.direction === CameraDirection.Front ? 'user' : 'environment';
|
||||
document.body.appendChild(cameraModal);
|
||||
try {
|
||||
await cameraModal.componentOnReady();
|
||||
cameraModal.addEventListener('onPhoto', async (e) => {
|
||||
const photo = e.detail;
|
||||
if (photo === null) {
|
||||
reject(new CapacitorException('User cancelled photos app'));
|
||||
}
|
||||
else if (photo instanceof Error) {
|
||||
reject(photo);
|
||||
}
|
||||
else {
|
||||
resolve(await this._getCameraPhoto(photo, options));
|
||||
}
|
||||
cameraModal.dismiss();
|
||||
document.body.removeChild(cameraModal);
|
||||
});
|
||||
cameraModal.present();
|
||||
}
|
||||
catch (e) {
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error(`Unable to load PWA Element 'pwa-camera-modal'. See the docs: https://capacitorjs.com/docs/web/pwa-elements.`);
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
}
|
||||
fileInputExperience(options, resolve, reject) {
|
||||
let input = document.querySelector('#_capacitor-camera-input');
|
||||
const cleanup = () => {
|
||||
var _a;
|
||||
(_a = input.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(input);
|
||||
};
|
||||
if (!input) {
|
||||
input = document.createElement('input');
|
||||
input.id = '_capacitor-camera-input';
|
||||
input.type = 'file';
|
||||
input.hidden = true;
|
||||
document.body.appendChild(input);
|
||||
input.addEventListener('change', (_e) => {
|
||||
const file = input.files[0];
|
||||
let format = 'jpeg';
|
||||
if (file.type === 'image/png') {
|
||||
format = 'png';
|
||||
}
|
||||
else if (file.type === 'image/gif') {
|
||||
format = 'gif';
|
||||
}
|
||||
if (options.resultType === 'dataUrl' ||
|
||||
options.resultType === 'base64') {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => {
|
||||
if (options.resultType === 'dataUrl') {
|
||||
resolve({
|
||||
dataUrl: reader.result,
|
||||
format,
|
||||
});
|
||||
}
|
||||
else if (options.resultType === 'base64') {
|
||||
const b64 = reader.result.split(',')[1];
|
||||
resolve({
|
||||
base64String: b64,
|
||||
format,
|
||||
});
|
||||
}
|
||||
cleanup();
|
||||
});
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
else {
|
||||
resolve({
|
||||
webPath: URL.createObjectURL(file),
|
||||
format: format,
|
||||
});
|
||||
cleanup();
|
||||
}
|
||||
});
|
||||
input.addEventListener('cancel', (_e) => {
|
||||
reject(new CapacitorException('User cancelled photos app'));
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
input.accept = 'image/*';
|
||||
input.capture = true;
|
||||
if (options.source === CameraSource.Photos ||
|
||||
options.source === CameraSource.Prompt) {
|
||||
input.removeAttribute('capture');
|
||||
}
|
||||
else if (options.direction === CameraDirection.Front) {
|
||||
input.capture = 'user';
|
||||
}
|
||||
else if (options.direction === CameraDirection.Rear) {
|
||||
input.capture = 'environment';
|
||||
}
|
||||
input.click();
|
||||
}
|
||||
multipleFileInputExperience(resolve, reject) {
|
||||
let input = document.querySelector('#_capacitor-camera-input-multiple');
|
||||
const cleanup = () => {
|
||||
var _a;
|
||||
(_a = input.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(input);
|
||||
};
|
||||
if (!input) {
|
||||
input = document.createElement('input');
|
||||
input.id = '_capacitor-camera-input-multiple';
|
||||
input.type = 'file';
|
||||
input.hidden = true;
|
||||
input.multiple = true;
|
||||
document.body.appendChild(input);
|
||||
input.addEventListener('change', (_e) => {
|
||||
const photos = [];
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||
for (let i = 0; i < input.files.length; i++) {
|
||||
const file = input.files[i];
|
||||
let format = 'jpeg';
|
||||
if (file.type === 'image/png') {
|
||||
format = 'png';
|
||||
}
|
||||
else if (file.type === 'image/gif') {
|
||||
format = 'gif';
|
||||
}
|
||||
photos.push({
|
||||
webPath: URL.createObjectURL(file),
|
||||
format: format,
|
||||
});
|
||||
}
|
||||
resolve({ photos });
|
||||
cleanup();
|
||||
});
|
||||
input.addEventListener('cancel', (_e) => {
|
||||
reject(new CapacitorException('User cancelled photos app'));
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
input.accept = 'image/*';
|
||||
input.click();
|
||||
}
|
||||
_getCameraPhoto(photo, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
const format = photo.type.split('/')[1];
|
||||
if (options.resultType === 'uri') {
|
||||
resolve({
|
||||
webPath: URL.createObjectURL(photo),
|
||||
format: format,
|
||||
saved: false,
|
||||
});
|
||||
}
|
||||
else {
|
||||
reader.readAsDataURL(photo);
|
||||
reader.onloadend = () => {
|
||||
const r = reader.result;
|
||||
if (options.resultType === 'dataUrl') {
|
||||
resolve({
|
||||
dataUrl: r,
|
||||
format: format,
|
||||
saved: false,
|
||||
});
|
||||
}
|
||||
else {
|
||||
resolve({
|
||||
base64String: r.split(',')[1],
|
||||
format: format,
|
||||
saved: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
reader.onerror = e => {
|
||||
reject(e);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
async checkPermissions() {
|
||||
if (typeof navigator === 'undefined' || !navigator.permissions) {
|
||||
throw this.unavailable('Permissions API not available in this browser');
|
||||
}
|
||||
try {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query
|
||||
// the specific permissions that are supported varies among browsers that implement the
|
||||
// permissions API, so we need a try/catch in case 'camera' is invalid
|
||||
const permission = await window.navigator.permissions.query({
|
||||
name: 'camera',
|
||||
});
|
||||
return {
|
||||
camera: permission.state,
|
||||
photos: 'granted',
|
||||
};
|
||||
}
|
||||
catch (_a) {
|
||||
throw this.unavailable('Camera permissions are not available in this browser');
|
||||
}
|
||||
}
|
||||
async requestPermissions() {
|
||||
throw this.unimplemented('Not implemented on web.');
|
||||
}
|
||||
async pickLimitedLibraryPhotos() {
|
||||
throw this.unavailable('Not implemented on web.');
|
||||
}
|
||||
async getLimitedLibraryPhotos() {
|
||||
throw this.unavailable('Not implemented on web.');
|
||||
}
|
||||
}
|
||||
const Camera = new CameraWeb();
|
||||
export { Camera };
|
||||
//# sourceMappingURL=web.js.map
|
||||
1
node_modules/@capacitor/camera/dist/esm/web.js.map
generated
vendored
Normal file
1
node_modules/@capacitor/camera/dist/esm/web.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
288
node_modules/@capacitor/camera/dist/plugin.cjs.js
generated
vendored
Normal file
288
node_modules/@capacitor/camera/dist/plugin.cjs.js
generated
vendored
Normal file
@@ -0,0 +1,288 @@
|
||||
'use strict';
|
||||
|
||||
var core = require('@capacitor/core');
|
||||
|
||||
exports.CameraSource = void 0;
|
||||
(function (CameraSource) {
|
||||
/**
|
||||
* Prompts the user to select either the photo album or take a photo.
|
||||
*/
|
||||
CameraSource["Prompt"] = "PROMPT";
|
||||
/**
|
||||
* Take a new photo using the camera.
|
||||
*/
|
||||
CameraSource["Camera"] = "CAMERA";
|
||||
/**
|
||||
* Pick an existing photo from the gallery or photo album.
|
||||
*/
|
||||
CameraSource["Photos"] = "PHOTOS";
|
||||
})(exports.CameraSource || (exports.CameraSource = {}));
|
||||
exports.CameraDirection = void 0;
|
||||
(function (CameraDirection) {
|
||||
CameraDirection["Rear"] = "REAR";
|
||||
CameraDirection["Front"] = "FRONT";
|
||||
})(exports.CameraDirection || (exports.CameraDirection = {}));
|
||||
exports.CameraResultType = void 0;
|
||||
(function (CameraResultType) {
|
||||
CameraResultType["Uri"] = "uri";
|
||||
CameraResultType["Base64"] = "base64";
|
||||
CameraResultType["DataUrl"] = "dataUrl";
|
||||
})(exports.CameraResultType || (exports.CameraResultType = {}));
|
||||
|
||||
class CameraWeb extends core.WebPlugin {
|
||||
async getPhoto(options) {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (options.webUseInput || options.source === exports.CameraSource.Photos) {
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
else if (options.source === exports.CameraSource.Prompt) {
|
||||
let actionSheet = document.querySelector('pwa-action-sheet');
|
||||
if (!actionSheet) {
|
||||
actionSheet = document.createElement('pwa-action-sheet');
|
||||
document.body.appendChild(actionSheet);
|
||||
}
|
||||
actionSheet.header = options.promptLabelHeader || 'Photo';
|
||||
actionSheet.cancelable = false;
|
||||
actionSheet.options = [
|
||||
{ title: options.promptLabelPhoto || 'From Photos' },
|
||||
{ title: options.promptLabelPicture || 'Take Picture' },
|
||||
];
|
||||
actionSheet.addEventListener('onSelection', async (e) => {
|
||||
const selection = e.detail;
|
||||
if (selection === 0) {
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
else {
|
||||
this.cameraExperience(options, resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.cameraExperience(options, resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
async pickImages(_options) {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
return new Promise(async (resolve, reject) => {
|
||||
this.multipleFileInputExperience(resolve, reject);
|
||||
});
|
||||
}
|
||||
async cameraExperience(options, resolve, reject) {
|
||||
if (customElements.get('pwa-camera-modal')) {
|
||||
const cameraModal = document.createElement('pwa-camera-modal');
|
||||
cameraModal.facingMode =
|
||||
options.direction === exports.CameraDirection.Front ? 'user' : 'environment';
|
||||
document.body.appendChild(cameraModal);
|
||||
try {
|
||||
await cameraModal.componentOnReady();
|
||||
cameraModal.addEventListener('onPhoto', async (e) => {
|
||||
const photo = e.detail;
|
||||
if (photo === null) {
|
||||
reject(new core.CapacitorException('User cancelled photos app'));
|
||||
}
|
||||
else if (photo instanceof Error) {
|
||||
reject(photo);
|
||||
}
|
||||
else {
|
||||
resolve(await this._getCameraPhoto(photo, options));
|
||||
}
|
||||
cameraModal.dismiss();
|
||||
document.body.removeChild(cameraModal);
|
||||
});
|
||||
cameraModal.present();
|
||||
}
|
||||
catch (e) {
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error(`Unable to load PWA Element 'pwa-camera-modal'. See the docs: https://capacitorjs.com/docs/web/pwa-elements.`);
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
}
|
||||
fileInputExperience(options, resolve, reject) {
|
||||
let input = document.querySelector('#_capacitor-camera-input');
|
||||
const cleanup = () => {
|
||||
var _a;
|
||||
(_a = input.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(input);
|
||||
};
|
||||
if (!input) {
|
||||
input = document.createElement('input');
|
||||
input.id = '_capacitor-camera-input';
|
||||
input.type = 'file';
|
||||
input.hidden = true;
|
||||
document.body.appendChild(input);
|
||||
input.addEventListener('change', (_e) => {
|
||||
const file = input.files[0];
|
||||
let format = 'jpeg';
|
||||
if (file.type === 'image/png') {
|
||||
format = 'png';
|
||||
}
|
||||
else if (file.type === 'image/gif') {
|
||||
format = 'gif';
|
||||
}
|
||||
if (options.resultType === 'dataUrl' ||
|
||||
options.resultType === 'base64') {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => {
|
||||
if (options.resultType === 'dataUrl') {
|
||||
resolve({
|
||||
dataUrl: reader.result,
|
||||
format,
|
||||
});
|
||||
}
|
||||
else if (options.resultType === 'base64') {
|
||||
const b64 = reader.result.split(',')[1];
|
||||
resolve({
|
||||
base64String: b64,
|
||||
format,
|
||||
});
|
||||
}
|
||||
cleanup();
|
||||
});
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
else {
|
||||
resolve({
|
||||
webPath: URL.createObjectURL(file),
|
||||
format: format,
|
||||
});
|
||||
cleanup();
|
||||
}
|
||||
});
|
||||
input.addEventListener('cancel', (_e) => {
|
||||
reject(new core.CapacitorException('User cancelled photos app'));
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
input.accept = 'image/*';
|
||||
input.capture = true;
|
||||
if (options.source === exports.CameraSource.Photos ||
|
||||
options.source === exports.CameraSource.Prompt) {
|
||||
input.removeAttribute('capture');
|
||||
}
|
||||
else if (options.direction === exports.CameraDirection.Front) {
|
||||
input.capture = 'user';
|
||||
}
|
||||
else if (options.direction === exports.CameraDirection.Rear) {
|
||||
input.capture = 'environment';
|
||||
}
|
||||
input.click();
|
||||
}
|
||||
multipleFileInputExperience(resolve, reject) {
|
||||
let input = document.querySelector('#_capacitor-camera-input-multiple');
|
||||
const cleanup = () => {
|
||||
var _a;
|
||||
(_a = input.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(input);
|
||||
};
|
||||
if (!input) {
|
||||
input = document.createElement('input');
|
||||
input.id = '_capacitor-camera-input-multiple';
|
||||
input.type = 'file';
|
||||
input.hidden = true;
|
||||
input.multiple = true;
|
||||
document.body.appendChild(input);
|
||||
input.addEventListener('change', (_e) => {
|
||||
const photos = [];
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||
for (let i = 0; i < input.files.length; i++) {
|
||||
const file = input.files[i];
|
||||
let format = 'jpeg';
|
||||
if (file.type === 'image/png') {
|
||||
format = 'png';
|
||||
}
|
||||
else if (file.type === 'image/gif') {
|
||||
format = 'gif';
|
||||
}
|
||||
photos.push({
|
||||
webPath: URL.createObjectURL(file),
|
||||
format: format,
|
||||
});
|
||||
}
|
||||
resolve({ photos });
|
||||
cleanup();
|
||||
});
|
||||
input.addEventListener('cancel', (_e) => {
|
||||
reject(new core.CapacitorException('User cancelled photos app'));
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
input.accept = 'image/*';
|
||||
input.click();
|
||||
}
|
||||
_getCameraPhoto(photo, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
const format = photo.type.split('/')[1];
|
||||
if (options.resultType === 'uri') {
|
||||
resolve({
|
||||
webPath: URL.createObjectURL(photo),
|
||||
format: format,
|
||||
saved: false,
|
||||
});
|
||||
}
|
||||
else {
|
||||
reader.readAsDataURL(photo);
|
||||
reader.onloadend = () => {
|
||||
const r = reader.result;
|
||||
if (options.resultType === 'dataUrl') {
|
||||
resolve({
|
||||
dataUrl: r,
|
||||
format: format,
|
||||
saved: false,
|
||||
});
|
||||
}
|
||||
else {
|
||||
resolve({
|
||||
base64String: r.split(',')[1],
|
||||
format: format,
|
||||
saved: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
reader.onerror = e => {
|
||||
reject(e);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
async checkPermissions() {
|
||||
if (typeof navigator === 'undefined' || !navigator.permissions) {
|
||||
throw this.unavailable('Permissions API not available in this browser');
|
||||
}
|
||||
try {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query
|
||||
// the specific permissions that are supported varies among browsers that implement the
|
||||
// permissions API, so we need a try/catch in case 'camera' is invalid
|
||||
const permission = await window.navigator.permissions.query({
|
||||
name: 'camera',
|
||||
});
|
||||
return {
|
||||
camera: permission.state,
|
||||
photos: 'granted',
|
||||
};
|
||||
}
|
||||
catch (_a) {
|
||||
throw this.unavailable('Camera permissions are not available in this browser');
|
||||
}
|
||||
}
|
||||
async requestPermissions() {
|
||||
throw this.unimplemented('Not implemented on web.');
|
||||
}
|
||||
async pickLimitedLibraryPhotos() {
|
||||
throw this.unavailable('Not implemented on web.');
|
||||
}
|
||||
async getLimitedLibraryPhotos() {
|
||||
throw this.unavailable('Not implemented on web.');
|
||||
}
|
||||
}
|
||||
new CameraWeb();
|
||||
|
||||
const Camera = core.registerPlugin('Camera', {
|
||||
web: () => new CameraWeb(),
|
||||
});
|
||||
|
||||
exports.Camera = Camera;
|
||||
//# sourceMappingURL=plugin.cjs.js.map
|
||||
1
node_modules/@capacitor/camera/dist/plugin.cjs.js.map
generated
vendored
Normal file
1
node_modules/@capacitor/camera/dist/plugin.cjs.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
291
node_modules/@capacitor/camera/dist/plugin.js
generated
vendored
Normal file
291
node_modules/@capacitor/camera/dist/plugin.js
generated
vendored
Normal file
@@ -0,0 +1,291 @@
|
||||
var capacitorCamera = (function (exports, core) {
|
||||
'use strict';
|
||||
|
||||
exports.CameraSource = void 0;
|
||||
(function (CameraSource) {
|
||||
/**
|
||||
* Prompts the user to select either the photo album or take a photo.
|
||||
*/
|
||||
CameraSource["Prompt"] = "PROMPT";
|
||||
/**
|
||||
* Take a new photo using the camera.
|
||||
*/
|
||||
CameraSource["Camera"] = "CAMERA";
|
||||
/**
|
||||
* Pick an existing photo from the gallery or photo album.
|
||||
*/
|
||||
CameraSource["Photos"] = "PHOTOS";
|
||||
})(exports.CameraSource || (exports.CameraSource = {}));
|
||||
exports.CameraDirection = void 0;
|
||||
(function (CameraDirection) {
|
||||
CameraDirection["Rear"] = "REAR";
|
||||
CameraDirection["Front"] = "FRONT";
|
||||
})(exports.CameraDirection || (exports.CameraDirection = {}));
|
||||
exports.CameraResultType = void 0;
|
||||
(function (CameraResultType) {
|
||||
CameraResultType["Uri"] = "uri";
|
||||
CameraResultType["Base64"] = "base64";
|
||||
CameraResultType["DataUrl"] = "dataUrl";
|
||||
})(exports.CameraResultType || (exports.CameraResultType = {}));
|
||||
|
||||
class CameraWeb extends core.WebPlugin {
|
||||
async getPhoto(options) {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
return new Promise(async (resolve, reject) => {
|
||||
if (options.webUseInput || options.source === exports.CameraSource.Photos) {
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
else if (options.source === exports.CameraSource.Prompt) {
|
||||
let actionSheet = document.querySelector('pwa-action-sheet');
|
||||
if (!actionSheet) {
|
||||
actionSheet = document.createElement('pwa-action-sheet');
|
||||
document.body.appendChild(actionSheet);
|
||||
}
|
||||
actionSheet.header = options.promptLabelHeader || 'Photo';
|
||||
actionSheet.cancelable = false;
|
||||
actionSheet.options = [
|
||||
{ title: options.promptLabelPhoto || 'From Photos' },
|
||||
{ title: options.promptLabelPicture || 'Take Picture' },
|
||||
];
|
||||
actionSheet.addEventListener('onSelection', async (e) => {
|
||||
const selection = e.detail;
|
||||
if (selection === 0) {
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
else {
|
||||
this.cameraExperience(options, resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
else {
|
||||
this.cameraExperience(options, resolve, reject);
|
||||
}
|
||||
});
|
||||
}
|
||||
async pickImages(_options) {
|
||||
// eslint-disable-next-line no-async-promise-executor
|
||||
return new Promise(async (resolve, reject) => {
|
||||
this.multipleFileInputExperience(resolve, reject);
|
||||
});
|
||||
}
|
||||
async cameraExperience(options, resolve, reject) {
|
||||
if (customElements.get('pwa-camera-modal')) {
|
||||
const cameraModal = document.createElement('pwa-camera-modal');
|
||||
cameraModal.facingMode =
|
||||
options.direction === exports.CameraDirection.Front ? 'user' : 'environment';
|
||||
document.body.appendChild(cameraModal);
|
||||
try {
|
||||
await cameraModal.componentOnReady();
|
||||
cameraModal.addEventListener('onPhoto', async (e) => {
|
||||
const photo = e.detail;
|
||||
if (photo === null) {
|
||||
reject(new core.CapacitorException('User cancelled photos app'));
|
||||
}
|
||||
else if (photo instanceof Error) {
|
||||
reject(photo);
|
||||
}
|
||||
else {
|
||||
resolve(await this._getCameraPhoto(photo, options));
|
||||
}
|
||||
cameraModal.dismiss();
|
||||
document.body.removeChild(cameraModal);
|
||||
});
|
||||
cameraModal.present();
|
||||
}
|
||||
catch (e) {
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
}
|
||||
else {
|
||||
console.error(`Unable to load PWA Element 'pwa-camera-modal'. See the docs: https://capacitorjs.com/docs/web/pwa-elements.`);
|
||||
this.fileInputExperience(options, resolve, reject);
|
||||
}
|
||||
}
|
||||
fileInputExperience(options, resolve, reject) {
|
||||
let input = document.querySelector('#_capacitor-camera-input');
|
||||
const cleanup = () => {
|
||||
var _a;
|
||||
(_a = input.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(input);
|
||||
};
|
||||
if (!input) {
|
||||
input = document.createElement('input');
|
||||
input.id = '_capacitor-camera-input';
|
||||
input.type = 'file';
|
||||
input.hidden = true;
|
||||
document.body.appendChild(input);
|
||||
input.addEventListener('change', (_e) => {
|
||||
const file = input.files[0];
|
||||
let format = 'jpeg';
|
||||
if (file.type === 'image/png') {
|
||||
format = 'png';
|
||||
}
|
||||
else if (file.type === 'image/gif') {
|
||||
format = 'gif';
|
||||
}
|
||||
if (options.resultType === 'dataUrl' ||
|
||||
options.resultType === 'base64') {
|
||||
const reader = new FileReader();
|
||||
reader.addEventListener('load', () => {
|
||||
if (options.resultType === 'dataUrl') {
|
||||
resolve({
|
||||
dataUrl: reader.result,
|
||||
format,
|
||||
});
|
||||
}
|
||||
else if (options.resultType === 'base64') {
|
||||
const b64 = reader.result.split(',')[1];
|
||||
resolve({
|
||||
base64String: b64,
|
||||
format,
|
||||
});
|
||||
}
|
||||
cleanup();
|
||||
});
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
else {
|
||||
resolve({
|
||||
webPath: URL.createObjectURL(file),
|
||||
format: format,
|
||||
});
|
||||
cleanup();
|
||||
}
|
||||
});
|
||||
input.addEventListener('cancel', (_e) => {
|
||||
reject(new core.CapacitorException('User cancelled photos app'));
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
input.accept = 'image/*';
|
||||
input.capture = true;
|
||||
if (options.source === exports.CameraSource.Photos ||
|
||||
options.source === exports.CameraSource.Prompt) {
|
||||
input.removeAttribute('capture');
|
||||
}
|
||||
else if (options.direction === exports.CameraDirection.Front) {
|
||||
input.capture = 'user';
|
||||
}
|
||||
else if (options.direction === exports.CameraDirection.Rear) {
|
||||
input.capture = 'environment';
|
||||
}
|
||||
input.click();
|
||||
}
|
||||
multipleFileInputExperience(resolve, reject) {
|
||||
let input = document.querySelector('#_capacitor-camera-input-multiple');
|
||||
const cleanup = () => {
|
||||
var _a;
|
||||
(_a = input.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(input);
|
||||
};
|
||||
if (!input) {
|
||||
input = document.createElement('input');
|
||||
input.id = '_capacitor-camera-input-multiple';
|
||||
input.type = 'file';
|
||||
input.hidden = true;
|
||||
input.multiple = true;
|
||||
document.body.appendChild(input);
|
||||
input.addEventListener('change', (_e) => {
|
||||
const photos = [];
|
||||
// eslint-disable-next-line @typescript-eslint/prefer-for-of
|
||||
for (let i = 0; i < input.files.length; i++) {
|
||||
const file = input.files[i];
|
||||
let format = 'jpeg';
|
||||
if (file.type === 'image/png') {
|
||||
format = 'png';
|
||||
}
|
||||
else if (file.type === 'image/gif') {
|
||||
format = 'gif';
|
||||
}
|
||||
photos.push({
|
||||
webPath: URL.createObjectURL(file),
|
||||
format: format,
|
||||
});
|
||||
}
|
||||
resolve({ photos });
|
||||
cleanup();
|
||||
});
|
||||
input.addEventListener('cancel', (_e) => {
|
||||
reject(new core.CapacitorException('User cancelled photos app'));
|
||||
cleanup();
|
||||
});
|
||||
}
|
||||
input.accept = 'image/*';
|
||||
input.click();
|
||||
}
|
||||
_getCameraPhoto(photo, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const reader = new FileReader();
|
||||
const format = photo.type.split('/')[1];
|
||||
if (options.resultType === 'uri') {
|
||||
resolve({
|
||||
webPath: URL.createObjectURL(photo),
|
||||
format: format,
|
||||
saved: false,
|
||||
});
|
||||
}
|
||||
else {
|
||||
reader.readAsDataURL(photo);
|
||||
reader.onloadend = () => {
|
||||
const r = reader.result;
|
||||
if (options.resultType === 'dataUrl') {
|
||||
resolve({
|
||||
dataUrl: r,
|
||||
format: format,
|
||||
saved: false,
|
||||
});
|
||||
}
|
||||
else {
|
||||
resolve({
|
||||
base64String: r.split(',')[1],
|
||||
format: format,
|
||||
saved: false,
|
||||
});
|
||||
}
|
||||
};
|
||||
reader.onerror = e => {
|
||||
reject(e);
|
||||
};
|
||||
}
|
||||
});
|
||||
}
|
||||
async checkPermissions() {
|
||||
if (typeof navigator === 'undefined' || !navigator.permissions) {
|
||||
throw this.unavailable('Permissions API not available in this browser');
|
||||
}
|
||||
try {
|
||||
// https://developer.mozilla.org/en-US/docs/Web/API/Permissions/query
|
||||
// the specific permissions that are supported varies among browsers that implement the
|
||||
// permissions API, so we need a try/catch in case 'camera' is invalid
|
||||
const permission = await window.navigator.permissions.query({
|
||||
name: 'camera',
|
||||
});
|
||||
return {
|
||||
camera: permission.state,
|
||||
photos: 'granted',
|
||||
};
|
||||
}
|
||||
catch (_a) {
|
||||
throw this.unavailable('Camera permissions are not available in this browser');
|
||||
}
|
||||
}
|
||||
async requestPermissions() {
|
||||
throw this.unimplemented('Not implemented on web.');
|
||||
}
|
||||
async pickLimitedLibraryPhotos() {
|
||||
throw this.unavailable('Not implemented on web.');
|
||||
}
|
||||
async getLimitedLibraryPhotos() {
|
||||
throw this.unavailable('Not implemented on web.');
|
||||
}
|
||||
}
|
||||
new CameraWeb();
|
||||
|
||||
const Camera = core.registerPlugin('Camera', {
|
||||
web: () => new CameraWeb(),
|
||||
});
|
||||
|
||||
exports.Camera = Camera;
|
||||
|
||||
return exports;
|
||||
|
||||
})({}, capacitorExports);
|
||||
//# sourceMappingURL=plugin.js.map
|
||||
1
node_modules/@capacitor/camera/dist/plugin.js.map
generated
vendored
Normal file
1
node_modules/@capacitor/camera/dist/plugin.js.map
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
100
node_modules/@capacitor/camera/ios/Sources/CameraPlugin/CameraExtensions.swift
generated
vendored
Normal file
100
node_modules/@capacitor/camera/ios/Sources/CameraPlugin/CameraExtensions.swift
generated
vendored
Normal file
@@ -0,0 +1,100 @@
|
||||
import UIKit
|
||||
import Photos
|
||||
|
||||
internal protocol CameraAuthorizationState {
|
||||
var authorizationState: String { get }
|
||||
}
|
||||
|
||||
extension AVAuthorizationStatus: CameraAuthorizationState {
|
||||
var authorizationState: String {
|
||||
switch self {
|
||||
case .denied, .restricted:
|
||||
return "denied"
|
||||
case .authorized:
|
||||
return "granted"
|
||||
case .notDetermined:
|
||||
fallthrough
|
||||
@unknown default:
|
||||
return "prompt"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension PHAuthorizationStatus: CameraAuthorizationState {
|
||||
var authorizationState: String {
|
||||
switch self {
|
||||
case .denied, .restricted:
|
||||
return "denied"
|
||||
case .authorized:
|
||||
return "granted"
|
||||
case .limited:
|
||||
return "limited"
|
||||
case .notDetermined:
|
||||
fallthrough
|
||||
@unknown default:
|
||||
return "prompt"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal extension PHAsset {
|
||||
/**
|
||||
Retrieves the image metadata for the asset.
|
||||
*/
|
||||
var imageData: [String: Any] {
|
||||
let options = PHImageRequestOptions()
|
||||
options.isSynchronous = true
|
||||
options.resizeMode = .none
|
||||
options.isNetworkAccessAllowed = false
|
||||
options.version = .current
|
||||
|
||||
var result: [String: Any] = [:]
|
||||
_ = PHCachingImageManager().requestImageDataAndOrientation(for: self, options: options) { (data, _, _, _) in
|
||||
if let data = data as NSData? {
|
||||
let options = [kCGImageSourceShouldCache as String: kCFBooleanFalse] as CFDictionary
|
||||
if let imgSrc = CGImageSourceCreateWithData(data, options),
|
||||
let metadata = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options) as? [String: Any] {
|
||||
result = metadata
|
||||
}
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
internal extension UIImage {
|
||||
/**
|
||||
Generates a new image from the existing one, implicitly resetting any orientation.
|
||||
Dimensions greater than 0 will resize the image while preserving the aspect ratio.
|
||||
*/
|
||||
func reformat(to size: CGSize? = nil) -> UIImage {
|
||||
let imageHeight = self.size.height
|
||||
let imageWidth = self.size.width
|
||||
// determine the max dimensions, 0 is treated as 'no restriction'
|
||||
var maxWidth: CGFloat
|
||||
if let size = size, size.width > 0 {
|
||||
maxWidth = size.width
|
||||
} else {
|
||||
maxWidth = imageWidth
|
||||
}
|
||||
let maxHeight: CGFloat
|
||||
if let size = size, size.height > 0 {
|
||||
maxHeight = size.height
|
||||
} else {
|
||||
maxHeight = imageHeight
|
||||
}
|
||||
// adjust to preserve aspect ratio
|
||||
var targetWidth = min(imageWidth, maxWidth)
|
||||
var targetHeight = (imageHeight * targetWidth) / imageWidth
|
||||
if targetHeight > maxHeight {
|
||||
targetWidth = (imageWidth * maxHeight) / imageHeight
|
||||
targetHeight = maxHeight
|
||||
}
|
||||
// generate the new image and return
|
||||
UIGraphicsBeginImageContextWithOptions(.init(width: targetWidth, height: targetHeight), false, 1.0) // size, opaque and scale
|
||||
self.draw(in: .init(origin: .zero, size: .init(width: targetWidth, height: targetHeight)))
|
||||
let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
|
||||
UIGraphicsEndImageContext()
|
||||
return resizedImage ?? self
|
||||
}
|
||||
}
|
||||
584
node_modules/@capacitor/camera/ios/Sources/CameraPlugin/CameraPlugin.swift
generated
vendored
Normal file
584
node_modules/@capacitor/camera/ios/Sources/CameraPlugin/CameraPlugin.swift
generated
vendored
Normal file
@@ -0,0 +1,584 @@
|
||||
import Foundation
|
||||
import Capacitor
|
||||
import Photos
|
||||
import PhotosUI
|
||||
|
||||
@objc(CAPCameraPlugin)
|
||||
public class CameraPlugin: CAPPlugin, CAPBridgedPlugin {
|
||||
public let identifier = "CAPCameraPlugin"
|
||||
public let jsName = "Camera"
|
||||
public let pluginMethods: [CAPPluginMethod] = [
|
||||
CAPPluginMethod(name: "getPhoto", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "pickImages", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "checkPermissions", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "requestPermissions", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "pickLimitedLibraryPhotos", returnType: CAPPluginReturnPromise),
|
||||
CAPPluginMethod(name: "getLimitedLibraryPhotos", returnType: CAPPluginReturnPromise)
|
||||
]
|
||||
private var call: CAPPluginCall?
|
||||
private var settings = CameraSettings()
|
||||
private let defaultSource = CameraSource.prompt
|
||||
private let defaultDirection = CameraDirection.rear
|
||||
private var multiple = false
|
||||
|
||||
private var imageCounter = 0
|
||||
|
||||
@objc override public func checkPermissions(_ call: CAPPluginCall) {
|
||||
var result: [String: Any] = [:]
|
||||
for permission in CameraPermissionType.allCases {
|
||||
let state: String
|
||||
switch permission {
|
||||
case .camera:
|
||||
state = AVCaptureDevice.authorizationStatus(for: .video).authorizationState
|
||||
case .photos:
|
||||
if #available(iOS 14, *) {
|
||||
state = PHPhotoLibrary.authorizationStatus(for: .readWrite).authorizationState
|
||||
} else {
|
||||
state = PHPhotoLibrary.authorizationStatus().authorizationState
|
||||
}
|
||||
}
|
||||
result[permission.rawValue] = state
|
||||
}
|
||||
call.resolve(result)
|
||||
}
|
||||
|
||||
@objc override public func requestPermissions(_ call: CAPPluginCall) {
|
||||
// get the list of desired types, if passed
|
||||
let typeList = call.getArray("permissions", String.self)?.compactMap({ (type) -> CameraPermissionType? in
|
||||
return CameraPermissionType(rawValue: type)
|
||||
}) ?? []
|
||||
// otherwise check everything
|
||||
let permissions: [CameraPermissionType] = (typeList.count > 0) ? typeList : CameraPermissionType.allCases
|
||||
// request the permissions
|
||||
let group = DispatchGroup()
|
||||
for permission in permissions {
|
||||
switch permission {
|
||||
case .camera:
|
||||
group.enter()
|
||||
AVCaptureDevice.requestAccess(for: .video) { _ in
|
||||
group.leave()
|
||||
}
|
||||
case .photos:
|
||||
group.enter()
|
||||
if #available(iOS 14, *) {
|
||||
PHPhotoLibrary.requestAuthorization(for: .readWrite) { (_) in
|
||||
group.leave()
|
||||
}
|
||||
} else {
|
||||
PHPhotoLibrary.requestAuthorization({ (_) in
|
||||
group.leave()
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
group.notify(queue: DispatchQueue.main) { [weak self] in
|
||||
self?.checkPermissions(call)
|
||||
}
|
||||
}
|
||||
|
||||
@objc func pickLimitedLibraryPhotos(_ call: CAPPluginCall) {
|
||||
if #available(iOS 14, *) {
|
||||
PHPhotoLibrary.requestAuthorization(for: .readWrite) { (granted) in
|
||||
if granted == .limited {
|
||||
if let viewController = self.bridge?.viewController {
|
||||
if #available(iOS 15, *) {
|
||||
PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: viewController) { _ in
|
||||
self.getLimitedLibraryPhotos(call)
|
||||
}
|
||||
} else {
|
||||
PHPhotoLibrary.shared().presentLimitedLibraryPicker(from: viewController)
|
||||
call.resolve([
|
||||
"photos": []
|
||||
])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
call.resolve([
|
||||
"photos": []
|
||||
])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
call.unavailable("Not available on iOS 13")
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getLimitedLibraryPhotos(_ call: CAPPluginCall) {
|
||||
if #available(iOS 14, *) {
|
||||
PHPhotoLibrary.requestAuthorization(for: .readWrite) { (granted) in
|
||||
if granted == .limited {
|
||||
|
||||
self.call = call
|
||||
|
||||
DispatchQueue.global(qos: .utility).async {
|
||||
let assets = PHAsset.fetchAssets(with: .image, options: nil)
|
||||
var processedImages: [ProcessedImage] = []
|
||||
|
||||
let imageManager = PHImageManager.default()
|
||||
let options = PHImageRequestOptions()
|
||||
options.deliveryMode = .highQualityFormat
|
||||
|
||||
let group = DispatchGroup()
|
||||
if assets.count > 0 {
|
||||
for index in 0...(assets.count - 1) {
|
||||
let asset = assets.object(at: index)
|
||||
let fullSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
|
||||
|
||||
group.enter()
|
||||
imageManager.requestImage(for: asset, targetSize: fullSize, contentMode: .default, options: options) { image, _ in
|
||||
guard let image = image else {
|
||||
group.leave()
|
||||
return
|
||||
}
|
||||
processedImages.append(self.processedImage(from: image, with: asset.imageData))
|
||||
group.leave()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
group.notify(queue: .global(qos: .utility)) { [weak self] in
|
||||
self?.returnImages(processedImages)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
call.resolve([
|
||||
"photos": []
|
||||
])
|
||||
}
|
||||
}
|
||||
} else {
|
||||
call.unavailable("Not available on iOS 13")
|
||||
}
|
||||
}
|
||||
|
||||
@objc func getPhoto(_ call: CAPPluginCall) {
|
||||
self.multiple = false
|
||||
self.call = call
|
||||
self.settings = cameraSettings(from: call)
|
||||
|
||||
// Make sure they have all the necessary info.plist settings
|
||||
if let missingUsageDescription = checkUsageDescriptions() {
|
||||
CAPLog.print("⚡️ ", self.pluginId, "-", missingUsageDescription)
|
||||
call.reject(missingUsageDescription)
|
||||
return
|
||||
}
|
||||
|
||||
DispatchQueue.main.async {
|
||||
switch self.settings.source {
|
||||
case .prompt:
|
||||
self.showPrompt()
|
||||
case .camera:
|
||||
self.showCamera()
|
||||
case .photos:
|
||||
self.showPhotos()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@objc func pickImages(_ call: CAPPluginCall) {
|
||||
self.multiple = true
|
||||
self.call = call
|
||||
self.settings = cameraSettings(from: call)
|
||||
DispatchQueue.main.async {
|
||||
self.showPhotos()
|
||||
}
|
||||
}
|
||||
|
||||
private func checkUsageDescriptions() -> String? {
|
||||
if let dict = Bundle.main.infoDictionary {
|
||||
for key in CameraPropertyListKeys.allCases where dict[key.rawValue] == nil {
|
||||
return key.missingMessage
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
private func cameraSettings(from call: CAPPluginCall) -> CameraSettings {
|
||||
var settings = CameraSettings()
|
||||
settings.jpegQuality = min(abs(CGFloat(call.getFloat("quality") ?? 100.0)) / 100.0, 1.0)
|
||||
settings.allowEditing = call.getBool("allowEditing") ?? false
|
||||
settings.source = CameraSource(rawValue: call.getString("source") ?? defaultSource.rawValue) ?? defaultSource
|
||||
settings.direction = CameraDirection(rawValue: call.getString("direction") ?? defaultDirection.rawValue) ?? defaultDirection
|
||||
if let typeString = call.getString("resultType"), let type = CameraResultType(rawValue: typeString) {
|
||||
settings.resultType = type
|
||||
}
|
||||
settings.saveToGallery = call.getBool("saveToGallery") ?? false
|
||||
|
||||
// Get the new image dimensions if provided
|
||||
settings.width = CGFloat(call.getInt("width") ?? 0)
|
||||
settings.height = CGFloat(call.getInt("height") ?? 0)
|
||||
if settings.width > 0 || settings.height > 0 {
|
||||
// We resize only if a dimension was provided
|
||||
settings.shouldResize = true
|
||||
}
|
||||
settings.shouldCorrectOrientation = call.getBool("correctOrientation") ?? true
|
||||
settings.userPromptText = CameraPromptText(title: call.getString("promptLabelHeader"),
|
||||
photoAction: call.getString("promptLabelPhoto"),
|
||||
cameraAction: call.getString("promptLabelPicture"),
|
||||
cancelAction: call.getString("promptLabelCancel"))
|
||||
if let styleString = call.getString("presentationStyle"), styleString == "popover" {
|
||||
settings.presentationStyle = .popover
|
||||
} else {
|
||||
settings.presentationStyle = .fullScreen
|
||||
}
|
||||
|
||||
return settings
|
||||
}
|
||||
}
|
||||
|
||||
// public delegate methods
|
||||
extension CameraPlugin: UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
|
||||
public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
||||
picker.dismiss(animated: true)
|
||||
self.call?.reject("User cancelled photos app")
|
||||
}
|
||||
|
||||
public func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
|
||||
self.call?.reject("User cancelled photos app")
|
||||
}
|
||||
|
||||
public func presentationControllerDidDismiss(_ presentationController: UIPresentationController) {
|
||||
self.call?.reject("User cancelled photos app")
|
||||
}
|
||||
|
||||
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
|
||||
picker.dismiss(animated: true) {
|
||||
if let processedImage = self.processImage(from: info) {
|
||||
self.returnProcessedImage(processedImage)
|
||||
} else {
|
||||
self.call?.reject("Error processing image")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
extension CameraPlugin: PHPickerViewControllerDelegate {
|
||||
public func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) {
|
||||
picker.dismiss(animated: true, completion: nil)
|
||||
|
||||
guard !results.isEmpty else {
|
||||
self.call?.reject("User cancelled photos app")
|
||||
return
|
||||
}
|
||||
|
||||
self.fetchProcessedImages(from: results) { [weak self] processedImageArray in
|
||||
guard let processedImageArray else {
|
||||
self?.call?.reject("Error loading image")
|
||||
return
|
||||
}
|
||||
|
||||
if self?.multiple == true {
|
||||
self?.returnImages(processedImageArray)
|
||||
} else if var processedImage = processedImageArray.first {
|
||||
processedImage.flags = .gallery
|
||||
self?.returnProcessedImage(processedImage)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private func fetchProcessedImages(from pickerResultArray: [PHPickerResult], accumulating: [ProcessedImage] = [], _ completionHandler: @escaping ([ProcessedImage]?) -> Void) {
|
||||
func loadImage(from pickerResult: PHPickerResult, _ completionHandler: @escaping (UIImage?) -> Void) {
|
||||
let itemProvider = pickerResult.itemProvider
|
||||
if itemProvider.canLoadObject(ofClass: UIImage.self) {
|
||||
// extract the image
|
||||
itemProvider.loadObject(ofClass: UIImage.self) { itemProviderReading, _ in
|
||||
completionHandler(itemProviderReading as? UIImage)
|
||||
}
|
||||
} else {
|
||||
// extract the image's data representation
|
||||
itemProvider.loadDataRepresentation(forTypeIdentifier: UTType.image.identifier) { data, _ in
|
||||
guard let data else {
|
||||
return completionHandler(nil)
|
||||
}
|
||||
completionHandler(UIImage(data: data))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
guard let currentPickerResult = pickerResultArray.first else { return completionHandler(accumulating) }
|
||||
|
||||
loadImage(from: currentPickerResult) { [weak self] loadedImage in
|
||||
guard let self, let loadedImage else { return completionHandler(nil) }
|
||||
var asset: PHAsset?
|
||||
if let assetId = currentPickerResult.assetIdentifier {
|
||||
asset = PHAsset.fetchAssets(withLocalIdentifiers: [assetId], options: nil).firstObject
|
||||
}
|
||||
let newElement = self.processedImage(from: loadedImage, with: asset?.imageData)
|
||||
self.fetchProcessedImages(
|
||||
from: Array(pickerResultArray.dropFirst()),
|
||||
accumulating: accumulating + [newElement],
|
||||
completionHandler
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private extension CameraPlugin {
|
||||
func returnImage(_ processedImage: ProcessedImage, isSaved: Bool) {
|
||||
guard let jpeg = processedImage.generateJPEG(with: settings.jpegQuality) else {
|
||||
self.call?.reject("Unable to convert image to jpeg")
|
||||
return
|
||||
}
|
||||
|
||||
if settings.resultType == CameraResultType.uri || multiple {
|
||||
guard let fileURL = try? saveTemporaryImage(jpeg),
|
||||
let webURL = bridge?.portablePath(fromLocalURL: fileURL) else {
|
||||
call?.reject("Unable to get portable path to file")
|
||||
return
|
||||
}
|
||||
if self.multiple {
|
||||
call?.resolve([
|
||||
"photos": [[
|
||||
"path": fileURL.absoluteString,
|
||||
"exif": processedImage.exifData,
|
||||
"webPath": webURL.absoluteString,
|
||||
"format": "jpeg"
|
||||
]]
|
||||
])
|
||||
return
|
||||
}
|
||||
call?.resolve([
|
||||
"path": fileURL.absoluteString,
|
||||
"exif": processedImage.exifData,
|
||||
"webPath": webURL.absoluteString,
|
||||
"format": "jpeg",
|
||||
"saved": isSaved
|
||||
])
|
||||
} else if settings.resultType == CameraResultType.base64 {
|
||||
self.call?.resolve([
|
||||
"base64String": jpeg.base64EncodedString(),
|
||||
"exif": processedImage.exifData,
|
||||
"format": "jpeg",
|
||||
"saved": isSaved
|
||||
])
|
||||
} else if settings.resultType == CameraResultType.dataURL {
|
||||
call?.resolve([
|
||||
"dataUrl": "data:image/jpeg;base64," + jpeg.base64EncodedString(),
|
||||
"exif": processedImage.exifData,
|
||||
"format": "jpeg",
|
||||
"saved": isSaved
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
func returnImages(_ processedImages: [ProcessedImage]) {
|
||||
var photos: [PluginCallResultData] = []
|
||||
for processedImage in processedImages {
|
||||
guard let jpeg = processedImage.generateJPEG(with: settings.jpegQuality) else {
|
||||
self.call?.reject("Unable to convert image to jpeg")
|
||||
return
|
||||
}
|
||||
|
||||
guard let fileURL = try? saveTemporaryImage(jpeg),
|
||||
let webURL = bridge?.portablePath(fromLocalURL: fileURL) else {
|
||||
call?.reject("Unable to get portable path to file")
|
||||
return
|
||||
}
|
||||
|
||||
photos.append([
|
||||
"path": fileURL.absoluteString,
|
||||
"exif": processedImage.exifData,
|
||||
"webPath": webURL.absoluteString,
|
||||
"format": "jpeg"
|
||||
])
|
||||
}
|
||||
call?.resolve([
|
||||
"photos": photos
|
||||
])
|
||||
}
|
||||
|
||||
func returnProcessedImage(_ processedImage: ProcessedImage) {
|
||||
// conditionally save the image
|
||||
if settings.saveToGallery && (processedImage.flags.contains(.edited) == true || processedImage.flags.contains(.gallery) == false) {
|
||||
_ = ImageSaver(image: processedImage.image) { error in
|
||||
var isSaved = false
|
||||
if error == nil {
|
||||
isSaved = true
|
||||
}
|
||||
self.returnImage(processedImage, isSaved: isSaved)
|
||||
}
|
||||
} else {
|
||||
self.returnImage(processedImage, isSaved: false)
|
||||
}
|
||||
}
|
||||
|
||||
func showPrompt() {
|
||||
// Build the action sheet
|
||||
let alert = UIAlertController(title: settings.userPromptText.title, message: nil, preferredStyle: UIAlertController.Style.actionSheet)
|
||||
alert.addAction(UIAlertAction(title: settings.userPromptText.photoAction, style: .default, handler: { [weak self] (_: UIAlertAction) in
|
||||
self?.showPhotos()
|
||||
}))
|
||||
|
||||
alert.addAction(UIAlertAction(title: settings.userPromptText.cameraAction, style: .default, handler: { [weak self] (_: UIAlertAction) in
|
||||
self?.showCamera()
|
||||
}))
|
||||
|
||||
alert.addAction(UIAlertAction(title: settings.userPromptText.cancelAction, style: .cancel, handler: { [weak self] (_: UIAlertAction) in
|
||||
self?.call?.reject("User cancelled photos app")
|
||||
}))
|
||||
self.setCenteredPopover(alert)
|
||||
self.bridge?.viewController?.present(alert, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func showCamera() {
|
||||
// check if we have a camera
|
||||
if (bridge?.isSimEnvironment ?? false) || !UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
|
||||
CAPLog.print("⚡️ ", self.pluginId, "-", "Camera not available in simulator")
|
||||
call?.reject("Camera not available while running in Simulator")
|
||||
return
|
||||
}
|
||||
// check for permission
|
||||
let authStatus = AVCaptureDevice.authorizationStatus(for: .video)
|
||||
if authStatus == .restricted || authStatus == .denied {
|
||||
call?.reject("User denied access to camera")
|
||||
return
|
||||
}
|
||||
// we either already have permission or can prompt
|
||||
AVCaptureDevice.requestAccess(for: .video) { [weak self] granted in
|
||||
if granted {
|
||||
DispatchQueue.main.async {
|
||||
self?.presentCameraPicker()
|
||||
}
|
||||
} else {
|
||||
self?.call?.reject("User denied access to camera")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func showPhotos() {
|
||||
// check for permission
|
||||
let authStatus = PHPhotoLibrary.authorizationStatus()
|
||||
if authStatus == .restricted || authStatus == .denied {
|
||||
call?.reject("User denied access to photos")
|
||||
return
|
||||
}
|
||||
// we either already have permission or can prompt
|
||||
if authStatus == .authorized {
|
||||
presentSystemAppropriateImagePicker()
|
||||
} else {
|
||||
PHPhotoLibrary.requestAuthorization({ [weak self] (status) in
|
||||
if status == PHAuthorizationStatus.authorized {
|
||||
DispatchQueue.main.async { [weak self] in
|
||||
self?.presentSystemAppropriateImagePicker()
|
||||
}
|
||||
} else {
|
||||
self?.call?.reject("User denied access to photos")
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func presentCameraPicker() {
|
||||
let picker = UIImagePickerController()
|
||||
picker.delegate = self
|
||||
picker.allowsEditing = self.settings.allowEditing
|
||||
// select the input
|
||||
picker.sourceType = .camera
|
||||
if settings.direction == .rear, UIImagePickerController.isCameraDeviceAvailable(.rear) {
|
||||
picker.cameraDevice = .rear
|
||||
} else if settings.direction == .front, UIImagePickerController.isCameraDeviceAvailable(.front) {
|
||||
picker.cameraDevice = .front
|
||||
}
|
||||
// present
|
||||
picker.modalPresentationStyle = settings.presentationStyle
|
||||
if settings.presentationStyle == .popover {
|
||||
picker.popoverPresentationController?.delegate = self
|
||||
setCenteredPopover(picker)
|
||||
}
|
||||
bridge?.viewController?.present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func presentSystemAppropriateImagePicker() {
|
||||
if #available(iOS 14, *) {
|
||||
presentPhotoPicker()
|
||||
} else {
|
||||
presentImagePicker()
|
||||
}
|
||||
}
|
||||
|
||||
func presentImagePicker() {
|
||||
let picker = UIImagePickerController()
|
||||
picker.delegate = self
|
||||
picker.allowsEditing = self.settings.allowEditing
|
||||
// select the input
|
||||
picker.sourceType = .photoLibrary
|
||||
// present
|
||||
picker.modalPresentationStyle = settings.presentationStyle
|
||||
if settings.presentationStyle == .popover {
|
||||
picker.popoverPresentationController?.delegate = self
|
||||
setCenteredPopover(picker)
|
||||
}
|
||||
bridge?.viewController?.present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
@available(iOS 14, *)
|
||||
func presentPhotoPicker() {
|
||||
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
|
||||
configuration.selectionLimit = self.multiple ? (self.call?.getInt("limit") ?? 0) : 1
|
||||
configuration.filter = .images
|
||||
let picker = PHPickerViewController(configuration: configuration)
|
||||
picker.delegate = self
|
||||
// present
|
||||
picker.modalPresentationStyle = settings.presentationStyle
|
||||
if settings.presentationStyle == .popover {
|
||||
picker.popoverPresentationController?.delegate = self
|
||||
setCenteredPopover(picker)
|
||||
}
|
||||
bridge?.viewController?.present(picker, animated: true, completion: nil)
|
||||
}
|
||||
|
||||
func saveTemporaryImage(_ data: Data) throws -> URL {
|
||||
var url: URL
|
||||
repeat {
|
||||
imageCounter += 1
|
||||
url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("photo-\(imageCounter).jpg")
|
||||
} while FileManager.default.fileExists(atPath: url.path)
|
||||
|
||||
try data.write(to: url, options: .atomic)
|
||||
return url
|
||||
}
|
||||
|
||||
func processImage(from info: [UIImagePickerController.InfoKey: Any]) -> ProcessedImage? {
|
||||
var selectedImage: UIImage?
|
||||
var flags: PhotoFlags = []
|
||||
// get the image
|
||||
if let edited = info[UIImagePickerController.InfoKey.editedImage] as? UIImage {
|
||||
selectedImage = edited // use the edited version
|
||||
flags = flags.union([.edited])
|
||||
} else if let original = info[UIImagePickerController.InfoKey.originalImage] as? UIImage {
|
||||
selectedImage = original // use the original version
|
||||
}
|
||||
guard let image = selectedImage else {
|
||||
return nil
|
||||
}
|
||||
var metadata: [String: Any] = [:]
|
||||
// get the image's metadata from the picker or from the photo album
|
||||
if let photoMetadata = info[UIImagePickerController.InfoKey.mediaMetadata] as? [String: Any] {
|
||||
metadata = photoMetadata
|
||||
} else {
|
||||
flags = flags.union([.gallery])
|
||||
}
|
||||
if let asset = info[UIImagePickerController.InfoKey.phAsset] as? PHAsset {
|
||||
metadata = asset.imageData
|
||||
}
|
||||
// get the result
|
||||
var result = processedImage(from: image, with: metadata)
|
||||
result.flags = flags
|
||||
return result
|
||||
}
|
||||
|
||||
func processedImage(from image: UIImage, with metadata: [String: Any]?) -> ProcessedImage {
|
||||
var result = ProcessedImage(image: image, metadata: metadata ?? [:])
|
||||
// resizing the image only makes sense if we have real values to which to constrain it
|
||||
if settings.shouldResize, settings.width > 0 || settings.height > 0 {
|
||||
result.image = result.image.reformat(to: CGSize(width: settings.width, height: settings.height))
|
||||
result.overwriteMetadataOrientation(to: 1)
|
||||
} else if settings.shouldCorrectOrientation {
|
||||
// resizing implicitly reformats the image so this is only needed if we aren't resizing
|
||||
result.image = result.image.reformat()
|
||||
result.overwriteMetadataOrientation(to: 1)
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
||||
142
node_modules/@capacitor/camera/ios/Sources/CameraPlugin/CameraTypes.swift
generated
vendored
Normal file
142
node_modules/@capacitor/camera/ios/Sources/CameraPlugin/CameraTypes.swift
generated
vendored
Normal file
@@ -0,0 +1,142 @@
|
||||
import UIKit
|
||||
|
||||
// MARK: - Public
|
||||
|
||||
public enum CameraSource: String {
|
||||
case prompt = "PROMPT"
|
||||
case camera = "CAMERA"
|
||||
case photos = "PHOTOS"
|
||||
}
|
||||
|
||||
public enum CameraDirection: String {
|
||||
case rear = "REAR"
|
||||
case front = "FRONT"
|
||||
}
|
||||
|
||||
public enum CameraResultType: String {
|
||||
case base64
|
||||
case uri
|
||||
case dataURL = "dataUrl"
|
||||
}
|
||||
|
||||
struct CameraPromptText {
|
||||
let title: String
|
||||
let photoAction: String
|
||||
let cameraAction: String
|
||||
let cancelAction: String
|
||||
|
||||
init(title: String? = nil, photoAction: String? = nil, cameraAction: String? = nil, cancelAction: String? = nil) {
|
||||
self.title = title ?? "Photo"
|
||||
self.photoAction = photoAction ?? "From Photos"
|
||||
self.cameraAction = cameraAction ?? "Take Picture"
|
||||
self.cancelAction = cancelAction ?? "Cancel"
|
||||
}
|
||||
}
|
||||
|
||||
public struct CameraSettings {
|
||||
var source: CameraSource = CameraSource.prompt
|
||||
var direction: CameraDirection = CameraDirection.rear
|
||||
var resultType = CameraResultType.base64
|
||||
var userPromptText = CameraPromptText()
|
||||
var jpegQuality: CGFloat = 1.0
|
||||
var width: CGFloat = 0
|
||||
var height: CGFloat = 0
|
||||
var allowEditing = false
|
||||
var shouldResize = false
|
||||
var shouldCorrectOrientation = true
|
||||
var saveToGallery = false
|
||||
var presentationStyle = UIModalPresentationStyle.fullScreen
|
||||
}
|
||||
|
||||
public struct CameraResult {
|
||||
let image: UIImage?
|
||||
let metadata: [AnyHashable: Any]
|
||||
}
|
||||
|
||||
// MARK: - Internal
|
||||
|
||||
internal enum CameraPermissionType: String, CaseIterable {
|
||||
case camera
|
||||
case photos
|
||||
}
|
||||
|
||||
internal enum CameraPropertyListKeys: String, CaseIterable {
|
||||
case photoLibraryAddUsage = "NSPhotoLibraryAddUsageDescription"
|
||||
case photoLibraryUsage = "NSPhotoLibraryUsageDescription"
|
||||
case cameraUsage = "NSCameraUsageDescription"
|
||||
|
||||
var link: String {
|
||||
switch self {
|
||||
case .photoLibraryAddUsage:
|
||||
return "https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW73"
|
||||
case .photoLibraryUsage:
|
||||
return "https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW17"
|
||||
case .cameraUsage:
|
||||
return "https://developer.apple.com/library/content/documentation/General/Reference/InfoPlistKeyReference/Articles/CocoaKeys.html#//apple_ref/doc/uid/TP40009251-SW24"
|
||||
}
|
||||
}
|
||||
|
||||
var missingMessage: String {
|
||||
return "You are missing \(self.rawValue) in your Info.plist file." +
|
||||
" Camera will not function without it. Learn more: \(self.link)"
|
||||
}
|
||||
}
|
||||
|
||||
internal struct PhotoFlags: OptionSet {
|
||||
let rawValue: Int
|
||||
|
||||
static let edited = PhotoFlags(rawValue: 1 << 0)
|
||||
static let gallery = PhotoFlags(rawValue: 1 << 1)
|
||||
|
||||
static let all: PhotoFlags = [.edited, .gallery]
|
||||
}
|
||||
|
||||
internal struct ProcessedImage {
|
||||
var image: UIImage
|
||||
var metadata: [String: Any]
|
||||
var flags: PhotoFlags = []
|
||||
|
||||
var exifData: [String: Any] {
|
||||
var exifData = metadata["{Exif}"] as? [String: Any]
|
||||
exifData?["Orientation"] = metadata["Orientation"]
|
||||
exifData?["GPS"] = metadata["{GPS}"]
|
||||
return exifData ?? [:]
|
||||
}
|
||||
|
||||
mutating func overwriteMetadataOrientation(to orientation: Int) {
|
||||
replaceDictionaryOrientation(atNode: &metadata, to: orientation)
|
||||
}
|
||||
|
||||
func replaceDictionaryOrientation(atNode node: inout [String: Any], to orientation: Int) {
|
||||
for key in node.keys {
|
||||
if key == "Orientation", (node[key] as? Int) != nil {
|
||||
node[key] = orientation
|
||||
} else if var child = node[key] as? [String: Any] {
|
||||
replaceDictionaryOrientation(atNode: &child, to: orientation)
|
||||
node[key] = child
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func generateJPEG(with quality: CGFloat) -> Data? {
|
||||
// convert the UIImage to a jpeg
|
||||
guard let data = self.image.jpegData(compressionQuality: quality) else {
|
||||
return nil
|
||||
}
|
||||
// define our jpeg data as an image source and get its type
|
||||
guard let source = CGImageSourceCreateWithData(data as CFData, nil), let type = CGImageSourceGetType(source) else {
|
||||
return data
|
||||
}
|
||||
// allocate an output buffer and create the destination to receive the new data
|
||||
guard let output = NSMutableData(capacity: data.count), let destination = CGImageDestinationCreateWithData(output, type, 1, nil) else {
|
||||
return data
|
||||
}
|
||||
// pipe the source into the destination while overwriting the metadata, this encodes the metadata information into the image
|
||||
CGImageDestinationAddImageFromSource(destination, source, 0, self.metadata as CFDictionary)
|
||||
// finish
|
||||
guard CGImageDestinationFinalize(destination) else {
|
||||
return data
|
||||
}
|
||||
return output as Data
|
||||
}
|
||||
}
|
||||
20
node_modules/@capacitor/camera/ios/Sources/CameraPlugin/ImageSaver.swift
generated
vendored
Normal file
20
node_modules/@capacitor/camera/ios/Sources/CameraPlugin/ImageSaver.swift
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
import UIKit
|
||||
|
||||
class ImageSaver: NSObject {
|
||||
|
||||
var onResult: ((Error?) -> Void) = {_ in }
|
||||
|
||||
init(image: UIImage, onResult: @escaping ((Error?) -> Void)) {
|
||||
self.onResult = onResult
|
||||
super.init()
|
||||
UIImageWriteToSavedPhotosAlbum(image, self, #selector(saveResult), nil)
|
||||
}
|
||||
|
||||
@objc func saveResult(_ image: UIImage, didFinishSavingWithError error: Error?, contextInfo: UnsafeRawPointer) {
|
||||
if let error = error {
|
||||
onResult(error)
|
||||
} else {
|
||||
onResult(nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
12
node_modules/@capacitor/camera/ios/Tests/CameraPluginTests/CameraPluginTests.swift
generated
vendored
Normal file
12
node_modules/@capacitor/camera/ios/Tests/CameraPluginTests/CameraPluginTests.swift
generated
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
import XCTest
|
||||
@testable import CameraPlugin
|
||||
|
||||
final class CameraPluginTests: XCTestCase {
|
||||
func testExample() throws {
|
||||
// XCTest Documentation
|
||||
// https://developer.apple.com/documentation/xctest
|
||||
|
||||
// Defining Test Cases and Test Methods
|
||||
// https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods
|
||||
}
|
||||
}
|
||||
85
node_modules/@capacitor/camera/package.json
generated
vendored
Normal file
85
node_modules/@capacitor/camera/package.json
generated
vendored
Normal file
@@ -0,0 +1,85 @@
|
||||
{
|
||||
"name": "@capacitor/camera",
|
||||
"version": "7.0.2",
|
||||
"description": "The Camera API provides the ability to take a photo with the camera or choose an existing one from the photo album.",
|
||||
"main": "dist/plugin.cjs.js",
|
||||
"module": "dist/esm/index.js",
|
||||
"types": "dist/esm/index.d.ts",
|
||||
"unpkg": "dist/plugin.js",
|
||||
"files": [
|
||||
"android/src/main/",
|
||||
"android/build.gradle",
|
||||
"dist/",
|
||||
"ios/Sources",
|
||||
"ios/Tests",
|
||||
"Package.swift",
|
||||
"CapacitorCamera.podspec"
|
||||
],
|
||||
"author": "Ionic <hi@ionicframework.com>",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/ionic-team/capacitor-plugins.git"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/ionic-team/capacitor-plugins/issues"
|
||||
},
|
||||
"keywords": [
|
||||
"capacitor",
|
||||
"plugin",
|
||||
"native"
|
||||
],
|
||||
"scripts": {
|
||||
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
||||
"verify:ios": "xcodebuild build -scheme CapacitorCamera -destination generic/platform=iOS",
|
||||
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
||||
"verify:web": "npm run build",
|
||||
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
||||
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
||||
"eslint": "eslint . --ext ts",
|
||||
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
||||
"swiftlint": "node-swiftlint",
|
||||
"docgen": "docgen --api CameraPlugin --output-readme README.md --output-json dist/docs.json",
|
||||
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
||||
"clean": "rimraf ./dist",
|
||||
"watch": "tsc --watch",
|
||||
"prepublishOnly": "npm run build",
|
||||
"publish:cocoapod": "pod trunk push ./CapacitorCamera.podspec --allow-warnings"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@capacitor/android": "^7.0.0",
|
||||
"@capacitor/core": "^7.0.0",
|
||||
"@capacitor/docgen": "0.2.2",
|
||||
"@capacitor/ios": "^7.0.0",
|
||||
"@ionic/eslint-config": "^0.4.0",
|
||||
"@ionic/prettier-config": "~1.0.1",
|
||||
"@ionic/swiftlint-config": "^1.1.2",
|
||||
"eslint": "^8.57.0",
|
||||
"prettier": "~2.3.0",
|
||||
"prettier-plugin-java": "~1.0.2",
|
||||
"rimraf": "^6.0.1",
|
||||
"rollup": "^4.26.0",
|
||||
"swiftlint": "^1.0.1",
|
||||
"typescript": "~4.1.5"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@capacitor/core": ">=7.0.0"
|
||||
},
|
||||
"prettier": "@ionic/prettier-config",
|
||||
"swiftlint": "@ionic/swiftlint-config",
|
||||
"eslintConfig": {
|
||||
"extends": "@ionic/eslint-config/recommended"
|
||||
},
|
||||
"capacitor": {
|
||||
"ios": {
|
||||
"src": "ios"
|
||||
},
|
||||
"android": {
|
||||
"src": "android"
|
||||
}
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"gitHead": "7c53a4c249abe958983f1ac9df04dec7ab89c10e"
|
||||
}
|
||||
Reference in New Issue
Block a user