@capgo/camera-preview 7.4.1 → 7.5.0
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 +8 -9
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraPreview.java +2 -10
- package/android/src/main/java/com/ahm/capacitor/camera/preview/CameraXView.java +49 -95
- package/dist/docs.json +4 -30
- package/dist/esm/definitions.d.ts +6 -14
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.js +28 -35
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +28 -35
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +28 -35
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreviewPlugin/CameraController.swift +139 -57
- package/ios/Sources/CapgoCameraPreviewPlugin/Plugin.swift +40 -81
- package/package.json +1 -1
|
@@ -70,6 +70,37 @@ class CameraController: NSObject {
|
|
|
70
70
|
|
|
71
71
|
// Track whether an aspect ratio was explicitly requested
|
|
72
72
|
var requestedAspectRatio: String?
|
|
73
|
+
|
|
74
|
+
private func calculateAspectRatioFrame(for aspectRatio: String, in bounds: CGRect) -> CGRect {
|
|
75
|
+
guard let ratio = parseAspectRatio(aspectRatio) else {
|
|
76
|
+
return bounds
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
let targetAspectRatio = ratio.width / ratio.height
|
|
80
|
+
let viewAspectRatio = bounds.width / bounds.height
|
|
81
|
+
|
|
82
|
+
var frame: CGRect
|
|
83
|
+
|
|
84
|
+
if viewAspectRatio > targetAspectRatio {
|
|
85
|
+
// View is wider than target - fit by height
|
|
86
|
+
let targetWidth = bounds.height * targetAspectRatio
|
|
87
|
+
let xOffset = (bounds.width - targetWidth) / 2
|
|
88
|
+
frame = CGRect(x: xOffset, y: 0, width: targetWidth, height: bounds.height)
|
|
89
|
+
} else {
|
|
90
|
+
// View is taller than target - fit by width
|
|
91
|
+
let targetHeight = bounds.width / targetAspectRatio
|
|
92
|
+
let yOffset = (bounds.height - targetHeight) / 2
|
|
93
|
+
frame = CGRect(x: 0, y: yOffset, width: bounds.width, height: targetHeight)
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return frame
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
private func parseAspectRatio(_ aspectRatio: String) -> (width: CGFloat, height: CGFloat)? {
|
|
100
|
+
let components = aspectRatio.split(separator: ":").compactMap { Float(String($0)) }
|
|
101
|
+
guard components.count == 2 else { return nil }
|
|
102
|
+
return (width: CGFloat(components[0]), height: CGFloat(components[1]))
|
|
103
|
+
}
|
|
73
104
|
}
|
|
74
105
|
|
|
75
106
|
extension CameraController {
|
|
@@ -416,9 +447,17 @@ extension CameraController {
|
|
|
416
447
|
}
|
|
417
448
|
|
|
418
449
|
// Fast configuration without CATransaction overhead
|
|
419
|
-
//
|
|
420
|
-
|
|
421
|
-
|
|
450
|
+
// Configure video gravity and frame based on aspect ratio
|
|
451
|
+
if let aspectRatio = requestedAspectRatio {
|
|
452
|
+
// Calculate the frame based on requested aspect ratio
|
|
453
|
+
let frame = calculateAspectRatioFrame(for: aspectRatio, in: view.bounds)
|
|
454
|
+
previewLayer.frame = frame
|
|
455
|
+
previewLayer.videoGravity = .resizeAspectFill
|
|
456
|
+
} else {
|
|
457
|
+
// No specific aspect ratio requested - fill the entire view
|
|
458
|
+
previewLayer.frame = view.bounds
|
|
459
|
+
previewLayer.videoGravity = .resizeAspect
|
|
460
|
+
}
|
|
422
461
|
|
|
423
462
|
// Insert layer immediately (only if new)
|
|
424
463
|
if previewLayer.superlayer != view.layer {
|
|
@@ -433,7 +472,16 @@ extension CameraController {
|
|
|
433
472
|
// Disable animation for grid overlay creation and positioning
|
|
434
473
|
CATransaction.begin()
|
|
435
474
|
CATransaction.setDisableActions(true)
|
|
436
|
-
|
|
475
|
+
|
|
476
|
+
// Use preview layer frame if aspect ratio is specified, otherwise use full view bounds
|
|
477
|
+
let gridFrame: CGRect
|
|
478
|
+
if requestedAspectRatio != nil, let previewLayer = previewLayer {
|
|
479
|
+
gridFrame = previewLayer.frame
|
|
480
|
+
} else {
|
|
481
|
+
gridFrame = view.bounds
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
gridOverlayView = GridOverlayView(frame: gridFrame)
|
|
437
485
|
gridOverlayView?.gridMode = gridMode
|
|
438
486
|
view.addSubview(gridOverlayView!)
|
|
439
487
|
CATransaction.commit()
|
|
@@ -628,8 +676,8 @@ extension CameraController {
|
|
|
628
676
|
}
|
|
629
677
|
}
|
|
630
678
|
|
|
631
|
-
func captureImage(width: Int?, height: Int?,
|
|
632
|
-
print("[CameraPreview] captureImage called - width: \(width ?? -1), height: \(height ?? -1)
|
|
679
|
+
func captureImage(width: Int?, height: Int?, quality: Float, gpsLocation: CLLocation?, completion: @escaping (UIImage?, Data?, [AnyHashable: Any]?, Error?) -> Void) {
|
|
680
|
+
print("[CameraPreview] captureImage called - width: \(width ?? -1), height: \(height ?? -1)")
|
|
633
681
|
|
|
634
682
|
guard let photoOutput = self.photoOutput else {
|
|
635
683
|
completion(nil, nil, nil, NSError(domain: "Camera", code: 0, userInfo: [NSLocalizedDescriptionKey: "Photo output is not available"]))
|
|
@@ -637,9 +685,12 @@ extension CameraController {
|
|
|
637
685
|
}
|
|
638
686
|
|
|
639
687
|
let settings = AVCapturePhotoSettings()
|
|
640
|
-
//
|
|
688
|
+
// Configure photo capture settings
|
|
641
689
|
if #available(iOS 13.0, *) {
|
|
642
|
-
|
|
690
|
+
// Enable high resolution capture if max dimensions are specified or no aspect ratio constraint
|
|
691
|
+
// When aspect ratio is specified WITHOUT max dimensions, use session preset dimensions
|
|
692
|
+
let shouldUseHighRes = (width != nil || height != nil) || (self.requestedAspectRatio == nil)
|
|
693
|
+
settings.isHighResolutionPhotoEnabled = shouldUseHighRes
|
|
643
694
|
}
|
|
644
695
|
if #available(iOS 15.0, *) {
|
|
645
696
|
settings.photoQualityPrioritization = .balanced
|
|
@@ -683,46 +734,29 @@ extension CameraController {
|
|
|
683
734
|
var finalImage = image
|
|
684
735
|
|
|
685
736
|
// Determine what to do based on parameters
|
|
686
|
-
if
|
|
687
|
-
//
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
|
|
691
|
-
|
|
692
|
-
let components = aspectRatio.split(separator: ":").compactMap { Double($0) }
|
|
693
|
-
if components.count == 2 {
|
|
694
|
-
// For capture in portrait orientation, swap the aspect ratio (16:9 becomes 9:16)
|
|
695
|
-
let isPortrait = image.size.height > image.size.width
|
|
696
|
-
let targetAspectRatio = isPortrait ? components[1] / components[0] : components[0] / components[1]
|
|
697
|
-
let imageSize = image.size
|
|
698
|
-
let originalAspectRatio = imageSize.width / imageSize.height
|
|
699
|
-
|
|
700
|
-
// Only crop if the aspect ratios don't match
|
|
701
|
-
if abs(originalAspectRatio - targetAspectRatio) > 0.01 {
|
|
702
|
-
var targetSize = imageSize
|
|
703
|
-
|
|
704
|
-
if originalAspectRatio > targetAspectRatio {
|
|
705
|
-
// Original is wider than target - fit by height
|
|
706
|
-
targetSize.width = imageSize.height * CGFloat(targetAspectRatio)
|
|
707
|
-
} else {
|
|
708
|
-
// Original is taller than target - fit by width
|
|
709
|
-
targetSize.height = imageSize.width / CGFloat(targetAspectRatio)
|
|
710
|
-
}
|
|
711
|
-
|
|
712
|
-
// Center crop the image
|
|
713
|
-
if let croppedImage = self.cropImageToAspectRatio(image: image, targetSize: targetSize) {
|
|
714
|
-
finalImage = croppedImage
|
|
715
|
-
print("[CameraPreview] Applied aspect ratio crop: \(finalImage.size.width)x\(finalImage.size.height)")
|
|
716
|
-
}
|
|
717
|
-
}
|
|
737
|
+
if width != nil || height != nil {
|
|
738
|
+
// When max dimensions are specified, we used high-res capture
|
|
739
|
+
// First crop to aspect ratio if needed, then resize to max dimensions
|
|
740
|
+
if let aspectRatio = self.requestedAspectRatio {
|
|
741
|
+
finalImage = self.cropImageToAspectRatio(image: image, aspectRatio: aspectRatio) ?? image
|
|
742
|
+
print("[CameraPreview] Cropped high-res image to aspect ratio \(aspectRatio)")
|
|
718
743
|
}
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
744
|
+
// Then resize to fit within maximum dimensions while maintaining aspect ratio
|
|
745
|
+
finalImage = self.resizeImageToMaxDimensions(image: finalImage, maxWidth: width, maxHeight: height)!
|
|
746
|
+
print("[CameraPreview] Resized to max dimensions: \(finalImage.size.width)x\(finalImage.size.height)")
|
|
747
|
+
} else if let aspectRatio = self.requestedAspectRatio {
|
|
748
|
+
// No max dimensions specified, but aspect ratio is specified
|
|
749
|
+
// If we used session preset (low-res), image should already be correct aspect ratio
|
|
750
|
+
// If we used high-res (shouldn't happen without max dimensions), crop it
|
|
751
|
+
let imageAspectRatio = image.size.width / image.size.height
|
|
752
|
+
if let targetRatio = self.parseAspectRatio(aspectRatio) {
|
|
753
|
+
let targetAspectRatio = targetRatio.width / targetRatio.height
|
|
754
|
+
|
|
755
|
+
// Allow small tolerance for aspect ratio comparison
|
|
756
|
+
if abs(imageAspectRatio - targetAspectRatio) > 0.01 {
|
|
757
|
+
finalImage = self.cropImageToAspectRatio(image: image, aspectRatio: aspectRatio) ?? image
|
|
758
|
+
print("[CameraPreview] Cropped to match aspect ratio \(aspectRatio): \(finalImage.size.width)x\(finalImage.size.height)")
|
|
759
|
+
}
|
|
726
760
|
}
|
|
727
761
|
}
|
|
728
762
|
|
|
@@ -762,27 +796,75 @@ extension CameraController {
|
|
|
762
796
|
}
|
|
763
797
|
|
|
764
798
|
func resizeImage(image: UIImage, to size: CGSize) -> UIImage? {
|
|
765
|
-
|
|
799
|
+
// Create a renderer with scale 1.0 to ensure we get exact pixel dimensions
|
|
800
|
+
let format = UIGraphicsImageRendererFormat()
|
|
801
|
+
format.scale = 1.0
|
|
802
|
+
let renderer = UIGraphicsImageRenderer(size: size, format: format)
|
|
766
803
|
let resizedImage = renderer.image { (_) in
|
|
767
804
|
image.draw(in: CGRect(origin: .zero, size: size))
|
|
768
805
|
}
|
|
769
806
|
return resizedImage
|
|
770
807
|
}
|
|
771
808
|
|
|
772
|
-
func
|
|
773
|
-
let
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
let
|
|
809
|
+
func resizeImageToMaxDimensions(image: UIImage, maxWidth: Int?, maxHeight: Int?) -> UIImage? {
|
|
810
|
+
let originalSize = image.size
|
|
811
|
+
let originalAspectRatio = originalSize.width / originalSize.height
|
|
812
|
+
|
|
813
|
+
var targetSize = originalSize
|
|
814
|
+
|
|
815
|
+
if let maxWidth = maxWidth, let maxHeight = maxHeight {
|
|
816
|
+
// Both dimensions specified - fit within both maximums
|
|
817
|
+
let maxAspectRatio = CGFloat(maxWidth) / CGFloat(maxHeight)
|
|
818
|
+
if originalAspectRatio > maxAspectRatio {
|
|
819
|
+
// Original is wider - fit by width
|
|
820
|
+
targetSize.width = CGFloat(maxWidth)
|
|
821
|
+
targetSize.height = CGFloat(maxWidth) / originalAspectRatio
|
|
822
|
+
} else {
|
|
823
|
+
// Original is taller - fit by height
|
|
824
|
+
targetSize.width = CGFloat(maxHeight) * originalAspectRatio
|
|
825
|
+
targetSize.height = CGFloat(maxHeight)
|
|
826
|
+
}
|
|
827
|
+
} else if let maxWidth = maxWidth {
|
|
828
|
+
// Only width specified - maintain aspect ratio
|
|
829
|
+
targetSize.width = CGFloat(maxWidth)
|
|
830
|
+
targetSize.height = CGFloat(maxWidth) / originalAspectRatio
|
|
831
|
+
} else if let maxHeight = maxHeight {
|
|
832
|
+
// Only height specified - maintain aspect ratio
|
|
833
|
+
targetSize.width = CGFloat(maxHeight) * originalAspectRatio
|
|
834
|
+
targetSize.height = CGFloat(maxHeight)
|
|
835
|
+
}
|
|
836
|
+
|
|
837
|
+
return resizeImage(image: image, to: targetSize)
|
|
838
|
+
}
|
|
779
839
|
|
|
780
|
-
|
|
840
|
+
func cropImageToAspectRatio(image: UIImage, aspectRatio: String) -> UIImage? {
|
|
841
|
+
guard let ratio = parseAspectRatio(aspectRatio) else {
|
|
842
|
+
return image
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
let imageSize = image.size
|
|
846
|
+
let imageAspectRatio = imageSize.width / imageSize.height
|
|
847
|
+
let targetAspectRatio = ratio.width / ratio.height
|
|
848
|
+
|
|
849
|
+
var cropRect: CGRect
|
|
850
|
+
|
|
851
|
+
if imageAspectRatio > targetAspectRatio {
|
|
852
|
+
// Image is wider than target - crop horizontally (center crop)
|
|
853
|
+
let targetWidth = imageSize.height * targetAspectRatio
|
|
854
|
+
let xOffset = (imageSize.width - targetWidth) / 2
|
|
855
|
+
cropRect = CGRect(x: xOffset, y: 0, width: targetWidth, height: imageSize.height)
|
|
856
|
+
} else {
|
|
857
|
+
// Image is taller than target - crop vertically (center crop)
|
|
858
|
+
let targetHeight = imageSize.width / targetAspectRatio
|
|
859
|
+
let yOffset = (imageSize.height - targetHeight) / 2
|
|
860
|
+
cropRect = CGRect(x: 0, y: yOffset, width: imageSize.width, height: targetHeight)
|
|
861
|
+
}
|
|
862
|
+
|
|
781
863
|
guard let cgImage = image.cgImage,
|
|
782
864
|
let croppedCGImage = cgImage.cropping(to: cropRect) else {
|
|
783
865
|
return nil
|
|
784
866
|
}
|
|
785
|
-
|
|
867
|
+
|
|
786
868
|
return UIImage(cgImage: croppedCGImage, scale: image.scale, orientation: image.imageOrientation)
|
|
787
869
|
}
|
|
788
870
|
|
|
@@ -100,13 +100,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
100
100
|
|
|
101
101
|
// MARK: - Helper Methods for Aspect Ratio
|
|
102
102
|
|
|
103
|
-
|
|
104
|
-
private func validateAspectRatioParameters(aspectRatio: String?, width: Int?, height: Int?) -> String? {
|
|
105
|
-
if aspectRatio != nil && (width != nil || height != nil) {
|
|
106
|
-
return "Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start."
|
|
107
|
-
}
|
|
108
|
-
return nil
|
|
109
|
-
}
|
|
103
|
+
|
|
110
104
|
|
|
111
105
|
/// Parses aspect ratio string and returns the appropriate ratio for the current orientation
|
|
112
106
|
private func parseAspectRatio(_ ratio: String, isPortrait: Bool) -> CGFloat {
|
|
@@ -579,12 +573,18 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
579
573
|
|
|
580
574
|
let initialZoomLevel = call.getFloat("initialZoomLevel")
|
|
581
575
|
|
|
582
|
-
//
|
|
583
|
-
|
|
584
|
-
|
|
576
|
+
// Check for conflict between aspectRatio and size (width/height)
|
|
577
|
+
let hasAspectRatio = call.getString("aspectRatio") != nil
|
|
578
|
+
let hasWidth = call.getInt("width") != nil
|
|
579
|
+
let hasHeight = call.getInt("height") != nil
|
|
580
|
+
|
|
581
|
+
if hasAspectRatio && (hasWidth || hasHeight) {
|
|
582
|
+
call.reject("Cannot set both aspectRatio and size (width/height). Use setPreviewSize after start.")
|
|
585
583
|
return
|
|
586
584
|
}
|
|
587
585
|
|
|
586
|
+
|
|
587
|
+
|
|
588
588
|
AVCaptureDevice.requestAccess(for: .video, completionHandler: { (granted: Bool) in
|
|
589
589
|
|
|
590
590
|
guard granted else {
|
|
@@ -833,27 +833,10 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
833
833
|
let withExifLocation = call.getBool("withExifLocation", false)
|
|
834
834
|
let width = call.getInt("width")
|
|
835
835
|
let height = call.getInt("height")
|
|
836
|
-
let aspectRatio = call.getString("aspectRatio")
|
|
837
|
-
|
|
838
|
-
print("[CameraPreview] Raw parameter values - width: \(String(describing: width)), height: \(String(describing: height)), aspectRatio: \(String(describing: aspectRatio))")
|
|
839
836
|
|
|
840
|
-
|
|
841
|
-
if let validationError = validateAspectRatioParameters(aspectRatio: aspectRatio, width: width, height: height) {
|
|
842
|
-
print("[CameraPreview] Error: \(validationError)")
|
|
843
|
-
call.reject(validationError)
|
|
844
|
-
return
|
|
845
|
-
}
|
|
846
|
-
|
|
847
|
-
// When no dimensions are specified, we should capture exactly what's visible in the preview
|
|
848
|
-
// Don't pass aspectRatio in this case - let the capture method handle preview matching
|
|
849
|
-
print("[CameraPreview] Capture decision - width: \(width == nil), height: \(height == nil), aspectRatio param: \(aspectRatio == nil)")
|
|
850
|
-
print("[CameraPreview] Stored aspectRatio: \(self.aspectRatio ?? "nil")")
|
|
837
|
+
print("[CameraPreview] Raw parameter values - width: \(String(describing: width)), height: \(String(describing: height))")
|
|
851
838
|
|
|
852
|
-
|
|
853
|
-
// Never use the stored aspectRatio when capturing without dimensions
|
|
854
|
-
let captureAspectRatio: String? = aspectRatio
|
|
855
|
-
|
|
856
|
-
print("[CameraPreview] Capture params - quality: \(quality), saveToGallery: \(saveToGallery), withExifLocation: \(withExifLocation), width: \(width ?? -1), height: \(height ?? -1), aspectRatio: \(aspectRatio ?? "nil"), using aspectRatio: \(captureAspectRatio ?? "nil")")
|
|
839
|
+
print("[CameraPreview] Capture params - quality: \(quality), saveToGallery: \(saveToGallery), withExifLocation: \(withExifLocation), width: \(width ?? -1), height: \(height ?? -1)")
|
|
857
840
|
print("[CameraPreview] Current location: \(self.currentLocation?.description ?? "nil")")
|
|
858
841
|
// Safely read frame from main thread for logging
|
|
859
842
|
let (previewWidth, previewHeight): (CGFloat, CGFloat) = {
|
|
@@ -870,7 +853,7 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
870
853
|
}()
|
|
871
854
|
print("[CameraPreview] Preview dimensions: \(previewWidth)x\(previewHeight)")
|
|
872
855
|
|
|
873
|
-
self.cameraController.captureImage(width: width, height: height,
|
|
856
|
+
self.cameraController.captureImage(width: width, height: height, quality: quality, gpsLocation: self.currentLocation) { (image, originalPhotoData, _, error) in
|
|
874
857
|
print("[CameraPreview] captureImage callback received")
|
|
875
858
|
DispatchQueue.main.async {
|
|
876
859
|
print("[CameraPreview] Processing capture on main thread")
|
|
@@ -895,62 +878,38 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
895
878
|
|
|
896
879
|
print("[CameraPreview] Image data created, size: \(imageDataWithExif.count) bytes")
|
|
897
880
|
|
|
898
|
-
|
|
899
|
-
|
|
900
|
-
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
if !success, let error = error {
|
|
908
|
-
result["galleryError"] = error.localizedDescription
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
if self.storeToFile == false {
|
|
912
|
-
let base64Image = imageDataWithExif.base64EncodedString()
|
|
913
|
-
result["value"] = base64Image
|
|
914
|
-
} else {
|
|
915
|
-
do {
|
|
916
|
-
let fileUrl = self.getTempFilePath()
|
|
917
|
-
try imageDataWithExif.write(to: fileUrl)
|
|
918
|
-
result["value"] = fileUrl.absoluteString
|
|
919
|
-
} catch {
|
|
920
|
-
call.reject("Error writing image to file")
|
|
921
|
-
}
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
print("[CameraPreview] Resolving capture call with gallery save")
|
|
925
|
-
call.resolve(result)
|
|
926
|
-
}
|
|
881
|
+
// Prepare the result first
|
|
882
|
+
let exifData = self.getExifData(from: imageDataWithExif)
|
|
883
|
+
|
|
884
|
+
var result = JSObject()
|
|
885
|
+
result["exif"] = exifData
|
|
886
|
+
|
|
887
|
+
if self.storeToFile == false {
|
|
888
|
+
let base64Image = imageDataWithExif.base64EncodedString()
|
|
889
|
+
result["value"] = base64Image
|
|
927
890
|
} else {
|
|
928
|
-
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
891
|
+
do {
|
|
892
|
+
let fileUrl = self.getTempFilePath()
|
|
893
|
+
try imageDataWithExif.write(to: fileUrl)
|
|
894
|
+
result["value"] = fileUrl.absoluteString
|
|
895
|
+
} catch {
|
|
896
|
+
call.reject("Error writing image to file")
|
|
897
|
+
return
|
|
898
|
+
}
|
|
899
|
+
}
|
|
936
900
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
var result = JSObject()
|
|
944
|
-
result["value"] = fileUrl.absoluteString
|
|
945
|
-
result["exif"] = exifData
|
|
946
|
-
print("[CameraPreview] filePath - Resolving capture call")
|
|
947
|
-
call.resolve(result)
|
|
948
|
-
} catch {
|
|
949
|
-
call.reject("Error writing image to file")
|
|
901
|
+
// Save to gallery asynchronously if requested
|
|
902
|
+
if saveToGallery {
|
|
903
|
+
print("[CameraPreview] Saving to gallery asynchronously...")
|
|
904
|
+
DispatchQueue.global(qos: .utility).async {
|
|
905
|
+
self.saveImageDataToGallery(imageData: imageDataWithExif) { success, error in
|
|
906
|
+
print("[CameraPreview] Save to gallery completed, success: \(success), error: \(error?.localizedDescription ?? "none")")
|
|
950
907
|
}
|
|
951
908
|
}
|
|
952
|
-
|
|
953
909
|
}
|
|
910
|
+
|
|
911
|
+
print("[CameraPreview] Resolving capture call immediately")
|
|
912
|
+
call.resolve(result)
|
|
954
913
|
}
|
|
955
914
|
}
|
|
956
915
|
}
|