@capgo/camera-preview 7.4.0-beta.1 → 7.4.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +62 -9
- package/android/build.gradle +2 -1
- package/android/src/main/AndroidManifest.xml +4 -2
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +90 -20
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +232 -90
- package/dist/docs.json +44 -3
- package/dist/esm/definitions.d.ts +19 -1
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.js +7 -0
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +3 -0
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +3 -0
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreview/CameraController.swift +66 -6
- package/ios/Sources/CapgoCameraPreview/Plugin.swift +64 -28
- package/package.json +1 -1
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
|
|
9
9
|
import AVFoundation
|
|
10
10
|
import UIKit
|
|
11
|
+
import CoreLocation
|
|
11
12
|
|
|
12
13
|
class CameraController: NSObject {
|
|
13
14
|
var captureSession: AVCaptureSession?
|
|
@@ -427,15 +428,74 @@ extension CameraController {
|
|
|
427
428
|
}
|
|
428
429
|
}
|
|
429
430
|
|
|
430
|
-
func captureImage(completion: @escaping (UIImage?, Error?) -> Void) {
|
|
431
|
-
guard let
|
|
431
|
+
func captureImage(width: Int?, height: Int?, quality: Float, gpsLocation: CLLocation?, completion: @escaping (UIImage?, Error?) -> Void) {
|
|
432
|
+
guard let photoOutput = self.photoOutput else {
|
|
433
|
+
completion(nil, NSError(domain: "Camera", code: 0, userInfo: [NSLocalizedDescriptionKey: "Photo output is not available"]))
|
|
434
|
+
return
|
|
435
|
+
}
|
|
436
|
+
|
|
432
437
|
let settings = AVCapturePhotoSettings()
|
|
438
|
+
if photoOutput.isHighResolutionCaptureEnabled {
|
|
439
|
+
settings.isHighResolutionCaptureEnabled = true
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
self.photoCaptureCompletionBlock = { (image, error) in
|
|
443
|
+
if let error = error {
|
|
444
|
+
completion(nil, error)
|
|
445
|
+
return
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
guard let image = image else {
|
|
449
|
+
completion(nil, NSError(domain: "Camera", code: 0, userInfo: [NSLocalizedDescriptionKey: "Failed to capture image"]))
|
|
450
|
+
return
|
|
451
|
+
}
|
|
433
452
|
|
|
434
|
-
|
|
435
|
-
|
|
453
|
+
if let location = gpsLocation {
|
|
454
|
+
self.addGPSMetadata(to: image, location: location)
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
if let width = width, let height = height {
|
|
458
|
+
let resizedImage = self.resizeImage(image: image, to: CGSize(width: width, height: height))
|
|
459
|
+
completion(resizedImage, nil)
|
|
460
|
+
} else {
|
|
461
|
+
completion(image, nil)
|
|
462
|
+
}
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
photoOutput.capturePhoto(with: settings, delegate: self)
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
func addGPSMetadata(to image: UIImage, location: CLLocation) {
|
|
469
|
+
guard let jpegData = image.jpegData(compressionQuality: 1.0),
|
|
470
|
+
let source = CGImageSourceCreateWithData(jpegData as CFData, nil),
|
|
471
|
+
let uti = CGImageSourceGetType(source) else { return }
|
|
472
|
+
|
|
473
|
+
let metadata = CGImageSourceCopyPropertiesAtIndex(source, 0, nil) as? [String: Any] ?? [:]
|
|
474
|
+
|
|
475
|
+
let gpsDict: [String: Any] = [
|
|
476
|
+
kCGImagePropertyGPSLatitude as String: abs(location.coordinate.latitude),
|
|
477
|
+
kCGImagePropertyGPSLatitudeRef as String: location.coordinate.latitude >= 0 ? "N" : "S",
|
|
478
|
+
kCGImagePropertyGPSLongitude as String: abs(location.coordinate.longitude),
|
|
479
|
+
kCGImagePropertyGPSLongitudeRef as String: location.coordinate.longitude >= 0 ? "E" : "W",
|
|
480
|
+
kCGImagePropertyGPSTimeStamp as String: location.timestamp.ISO8601Format(),
|
|
481
|
+
kCGImagePropertyGPSAltitude as String: location.altitude,
|
|
482
|
+
kCGImagePropertyGPSAltitudeRef as String: location.altitude >= 0 ? 0 : 1
|
|
483
|
+
]
|
|
484
|
+
|
|
485
|
+
metadata[kCGImagePropertyGPSDictionary as String] = gpsDict
|
|
486
|
+
|
|
487
|
+
let destData = NSMutableData()
|
|
488
|
+
guard let destination = CGImageDestinationCreateWithData(destData, uti, 1, nil) else { return }
|
|
489
|
+
CGImageDestinationAddImageFromSource(destination, source, 0, metadata as CFDictionary)
|
|
490
|
+
CGImageDestinationFinalize(destination)
|
|
491
|
+
}
|
|
436
492
|
|
|
437
|
-
|
|
438
|
-
|
|
493
|
+
func resizeImage(image: UIImage, to size: CGSize) -> UIImage? {
|
|
494
|
+
let renderer = UIGraphicsImageRenderer(size: size)
|
|
495
|
+
let resizedImage = renderer.image { (context) in
|
|
496
|
+
image.draw(in: CGRect(origin: .zero, size: size))
|
|
497
|
+
}
|
|
498
|
+
return resizedImage
|
|
439
499
|
}
|
|
440
500
|
|
|
441
501
|
func captureSample(completion: @escaping (UIImage?, Error?) -> Void) {
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import Capacitor
|
|
3
3
|
import AVFoundation
|
|
4
|
+
import Photos
|
|
5
|
+
import CoreImage
|
|
6
|
+
import CoreLocation
|
|
4
7
|
|
|
5
8
|
extension UIWindow {
|
|
6
9
|
static var isLandscape: Bool {
|
|
@@ -74,7 +77,9 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
74
77
|
var enableZoom: Bool?
|
|
75
78
|
var highResolutionOutput: Bool = false
|
|
76
79
|
var disableAudio: Bool = false
|
|
77
|
-
|
|
80
|
+
var locationManager: CLLocationManager?
|
|
81
|
+
var currentLocation: CLLocation?
|
|
82
|
+
|
|
78
83
|
// MARK: - Transparency Methods
|
|
79
84
|
|
|
80
85
|
private func makeWebViewTransparent() {
|
|
@@ -286,7 +291,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
286
291
|
self.toBack = call.getBool("toBack") ?? true
|
|
287
292
|
self.storeToFile = call.getBool("storeToFile") ?? false
|
|
288
293
|
self.enableZoom = call.getBool("enableZoom") ?? false
|
|
289
|
-
self.disableAudio = call.getBool("disableAudio") ??
|
|
294
|
+
self.disableAudio = call.getBool("disableAudio") ?? true
|
|
290
295
|
|
|
291
296
|
AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) in
|
|
292
297
|
guard granted else {
|
|
@@ -436,43 +441,66 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
436
441
|
@objc func capture(_ call: CAPPluginCall) {
|
|
437
442
|
DispatchQueue.main.async {
|
|
438
443
|
|
|
439
|
-
let quality
|
|
440
|
-
|
|
441
|
-
|
|
444
|
+
let quality = call.getFloat("quality", 85)
|
|
445
|
+
let saveToGallery = call.getBool("saveToGallery", false)
|
|
446
|
+
let withExifLocation = call.getBool("withExifLocation", false)
|
|
447
|
+
let width = call.getInt("width")
|
|
448
|
+
let height = call.getInt("height")
|
|
449
|
+
|
|
450
|
+
if withExifLocation {
|
|
451
|
+
self.locationManager = CLLocationManager()
|
|
452
|
+
self.locationManager?.delegate = self
|
|
453
|
+
self.locationManager?.requestWhenInUseAuthorization()
|
|
454
|
+
self.locationManager?.startUpdatingLocation()
|
|
455
|
+
}
|
|
442
456
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
guard let error = error else {
|
|
446
|
-
call.reject("Image capture error")
|
|
447
|
-
return
|
|
448
|
-
}
|
|
457
|
+
self.cameraController.captureImage(width: width, height: height, quality: quality, gpsLocation: self.currentLocation) { (image, error) in
|
|
458
|
+
if let error = error {
|
|
449
459
|
call.reject(error.localizedDescription)
|
|
450
460
|
return
|
|
451
461
|
}
|
|
452
|
-
|
|
453
|
-
if
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
462
|
+
|
|
463
|
+
if saveToGallery {
|
|
464
|
+
PHPhotoLibrary.shared().performChanges({
|
|
465
|
+
PHAssetChangeRequest.creationRequestForAsset(from: image!)
|
|
466
|
+
}, completionHandler: { (success, error) in
|
|
467
|
+
if !success {
|
|
468
|
+
Logger.error("CameraPreview", "Error saving image to gallery", error)
|
|
469
|
+
}
|
|
470
|
+
})
|
|
458
471
|
}
|
|
459
472
|
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
} else {
|
|
464
|
-
do {
|
|
465
|
-
let fileUrl=self.getTempFilePath()
|
|
466
|
-
try imageData?.write(to: fileUrl)
|
|
467
|
-
call.resolve(["value": fileUrl.absoluteString])
|
|
468
|
-
} catch {
|
|
469
|
-
call.reject("error writing image to file")
|
|
470
|
-
}
|
|
473
|
+
guard let imageData = image?.jpegData(compressionQuality: CGFloat(quality / 100.0)) else {
|
|
474
|
+
call.reject("Failed to get JPEG data from image")
|
|
475
|
+
return
|
|
471
476
|
}
|
|
477
|
+
|
|
478
|
+
let exifData = self.getExifData(from: imageData)
|
|
479
|
+
let base64Image = imageData.base64EncodedString()
|
|
480
|
+
|
|
481
|
+
var result = JSObject()
|
|
482
|
+
result["value"] = base64Image
|
|
483
|
+
result["exif"] = exifData
|
|
484
|
+
call.resolve(result)
|
|
472
485
|
}
|
|
473
486
|
}
|
|
474
487
|
}
|
|
475
488
|
|
|
489
|
+
private func getExifData(from imageData: Data) -> JSObject {
|
|
490
|
+
guard let imageSource = CGImageSourceCreateWithData(imageData as CFData, nil),
|
|
491
|
+
let imageProperties = CGImageSourceCopyPropertiesAtIndex(imageSource, 0, nil) as? [String: Any],
|
|
492
|
+
let exifDict = imageProperties[kCGImagePropertyExifDictionary as String] as? [String: Any] else {
|
|
493
|
+
return [:]
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
var exifData = JSObject()
|
|
497
|
+
for (key, value) in exifDict {
|
|
498
|
+
exifData[key] = value
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
return exifData
|
|
502
|
+
}
|
|
503
|
+
|
|
476
504
|
@objc func captureSample(_ call: CAPPluginCall) {
|
|
477
505
|
DispatchQueue.main.async {
|
|
478
506
|
let quality: Int? = call.getInt("quality", 85)
|
|
@@ -797,6 +825,14 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin {
|
|
|
797
825
|
}
|
|
798
826
|
}
|
|
799
827
|
|
|
828
|
+
func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
|
|
829
|
+
self.currentLocation = locations.last
|
|
830
|
+
self.locationManager?.stopUpdatingLocation()
|
|
831
|
+
}
|
|
832
|
+
|
|
833
|
+
func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
|
|
834
|
+
Logger.error("CameraPreview", "Failed to get location", error)
|
|
835
|
+
}
|
|
800
836
|
|
|
801
837
|
|
|
802
838
|
}
|