@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.
@@ -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 captureSession = captureSession, captureSession.isRunning else { completion(nil, CameraControllerError.captureSessionIsMissing); return }
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
- settings.flashMode = self.flashMode
435
- settings.isHighResolutionPhotoEnabled = self.highResolutionOutput
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
- self.photoOutput?.capturePhoto(with: settings, delegate: self)
438
- self.photoCaptureCompletionBlock = completion
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") ?? false
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: Int? = call.getInt("quality", 85)
440
-
441
- self.cameraController.captureImage { (image, error) in
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
- guard let image = image else {
444
- print(error ?? "Image capture error")
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
- let imageData: Data?
453
- if self.cameraController.currentCameraPosition == .front {
454
- let flippedImage = image.withHorizontallyFlippedOrientation()
455
- imageData = flippedImage.jpegData(compressionQuality: CGFloat(quality!/100))
456
- } else {
457
- imageData = image.jpegData(compressionQuality: CGFloat(quality!/100))
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
- if self.storeToFile == false {
461
- let imageBase64 = imageData?.base64EncodedString()
462
- call.resolve(["value": imageBase64!])
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
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@capgo/camera-preview",
3
- "version": "7.4.0-beta.1",
3
+ "version": "7.4.0-beta.3",
4
4
  "description": "Camera preview",
5
5
  "license": "MIT",
6
6
  "repository": {