license headers

feat/camera
Lucas Nogueira 2 years ago
parent 6940f74acd
commit c34afb7187
No known key found for this signature in database
GPG Key ID: 7C32FCA95C8C95D7

@ -27,7 +27,7 @@ const ignore = [
async function checkFile(file) { async function checkFile(file) {
if ( if (
extensions.some((e) => file.endsWith(e)) && extensions.some((e) => file.endsWith(e)) &&
!ignore.some((i) => file.endsWith(i)) !ignore.some((i) => file.includes(i))
) { ) {
const fileStream = fs.createReadStream(file); const fileStream = fs.createReadStream(file);
const rl = readline.createInterface({ const rl = readline.createInterface({
@ -113,7 +113,8 @@ if (files.length > 0) {
run(); run();
} else { } else {
check(path.resolve(new URL(import.meta.url).pathname, "../../..")).then( check(path.resolve(new URL(
import.meta.url).pathname, "../../..")).then(
(missing) => { (missing) => {
if (missing.length > 0) { if (missing.length > 0) {
console.log(missing.join("\n")); console.log(missing.join("\n"));

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera package app.tauri.camera
import androidx.test.platform.app.InstrumentationRegistry import androidx.test.platform.app.InstrumentationRegistry

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera package app.tauri.camera
import android.annotation.SuppressLint import android.annotation.SuppressLint

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera package app.tauri.camera
import android.Manifest import android.Manifest

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera package app.tauri.camera
import android.app.Activity import android.app.Activity

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera package app.tauri.camera
import androidx.exifinterface.media.ExifInterface.* import androidx.exifinterface.media.ExifInterface.*

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera package app.tauri.camera
import android.content.Context import android.content.Context

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
package app.tauri.camera package app.tauri.camera
import org.junit.Test import org.junit.Test

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
export declare enum Source { export declare enum Source {
Prompt = "PROMPT", Prompt = "PROMPT",
Camera = "CAMERA", Camera = "CAMERA",

@ -1,4 +1,7 @@
// swift-tools-version:5.3 // swift-tools-version:5.3
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
// The swift-tools-version declares the minimum version of Swift required to build this package. // The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription import PackageDescription
@ -6,14 +9,14 @@ import PackageDescription
let package = Package( let package = Package(
name: "tauri-plugin-camera", name: "tauri-plugin-camera",
platforms: [ platforms: [
.iOS(.v11), .iOS(.v11)
], ],
products: [ products: [
// Products define the executables and libraries a package produces, and make them visible to other packages. // Products define the executables and libraries a package produces, and make them visible to other packages.
.library( .library(
name: "tauri-plugin-camera", name: "tauri-plugin-camera",
type: .static, type: .static,
targets: ["tauri-plugin-camera"]), targets: ["tauri-plugin-camera"])
], ],
dependencies: [ dependencies: [
.package(name: "Tauri", path: "../.tauri/tauri-api") .package(name: "Tauri", path: "../.tauri/tauri-api")

@ -1,5 +1,9 @@
import UIKit // Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import Photos import Photos
import UIKit
internal protocol CameraAuthorizationState { internal protocol CameraAuthorizationState {
var authorizationState: String { get } var authorizationState: String { get }
@ -40,7 +44,7 @@ extension PHAuthorizationStatus: CameraAuthorizationState {
} }
} }
internal extension PHAsset { extension PHAsset {
/** /**
Retrieves the image metadata for the asset. Retrieves the image metadata for the asset.
*/ */
@ -52,11 +56,13 @@ internal extension PHAsset {
options.version = .current options.version = .current
var result: [String: Any] = [:] var result: [String: Any] = [:]
_ = PHCachingImageManager().requestImageDataAndOrientation(for: self, options: options) { (data, _, _, _) in _ = PHCachingImageManager().requestImageDataAndOrientation(for: self, options: options) {
(data, _, _, _) in
if let data = data as NSData? { if let data = data as NSData? {
let options = [kCGImageSourceShouldCache as String: kCFBooleanFalse] as CFDictionary let options = [kCGImageSourceShouldCache as String: kCFBooleanFalse] as CFDictionary
if let imgSrc = CGImageSourceCreateWithData(data, options), if let imgSrc = CGImageSourceCreateWithData(data, options),
let metadata = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options) as? [String: Any] { let metadata = CGImageSourceCopyPropertiesAtIndex(imgSrc, 0, options) as? [String: Any]
{
result = metadata result = metadata
} }
} }
@ -65,7 +71,7 @@ internal extension PHAsset {
} }
} }
internal extension UIImage { extension UIImage {
/** /**
Generates a new image from the existing one, implicitly resetting any orientation. 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. Dimensions greater than 0 will resize the image while preserving the aspect ratio.
@ -97,7 +103,8 @@ internal extension UIImage {
let format: UIGraphicsImageRendererFormat = UIGraphicsImageRendererFormat.default() let format: UIGraphicsImageRendererFormat = UIGraphicsImageRendererFormat.default()
format.scale = 1.0 format.scale = 1.0
format.opaque = false format.opaque = false
let renderer = UIGraphicsImageRenderer(size: CGSize(width: targetWidth, height: targetHeight), format: format) let renderer = UIGraphicsImageRenderer(
size: CGSize(width: targetWidth, height: targetHeight), format: format)
return renderer.image { (_) in return renderer.image { (_) in
self.draw(in: CGRect(origin: .zero, size: CGSize(width: targetWidth, height: targetHeight))) self.draw(in: CGRect(origin: .zero, size: CGSize(width: targetWidth, height: targetHeight)))
} }

@ -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

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import UIKit import UIKit
// MARK: - Public // MARK: - Public

@ -1,3 +1,7 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import UIKit import UIKit
class ImageSaver: NSObject { class ImageSaver: NSObject {

@ -1,3 +1,8 @@
// Copyright 2019-2023 Tauri Programme within The Commons Conservancy
// SPDX-License-Identifier: Apache-2.0
// SPDX-License-Identifier: MIT
import XCTest import XCTest
@testable import ExamplePlugin @testable import ExamplePlugin

Loading…
Cancel
Save