|
|
@ -1,8 +1,12 @@
|
|
|
|
import UIKit
|
|
|
|
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
|
|
|
|
import WebKit
|
|
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
import Tauri
|
|
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
|
|
|
|
|
|
|
|
import Photos
|
|
|
|
import Photos
|
|
|
|
import PhotosUI
|
|
|
|
import PhotosUI
|
|
|
|
|
|
|
|
import Tauri
|
|
|
|
|
|
|
|
import UIKit
|
|
|
|
|
|
|
|
import WebKit
|
|
|
|
|
|
|
|
|
|
|
|
public class CameraPlugin: Plugin {
|
|
|
|
public class CameraPlugin: Plugin {
|
|
|
|
private var invoke: Invoke?
|
|
|
|
private var invoke: Invoke?
|
|
|
@ -34,11 +38,13 @@ public class CameraPlugin: Plugin {
|
|
|
|
|
|
|
|
|
|
|
|
@objc override public func requestPermissions(_ invoke: Invoke) {
|
|
|
|
@objc override public func requestPermissions(_ invoke: Invoke) {
|
|
|
|
// get the list of desired types, if passed
|
|
|
|
// get the list of desired types, if passed
|
|
|
|
let typeList = invoke.getArray("permissions", String.self)?.compactMap({ (type) -> CameraPermissionType? in
|
|
|
|
let typeList =
|
|
|
|
|
|
|
|
invoke.getArray("permissions", String.self)?.compactMap({ (type) -> CameraPermissionType? in
|
|
|
|
return CameraPermissionType(rawValue: type)
|
|
|
|
return CameraPermissionType(rawValue: type)
|
|
|
|
}) ?? []
|
|
|
|
}) ?? []
|
|
|
|
// otherwise check everything
|
|
|
|
// otherwise check everything
|
|
|
|
let permissions: [CameraPermissionType] = (typeList.count > 0) ? typeList : CameraPermissionType.allCases
|
|
|
|
let permissions: [CameraPermissionType] =
|
|
|
|
|
|
|
|
(typeList.count > 0) ? typeList : CameraPermissionType.allCases
|
|
|
|
// request the permissions
|
|
|
|
// request the permissions
|
|
|
|
let group = DispatchGroup()
|
|
|
|
let group = DispatchGroup()
|
|
|
|
for permission in permissions {
|
|
|
|
for permission in permissions {
|
|
|
@ -115,7 +121,9 @@ public class CameraPlugin: Plugin {
|
|
|
|
let fullSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
|
|
|
|
let fullSize = CGSize(width: asset.pixelWidth, height: asset.pixelHeight)
|
|
|
|
|
|
|
|
|
|
|
|
group.enter()
|
|
|
|
group.enter()
|
|
|
|
imageManager.requestImage(for: asset, targetSize: fullSize, contentMode: .default, options: options) { image, _ in
|
|
|
|
imageManager.requestImage(
|
|
|
|
|
|
|
|
for: asset, targetSize: fullSize, contentMode: .default, options: options
|
|
|
|
|
|
|
|
) { image, _ in
|
|
|
|
guard let image = image else {
|
|
|
|
guard let image = image else {
|
|
|
|
group.leave()
|
|
|
|
group.leave()
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -186,9 +194,14 @@ public class CameraPlugin: Plugin {
|
|
|
|
var settings = CameraSettings()
|
|
|
|
var settings = CameraSettings()
|
|
|
|
settings.jpegQuality = min(abs(CGFloat(invoke.getFloat("quality") ?? 100.0)) / 100.0, 1.0)
|
|
|
|
settings.jpegQuality = min(abs(CGFloat(invoke.getFloat("quality") ?? 100.0)) / 100.0, 1.0)
|
|
|
|
settings.allowEditing = invoke.getBool("allowEditing") ?? false
|
|
|
|
settings.allowEditing = invoke.getBool("allowEditing") ?? false
|
|
|
|
settings.source = CameraSource(rawValue: invoke.getString("source") ?? defaultSource.rawValue) ?? defaultSource
|
|
|
|
settings.source =
|
|
|
|
settings.direction = CameraDirection(rawValue: invoke.getString("direction") ?? defaultDirection.rawValue) ?? defaultDirection
|
|
|
|
CameraSource(rawValue: invoke.getString("source") ?? defaultSource.rawValue) ?? defaultSource
|
|
|
|
if let typeString = invoke.getString("resultType"), let type = CameraResultType(rawValue: typeString) {
|
|
|
|
settings.direction =
|
|
|
|
|
|
|
|
CameraDirection(rawValue: invoke.getString("direction") ?? defaultDirection.rawValue)
|
|
|
|
|
|
|
|
?? defaultDirection
|
|
|
|
|
|
|
|
if let typeString = invoke.getString("resultType"),
|
|
|
|
|
|
|
|
let type = CameraResultType(rawValue: typeString)
|
|
|
|
|
|
|
|
{
|
|
|
|
settings.resultType = type
|
|
|
|
settings.resultType = type
|
|
|
|
}
|
|
|
|
}
|
|
|
|
settings.saveToGallery = invoke.getBool("saveToGallery") ?? false
|
|
|
|
settings.saveToGallery = invoke.getBool("saveToGallery") ?? false
|
|
|
@ -201,7 +214,8 @@ public class CameraPlugin: Plugin {
|
|
|
|
settings.shouldResize = true
|
|
|
|
settings.shouldResize = true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
settings.shouldCorrectOrientation = invoke.getBool("correctOrientation") ?? true
|
|
|
|
settings.shouldCorrectOrientation = invoke.getBool("correctOrientation") ?? true
|
|
|
|
settings.userPromptText = CameraPromptText(title: invoke.getString("promptLabelHeader"),
|
|
|
|
settings.userPromptText = CameraPromptText(
|
|
|
|
|
|
|
|
title: invoke.getString("promptLabelHeader"),
|
|
|
|
photoAction: invoke.getString("promptLabelPhoto"),
|
|
|
|
photoAction: invoke.getString("promptLabelPhoto"),
|
|
|
|
cameraAction: invoke.getString("promptLabelPicture"),
|
|
|
|
cameraAction: invoke.getString("promptLabelPicture"),
|
|
|
|
cancelAction: invoke.getString("promptLabelCancel"))
|
|
|
|
cancelAction: invoke.getString("promptLabelCancel"))
|
|
|
@ -216,13 +230,17 @@ public class CameraPlugin: Plugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// public delegate methods
|
|
|
|
// public delegate methods
|
|
|
|
extension CameraPlugin: UIImagePickerControllerDelegate, UINavigationControllerDelegate, UIPopoverPresentationControllerDelegate {
|
|
|
|
extension CameraPlugin: UIImagePickerControllerDelegate, UINavigationControllerDelegate,
|
|
|
|
|
|
|
|
UIPopoverPresentationControllerDelegate
|
|
|
|
|
|
|
|
{
|
|
|
|
public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
|
|
|
public func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
|
|
|
picker.dismiss(animated: true)
|
|
|
|
picker.dismiss(animated: true)
|
|
|
|
self.invoke?.reject("User cancelled photos app")
|
|
|
|
self.invoke?.reject("User cancelled photos app")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func popoverPresentationControllerDidDismissPopover(_ popoverPresentationController: UIPopoverPresentationController) {
|
|
|
|
public func popoverPresentationControllerDidDismissPopover(
|
|
|
|
|
|
|
|
_ popoverPresentationController: UIPopoverPresentationController
|
|
|
|
|
|
|
|
) {
|
|
|
|
self.invoke?.reject("User cancelled photos app")
|
|
|
|
self.invoke?.reject("User cancelled photos app")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -230,7 +248,10 @@ extension CameraPlugin: UIImagePickerControllerDelegate, UINavigationControllerD
|
|
|
|
self.invoke?.reject("User cancelled photos app")
|
|
|
|
self.invoke?.reject("User cancelled photos app")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]) {
|
|
|
|
public func imagePickerController(
|
|
|
|
|
|
|
|
_ picker: UIImagePickerController,
|
|
|
|
|
|
|
|
didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey: Any]
|
|
|
|
|
|
|
|
) {
|
|
|
|
picker.dismiss(animated: true) {
|
|
|
|
picker.dismiss(animated: true) {
|
|
|
|
if let processedImage = self.processImage(from: info) {
|
|
|
|
if let processedImage = self.processImage(from: info) {
|
|
|
|
self.returnProcessedImage(processedImage)
|
|
|
|
self.returnProcessedImage(processedImage)
|
|
|
@ -301,8 +322,8 @@ extension CameraPlugin: PHPickerViewControllerDelegate {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private extension CameraPlugin {
|
|
|
|
extension CameraPlugin {
|
|
|
|
func returnImage(_ processedImage: ProcessedImage, isSaved: Bool) {
|
|
|
|
fileprivate func returnImage(_ processedImage: ProcessedImage, isSaved: Bool) {
|
|
|
|
guard let jpeg = processedImage.generateJPEG(with: settings.jpegQuality) else {
|
|
|
|
guard let jpeg = processedImage.generateJPEG(with: settings.jpegQuality) else {
|
|
|
|
self.invoke?.reject("Unable to convert image to jpeg")
|
|
|
|
self.invoke?.reject("Unable to convert image to jpeg")
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -310,18 +331,21 @@ private extension CameraPlugin {
|
|
|
|
|
|
|
|
|
|
|
|
if settings.resultType == CameraResultType.uri || multiple {
|
|
|
|
if settings.resultType == CameraResultType.uri || multiple {
|
|
|
|
guard let fileURL = try? saveTemporaryImage(jpeg),
|
|
|
|
guard let fileURL = try? saveTemporaryImage(jpeg),
|
|
|
|
let webURL = manager.assetUrl(fromLocalURL: fileURL) else {
|
|
|
|
let webURL = manager.assetUrl(fromLocalURL: fileURL)
|
|
|
|
|
|
|
|
else {
|
|
|
|
invoke?.reject("Unable to get asset URL to file")
|
|
|
|
invoke?.reject("Unable to get asset URL to file")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if self.multiple {
|
|
|
|
if self.multiple {
|
|
|
|
invoke?.resolve([
|
|
|
|
invoke?.resolve([
|
|
|
|
"photos": [[
|
|
|
|
"photos": [
|
|
|
|
|
|
|
|
[
|
|
|
|
"data": fileURL.absoluteString,
|
|
|
|
"data": fileURL.absoluteString,
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"assetUrl": webURL.absoluteString,
|
|
|
|
"assetUrl": webURL.absoluteString,
|
|
|
|
"format": "jpeg"
|
|
|
|
"format": "jpeg",
|
|
|
|
]]
|
|
|
|
]
|
|
|
|
|
|
|
|
]
|
|
|
|
])
|
|
|
|
])
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -330,26 +354,26 @@ private extension CameraPlugin {
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"assetUrl": webURL.absoluteString,
|
|
|
|
"assetUrl": webURL.absoluteString,
|
|
|
|
"format": "jpeg",
|
|
|
|
"format": "jpeg",
|
|
|
|
"saved": isSaved
|
|
|
|
"saved": isSaved,
|
|
|
|
])
|
|
|
|
])
|
|
|
|
} else if settings.resultType == CameraResultType.base64 {
|
|
|
|
} else if settings.resultType == CameraResultType.base64 {
|
|
|
|
self.invoke?.resolve([
|
|
|
|
self.invoke?.resolve([
|
|
|
|
"data": jpeg.base64EncodedString(),
|
|
|
|
"data": jpeg.base64EncodedString(),
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"format": "jpeg",
|
|
|
|
"format": "jpeg",
|
|
|
|
"saved": isSaved
|
|
|
|
"saved": isSaved,
|
|
|
|
])
|
|
|
|
])
|
|
|
|
} else if settings.resultType == CameraResultType.dataURL {
|
|
|
|
} else if settings.resultType == CameraResultType.dataURL {
|
|
|
|
invoke?.resolve([
|
|
|
|
invoke?.resolve([
|
|
|
|
"data": "data:image/jpeg;base64," + jpeg.base64EncodedString(),
|
|
|
|
"data": "data:image/jpeg;base64," + jpeg.base64EncodedString(),
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"format": "jpeg",
|
|
|
|
"format": "jpeg",
|
|
|
|
"saved": isSaved
|
|
|
|
"saved": isSaved,
|
|
|
|
])
|
|
|
|
])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func returnImages(_ processedImages: [ProcessedImage]) {
|
|
|
|
fileprivate func returnImages(_ processedImages: [ProcessedImage]) {
|
|
|
|
var photos: [JsonObject] = []
|
|
|
|
var photos: [JsonObject] = []
|
|
|
|
for processedImage in processedImages {
|
|
|
|
for processedImage in processedImages {
|
|
|
|
guard let jpeg = processedImage.generateJPEG(with: settings.jpegQuality) else {
|
|
|
|
guard let jpeg = processedImage.generateJPEG(with: settings.jpegQuality) else {
|
|
|
@ -358,7 +382,8 @@ private extension CameraPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
guard let fileURL = try? saveTemporaryImage(jpeg),
|
|
|
|
guard let fileURL = try? saveTemporaryImage(jpeg),
|
|
|
|
let webURL = manager.assetUrl(fromLocalURL: fileURL) else {
|
|
|
|
let webURL = manager.assetUrl(fromLocalURL: fileURL)
|
|
|
|
|
|
|
|
else {
|
|
|
|
invoke?.reject("Unable to get asset URL to file")
|
|
|
|
invoke?.reject("Unable to get asset URL to file")
|
|
|
|
return
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -367,7 +392,7 @@ private extension CameraPlugin {
|
|
|
|
"path": fileURL.absoluteString,
|
|
|
|
"path": fileURL.absoluteString,
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"exif": processedImage.exifData,
|
|
|
|
"assetUrl": webURL.absoluteString,
|
|
|
|
"assetUrl": webURL.absoluteString,
|
|
|
|
"format": "jpeg"
|
|
|
|
"format": "jpeg",
|
|
|
|
])
|
|
|
|
])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
invoke?.resolve([
|
|
|
|
invoke?.resolve([
|
|
|
@ -375,9 +400,12 @@ private extension CameraPlugin {
|
|
|
|
])
|
|
|
|
])
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func returnProcessedImage(_ processedImage: ProcessedImage) {
|
|
|
|
fileprivate func returnProcessedImage(_ processedImage: ProcessedImage) {
|
|
|
|
// conditionally save the image
|
|
|
|
// conditionally save the image
|
|
|
|
if settings.saveToGallery && (processedImage.flags.contains(.edited) == true || processedImage.flags.contains(.gallery) == false) {
|
|
|
|
if settings.saveToGallery
|
|
|
|
|
|
|
|
&& (processedImage.flags.contains(.edited) == true
|
|
|
|
|
|
|
|
|| processedImage.flags.contains(.gallery) == false)
|
|
|
|
|
|
|
|
{
|
|
|
|
_ = ImageSaver(image: processedImage.image) { error in
|
|
|
|
_ = ImageSaver(image: processedImage.image) { error in
|
|
|
|
var isSaved = false
|
|
|
|
var isSaved = false
|
|
|
|
if error == nil {
|
|
|
|
if error == nil {
|
|
|
@ -390,27 +418,40 @@ private extension CameraPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func showPrompt() {
|
|
|
|
fileprivate func showPrompt() {
|
|
|
|
// Build the action sheet
|
|
|
|
// Build the action sheet
|
|
|
|
let alert = UIAlertController(title: settings.userPromptText.title, message: nil, preferredStyle: UIAlertController.Style.actionSheet)
|
|
|
|
let alert = UIAlertController(
|
|
|
|
alert.addAction(UIAlertAction(title: settings.userPromptText.photoAction, style: .default, handler: { [weak self] (_: UIAlertAction) in
|
|
|
|
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()
|
|
|
|
self?.showPhotos()
|
|
|
|
}))
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
alert.addAction(UIAlertAction(title: settings.userPromptText.cameraAction, style: .default, handler: { [weak self] (_: UIAlertAction) in
|
|
|
|
alert.addAction(
|
|
|
|
|
|
|
|
UIAlertAction(
|
|
|
|
|
|
|
|
title: settings.userPromptText.cameraAction, style: .default,
|
|
|
|
|
|
|
|
handler: { [weak self] (_: UIAlertAction) in
|
|
|
|
self?.showCamera()
|
|
|
|
self?.showCamera()
|
|
|
|
}))
|
|
|
|
}))
|
|
|
|
|
|
|
|
|
|
|
|
alert.addAction(UIAlertAction(title: settings.userPromptText.cancelAction, style: .cancel, handler: { [weak self] (_: UIAlertAction) in
|
|
|
|
alert.addAction(
|
|
|
|
|
|
|
|
UIAlertAction(
|
|
|
|
|
|
|
|
title: settings.userPromptText.cancelAction, style: .cancel,
|
|
|
|
|
|
|
|
handler: { [weak self] (_: UIAlertAction) in
|
|
|
|
self?.invoke?.reject("User cancelled photos app prompt")
|
|
|
|
self?.invoke?.reject("User cancelled photos app prompt")
|
|
|
|
}))
|
|
|
|
}))
|
|
|
|
UIUtils.centerPopover(rootViewController: manager.viewController, popoverController: alert)
|
|
|
|
UIUtils.centerPopover(rootViewController: manager.viewController, popoverController: alert)
|
|
|
|
self.manager.viewController?.present(alert, animated: true, completion: nil)
|
|
|
|
self.manager.viewController?.present(alert, animated: true, completion: nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func showCamera() {
|
|
|
|
fileprivate func showCamera() {
|
|
|
|
// check if we have a camera
|
|
|
|
// check if we have a camera
|
|
|
|
if manager.isSimEnvironment || !UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera) {
|
|
|
|
if manager.isSimEnvironment
|
|
|
|
|
|
|
|
|| !UIImagePickerController.isSourceTypeAvailable(UIImagePickerController.SourceType.camera)
|
|
|
|
|
|
|
|
{
|
|
|
|
Logger.error("[PLUGIN]", "Camera", "-", "Camera not available in simulator")
|
|
|
|
Logger.error("[PLUGIN]", "Camera", "-", "Camera not available in simulator")
|
|
|
|
invoke?.reject("Camera not available while running in Simulator")
|
|
|
|
invoke?.reject("Camera not available while running in Simulator")
|
|
|
|
return
|
|
|
|
return
|
|
|
@ -433,7 +474,7 @@ private extension CameraPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func showPhotos() {
|
|
|
|
fileprivate func showPhotos() {
|
|
|
|
// check for permission
|
|
|
|
// check for permission
|
|
|
|
let authStatus = PHPhotoLibrary.authorizationStatus()
|
|
|
|
let authStatus = PHPhotoLibrary.authorizationStatus()
|
|
|
|
if authStatus == .restricted || authStatus == .denied {
|
|
|
|
if authStatus == .restricted || authStatus == .denied {
|
|
|
@ -456,7 +497,7 @@ private extension CameraPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func presentCameraPicker() {
|
|
|
|
fileprivate func presentCameraPicker() {
|
|
|
|
let picker = UIImagePickerController()
|
|
|
|
let picker = UIImagePickerController()
|
|
|
|
picker.delegate = self
|
|
|
|
picker.delegate = self
|
|
|
|
picker.allowsEditing = self.settings.allowEditing
|
|
|
|
picker.allowsEditing = self.settings.allowEditing
|
|
|
@ -464,7 +505,8 @@ private extension CameraPlugin {
|
|
|
|
picker.sourceType = .camera
|
|
|
|
picker.sourceType = .camera
|
|
|
|
if settings.direction == .rear, UIImagePickerController.isCameraDeviceAvailable(.rear) {
|
|
|
|
if settings.direction == .rear, UIImagePickerController.isCameraDeviceAvailable(.rear) {
|
|
|
|
picker.cameraDevice = .rear
|
|
|
|
picker.cameraDevice = .rear
|
|
|
|
} else if settings.direction == .front, UIImagePickerController.isCameraDeviceAvailable(.front) {
|
|
|
|
} else if settings.direction == .front, UIImagePickerController.isCameraDeviceAvailable(.front)
|
|
|
|
|
|
|
|
{
|
|
|
|
picker.cameraDevice = .front
|
|
|
|
picker.cameraDevice = .front
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// present
|
|
|
|
// present
|
|
|
@ -476,7 +518,7 @@ private extension CameraPlugin {
|
|
|
|
manager.viewController?.present(picker, animated: true, completion: nil)
|
|
|
|
manager.viewController?.present(picker, animated: true, completion: nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func presentSystemAppropriateImagePicker() {
|
|
|
|
fileprivate func presentSystemAppropriateImagePicker() {
|
|
|
|
if #available(iOS 14, *) {
|
|
|
|
if #available(iOS 14, *) {
|
|
|
|
presentPhotoPicker()
|
|
|
|
presentPhotoPicker()
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
@ -484,7 +526,7 @@ private extension CameraPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func presentImagePicker() {
|
|
|
|
fileprivate func presentImagePicker() {
|
|
|
|
let picker = UIImagePickerController()
|
|
|
|
let picker = UIImagePickerController()
|
|
|
|
picker.delegate = self
|
|
|
|
picker.delegate = self
|
|
|
|
picker.allowsEditing = self.settings.allowEditing
|
|
|
|
picker.allowsEditing = self.settings.allowEditing
|
|
|
@ -500,7 +542,7 @@ private extension CameraPlugin {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@available(iOS 14, *)
|
|
|
|
@available(iOS 14, *)
|
|
|
|
func presentPhotoPicker() {
|
|
|
|
fileprivate func presentPhotoPicker() {
|
|
|
|
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
|
|
|
|
var configuration = PHPickerConfiguration(photoLibrary: PHPhotoLibrary.shared())
|
|
|
|
configuration.selectionLimit = self.multiple ? (self.invoke?.getInt("limit") ?? 0) : 1
|
|
|
|
configuration.selectionLimit = self.multiple ? (self.invoke?.getInt("limit") ?? 0) : 1
|
|
|
|
configuration.filter = .images
|
|
|
|
configuration.filter = .images
|
|
|
@ -515,18 +557,21 @@ private extension CameraPlugin {
|
|
|
|
manager.viewController?.present(picker, animated: true, completion: nil)
|
|
|
|
manager.viewController?.present(picker, animated: true, completion: nil)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func saveTemporaryImage(_ data: Data) throws -> URL {
|
|
|
|
fileprivate func saveTemporaryImage(_ data: Data) throws -> URL {
|
|
|
|
var url: URL
|
|
|
|
var url: URL
|
|
|
|
repeat {
|
|
|
|
repeat {
|
|
|
|
imageCounter += 1
|
|
|
|
imageCounter += 1
|
|
|
|
url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("photo-\(imageCounter).jpg")
|
|
|
|
url = URL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent(
|
|
|
|
|
|
|
|
"photo-\(imageCounter).jpg")
|
|
|
|
} while FileManager.default.fileExists(atPath: url.path)
|
|
|
|
} while FileManager.default.fileExists(atPath: url.path)
|
|
|
|
|
|
|
|
|
|
|
|
try data.write(to: url, options: .atomic)
|
|
|
|
try data.write(to: url, options: .atomic)
|
|
|
|
return url
|
|
|
|
return url
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func processImage(from info: [UIImagePickerController.InfoKey: Any]) -> ProcessedImage? {
|
|
|
|
fileprivate func processImage(from info: [UIImagePickerController.InfoKey: Any])
|
|
|
|
|
|
|
|
-> ProcessedImage?
|
|
|
|
|
|
|
|
{
|
|
|
|
var selectedImage: UIImage?
|
|
|
|
var selectedImage: UIImage?
|
|
|
|
var flags: PhotoFlags = []
|
|
|
|
var flags: PhotoFlags = []
|
|
|
|
// get the image
|
|
|
|
// get the image
|
|
|
@ -555,11 +600,14 @@ private extension CameraPlugin {
|
|
|
|
return result
|
|
|
|
return result
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func processedImage(from image: UIImage, with metadata: [String: Any]?) -> ProcessedImage {
|
|
|
|
fileprivate func processedImage(from image: UIImage, with metadata: [String: Any]?)
|
|
|
|
|
|
|
|
-> ProcessedImage
|
|
|
|
|
|
|
|
{
|
|
|
|
var result = ProcessedImage(image: image, metadata: metadata ?? [:])
|
|
|
|
var result = ProcessedImage(image: image, metadata: metadata ?? [:])
|
|
|
|
// resizing the image only makes sense if we have real values to which to constrain it
|
|
|
|
// 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 {
|
|
|
|
if settings.shouldResize, settings.width > 0 || settings.height > 0 {
|
|
|
|
result.image = result.image.reformat(to: CGSize(width: settings.width, height: settings.height))
|
|
|
|
result.image = result.image.reformat(
|
|
|
|
|
|
|
|
to: CGSize(width: settings.width, height: settings.height))
|
|
|
|
result.overwriteMetadataOrientation(to: 1)
|
|
|
|
result.overwriteMetadataOrientation(to: 1)
|
|
|
|
} else if settings.shouldCorrectOrientation {
|
|
|
|
} else if settings.shouldCorrectOrientation {
|
|
|
|
// resizing implicitly reformats the image so this is only needed if we aren't resizing
|
|
|
|
// resizing implicitly reformats the image so this is only needed if we aren't resizing
|
|
|
|