@capgo/camera-preview 8.8.0 → 8.9.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 +58 -0
- package/android/src/main/java/app/capgo/capacitor/camera/preview/CameraPreview.java +43 -0
- package/android/src/main/java/app/capgo/capacitor/camera/preview/CameraXView.java +130 -8
- package/dist/docs.json +80 -0
- package/dist/esm/definitions.d.ts +32 -0
- package/dist/esm/definitions.js.map +1 -1
- package/dist/esm/web.d.ts +10 -1
- package/dist/esm/web.js +50 -2
- package/dist/esm/web.js.map +1 -1
- package/dist/plugin.cjs.js +49 -2
- package/dist/plugin.cjs.js.map +1 -1
- package/dist/plugin.js +49 -2
- package/dist/plugin.js.map +1 -1
- package/ios/Sources/CapgoCameraPreviewPlugin/CameraController.swift +211 -80
- package/ios/Sources/CapgoCameraPreviewPlugin/Plugin.swift +56 -1
- package/package.json +1 -1
|
@@ -105,6 +105,10 @@ class CameraController: NSObject {
|
|
|
105
105
|
|
|
106
106
|
var captureSession: AVCaptureSession?
|
|
107
107
|
var disableFocusIndicator: Bool = false
|
|
108
|
+
private var focusExposureRestoreGeneration: UInt = 0
|
|
109
|
+
private var focusExposureRestoreTimeoutWorkItem: DispatchWorkItem?
|
|
110
|
+
private let focusExposureRestoreTimeout: TimeInterval = 3.0
|
|
111
|
+
private let focusExposureRestorePollInterval: TimeInterval = 0.05
|
|
108
112
|
|
|
109
113
|
var currentCameraPosition: CameraPosition?
|
|
110
114
|
|
|
@@ -619,7 +623,10 @@ extension CameraController {
|
|
|
619
623
|
self.photoOutput?.isHighResolutionCaptureEnabled = true
|
|
620
624
|
|
|
621
625
|
// Create video output
|
|
622
|
-
|
|
626
|
+
let movieFileOutput = AVCaptureMovieFileOutput()
|
|
627
|
+
// MP4 does not support movie fragments; the default 10s interval drops the final partial segment on stop.
|
|
628
|
+
movieFileOutput.movieFragmentInterval = .invalid
|
|
629
|
+
self.fileVideoOutput = movieFileOutput
|
|
623
630
|
|
|
624
631
|
// Create data output for preview
|
|
625
632
|
self.dataOutput = AVCaptureVideoDataOutput()
|
|
@@ -1000,6 +1007,10 @@ extension CameraController {
|
|
|
1000
1007
|
finalDevice.exposurePointOfInterest = CGPoint(x: 0.5, y: 0.5)
|
|
1001
1008
|
}
|
|
1002
1009
|
}
|
|
1010
|
+
// Default white balance to continuous auto (prevents a warm/yellow cast)
|
|
1011
|
+
if finalDevice.isWhiteBalanceModeSupported(.continuousAutoWhiteBalance) {
|
|
1012
|
+
finalDevice.whiteBalanceMode = .continuousAutoWhiteBalance
|
|
1013
|
+
}
|
|
1003
1014
|
// Reset exposure compensation so sessions start neutral
|
|
1004
1015
|
let minBias = finalDevice.minExposureTargetBias
|
|
1005
1016
|
let maxBias = finalDevice.maxExposureTargetBias
|
|
@@ -1195,6 +1206,7 @@ extension CameraController {
|
|
|
1195
1206
|
}
|
|
1196
1207
|
|
|
1197
1208
|
func switchCameras() throws {
|
|
1209
|
+
self.cancelPendingFocusExposureRestore()
|
|
1198
1210
|
configuredVideoFrameRate = nil
|
|
1199
1211
|
guard let currentCameraPosition = currentCameraPosition,
|
|
1200
1212
|
let captureSession = self.captureSession else {
|
|
@@ -2179,46 +2191,116 @@ extension CameraController {
|
|
|
2179
2191
|
}
|
|
2180
2192
|
}
|
|
2181
2193
|
|
|
2182
|
-
|
|
2183
|
-
|
|
2184
|
-
|
|
2185
|
-
|
|
2186
|
-
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
|
-
|
|
2194
|
+
|
|
2195
|
+
private func cancelPendingFocusExposureRestore() {
|
|
2196
|
+
self.focusExposureRestoreGeneration &+= 1
|
|
2197
|
+
self.focusExposureRestoreTimeoutWorkItem?.cancel()
|
|
2198
|
+
self.focusExposureRestoreTimeoutWorkItem = nil
|
|
2199
|
+
}
|
|
2200
|
+
|
|
2201
|
+
private func applyOneShotFocusAndExposure(at point: CGPoint, on device: AVCaptureDevice, adjustExposure: Bool) throws {
|
|
2202
|
+
try device.lockForConfiguration()
|
|
2203
|
+
defer { device.unlockForConfiguration() }
|
|
2204
|
+
|
|
2205
|
+
if device.isFocusModeSupported(.autoFocus) {
|
|
2206
|
+
device.focusMode = .autoFocus
|
|
2207
|
+
} else if device.isFocusModeSupported(.continuousAutoFocus) {
|
|
2208
|
+
device.focusMode = .continuousAutoFocus
|
|
2190
2209
|
}
|
|
2191
2210
|
|
|
2192
|
-
|
|
2211
|
+
if device.isFocusPointOfInterestSupported {
|
|
2212
|
+
device.focusPointOfInterest = point
|
|
2213
|
+
}
|
|
2214
|
+
|
|
2215
|
+
if adjustExposure, device.exposureMode != .locked {
|
|
2216
|
+
if device.isExposurePointOfInterestSupported, device.isExposureModeSupported(.autoExpose) {
|
|
2217
|
+
device.exposureMode = .autoExpose
|
|
2218
|
+
device.setExposureTargetBias(0.0) { _ in }
|
|
2219
|
+
device.exposurePointOfInterest = point
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
|
|
2223
|
+
device.isSubjectAreaChangeMonitoringEnabled = true
|
|
2224
|
+
}
|
|
2225
|
+
|
|
2226
|
+
private func scheduleFocusExposureRestore(for device: AVCaptureDevice) {
|
|
2227
|
+
self.focusExposureRestoreGeneration &+= 1
|
|
2228
|
+
let generation = self.focusExposureRestoreGeneration
|
|
2229
|
+
|
|
2230
|
+
self.focusExposureRestoreTimeoutWorkItem?.cancel()
|
|
2231
|
+
|
|
2232
|
+
let timeoutWork = DispatchWorkItem { [weak self] in
|
|
2233
|
+
self?.restoreContinuousFocusAndExposureIfCurrent(on: device, generation: generation)
|
|
2234
|
+
}
|
|
2235
|
+
self.focusExposureRestoreTimeoutWorkItem = timeoutWork
|
|
2236
|
+
|
|
2237
|
+
self.pollFocusExposureAdjustmentCompletion(on: device, generation: generation)
|
|
2238
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + self.focusExposureRestoreTimeout, execute: timeoutWork)
|
|
2239
|
+
}
|
|
2240
|
+
|
|
2241
|
+
private func pollFocusExposureAdjustmentCompletion(on device: AVCaptureDevice, generation: UInt) {
|
|
2242
|
+
guard generation == self.focusExposureRestoreGeneration else { return }
|
|
2243
|
+
|
|
2244
|
+
if device.isAdjustingFocus || device.isAdjustingExposure {
|
|
2245
|
+
DispatchQueue.main.asyncAfter(deadline: .now() + self.focusExposureRestorePollInterval) { [weak self] in
|
|
2246
|
+
self?.pollFocusExposureAdjustmentCompletion(on: device, generation: generation)
|
|
2247
|
+
}
|
|
2193
2248
|
return
|
|
2194
2249
|
}
|
|
2195
2250
|
|
|
2196
|
-
|
|
2197
|
-
|
|
2251
|
+
self.restoreContinuousFocusAndExposureIfCurrent(on: device, generation: generation)
|
|
2252
|
+
}
|
|
2253
|
+
|
|
2254
|
+
private func restoreContinuousFocusAndExposureIfCurrent(on device: AVCaptureDevice, generation: UInt) {
|
|
2255
|
+
guard generation == self.focusExposureRestoreGeneration else { return }
|
|
2256
|
+
|
|
2257
|
+
self.focusExposureRestoreTimeoutWorkItem?.cancel()
|
|
2258
|
+
self.focusExposureRestoreTimeoutWorkItem = nil
|
|
2198
2259
|
|
|
2199
2260
|
do {
|
|
2200
2261
|
try device.lockForConfiguration()
|
|
2262
|
+
defer { device.unlockForConfiguration() }
|
|
2201
2263
|
|
|
2202
|
-
|
|
2203
|
-
|
|
2204
|
-
|
|
2205
|
-
if device.isFocusPointOfInterestSupported {
|
|
2206
|
-
device.focusPointOfInterest = centerPoint
|
|
2207
|
-
}
|
|
2208
|
-
} else if device.isFocusModeSupported(.continuousAutoFocus) {
|
|
2264
|
+
let centerPoint = CGPoint(x: 0.5, y: 0.5)
|
|
2265
|
+
|
|
2266
|
+
if device.isFocusModeSupported(.continuousAutoFocus) {
|
|
2209
2267
|
device.focusMode = .continuousAutoFocus
|
|
2210
2268
|
if device.isFocusPointOfInterestSupported {
|
|
2211
2269
|
device.focusPointOfInterest = centerPoint
|
|
2212
2270
|
}
|
|
2213
2271
|
}
|
|
2214
2272
|
|
|
2215
|
-
if device.
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
device.
|
|
2273
|
+
if device.exposureMode != .locked {
|
|
2274
|
+
if device.isExposureModeSupported(.continuousAutoExposure) {
|
|
2275
|
+
device.exposureMode = .continuousAutoExposure
|
|
2276
|
+
if device.isExposurePointOfInterestSupported {
|
|
2277
|
+
device.exposurePointOfInterest = centerPoint
|
|
2278
|
+
}
|
|
2279
|
+
device.setExposureTargetBias(0.0) { _ in }
|
|
2219
2280
|
}
|
|
2220
2281
|
}
|
|
2221
|
-
|
|
2282
|
+
|
|
2283
|
+
device.isSubjectAreaChangeMonitoringEnabled = false
|
|
2284
|
+
} catch {
|
|
2285
|
+
print("[CameraPreview] Failed to restore continuous focus/exposure: \(error)")
|
|
2286
|
+
}
|
|
2287
|
+
}
|
|
2288
|
+
|
|
2289
|
+
private func triggerAutoFocus() {
|
|
2290
|
+
guard let device = self.activeVideoDevice() else { return }
|
|
2291
|
+
|
|
2292
|
+
let centerPoint = CGPoint(x: 0.5, y: 0.5)
|
|
2293
|
+
let adjustExposure: Bool
|
|
2294
|
+
do {
|
|
2295
|
+
let exposureMode = try self.getExposureMode()
|
|
2296
|
+
adjustExposure = exposureMode == "AUTO" || exposureMode == "CONTINUOUS"
|
|
2297
|
+
} catch {
|
|
2298
|
+
adjustExposure = true
|
|
2299
|
+
}
|
|
2300
|
+
|
|
2301
|
+
do {
|
|
2302
|
+
try self.applyOneShotFocusAndExposure(at: centerPoint, on: device, adjustExposure: adjustExposure)
|
|
2303
|
+
self.scheduleFocusExposureRestore(for: device)
|
|
2222
2304
|
} catch {
|
|
2223
2305
|
// Silently ignore errors during autofocus
|
|
2224
2306
|
}
|
|
@@ -2257,33 +2339,8 @@ extension CameraController {
|
|
|
2257
2339
|
}
|
|
2258
2340
|
|
|
2259
2341
|
do {
|
|
2260
|
-
try
|
|
2261
|
-
|
|
2262
|
-
// Set focus mode to auto if supported
|
|
2263
|
-
if device.isFocusModeSupported(.autoFocus) {
|
|
2264
|
-
device.focusMode = .autoFocus
|
|
2265
|
-
} else if device.isFocusModeSupported(.continuousAutoFocus) {
|
|
2266
|
-
device.focusMode = .continuousAutoFocus
|
|
2267
|
-
}
|
|
2268
|
-
|
|
2269
|
-
// Set the focus point
|
|
2270
|
-
device.focusPointOfInterest = point
|
|
2271
|
-
|
|
2272
|
-
// Skip exposure point if exposure locked
|
|
2273
|
-
if device.exposureMode != .locked {
|
|
2274
|
-
|
|
2275
|
-
// Also set exposure point if supported
|
|
2276
|
-
if device.isExposurePointOfInterestSupported && device.isExposureModeSupported(.autoExpose) {
|
|
2277
|
-
device.exposureMode = .autoExpose
|
|
2278
|
-
device.setExposureTargetBias(0.0) { _ in }
|
|
2279
|
-
device.exposurePointOfInterest = point
|
|
2280
|
-
}
|
|
2281
|
-
}
|
|
2282
|
-
|
|
2283
|
-
// Turn on subject area monitor for switch to continuous focus if needed
|
|
2284
|
-
device.isSubjectAreaChangeMonitoringEnabled = true
|
|
2285
|
-
|
|
2286
|
-
device.unlockForConfiguration()
|
|
2342
|
+
try self.applyOneShotFocusAndExposure(at: point, on: device, adjustExposure: true)
|
|
2343
|
+
self.scheduleFocusExposureRestore(for: device)
|
|
2287
2344
|
} catch {
|
|
2288
2345
|
throw CameraControllerError.unknown
|
|
2289
2346
|
}
|
|
@@ -2372,6 +2429,7 @@ extension CameraController {
|
|
|
2372
2429
|
}
|
|
2373
2430
|
|
|
2374
2431
|
func swapToDevice(deviceId: String) throws {
|
|
2432
|
+
self.cancelPendingFocusExposureRestore()
|
|
2375
2433
|
guard let captureSession = self.captureSession else {
|
|
2376
2434
|
throw CameraControllerError.captureSessionIsMissing
|
|
2377
2435
|
}
|
|
@@ -2460,6 +2518,7 @@ extension CameraController {
|
|
|
2460
2518
|
}
|
|
2461
2519
|
|
|
2462
2520
|
func cleanup() {
|
|
2521
|
+
self.cancelPendingFocusExposureRestore()
|
|
2463
2522
|
configuredVideoFrameRate = nil
|
|
2464
2523
|
stopBarcodeScanner()
|
|
2465
2524
|
if let captureSession = self.captureSession {
|
|
@@ -2669,6 +2728,100 @@ extension CameraController {
|
|
|
2669
2728
|
}
|
|
2670
2729
|
}
|
|
2671
2730
|
|
|
2731
|
+
// MARK: - White Balance Controls
|
|
2732
|
+
|
|
2733
|
+
func getWhiteBalanceModes() throws -> [String] {
|
|
2734
|
+
var currentCamera: AVCaptureDevice?
|
|
2735
|
+
switch currentCameraPosition {
|
|
2736
|
+
case .front:
|
|
2737
|
+
currentCamera = self.frontCamera
|
|
2738
|
+
case .rear:
|
|
2739
|
+
currentCamera = self.rearCamera
|
|
2740
|
+
default:
|
|
2741
|
+
break
|
|
2742
|
+
}
|
|
2743
|
+
|
|
2744
|
+
guard let device = currentCamera else {
|
|
2745
|
+
throw CameraControllerError.noCamerasAvailable
|
|
2746
|
+
}
|
|
2747
|
+
|
|
2748
|
+
var modes: [String] = []
|
|
2749
|
+
if device.isWhiteBalanceModeSupported(.locked) { modes.append("LOCK") }
|
|
2750
|
+
if device.isWhiteBalanceModeSupported(.autoWhiteBalance) { modes.append("AUTO") }
|
|
2751
|
+
if device.isWhiteBalanceModeSupported(.continuousAutoWhiteBalance) { modes.append("CONTINUOUS") }
|
|
2752
|
+
return modes
|
|
2753
|
+
}
|
|
2754
|
+
|
|
2755
|
+
func getWhiteBalanceMode() throws -> String {
|
|
2756
|
+
var currentCamera: AVCaptureDevice?
|
|
2757
|
+
switch currentCameraPosition {
|
|
2758
|
+
case .front:
|
|
2759
|
+
currentCamera = self.frontCamera
|
|
2760
|
+
case .rear:
|
|
2761
|
+
currentCamera = self.rearCamera
|
|
2762
|
+
default:
|
|
2763
|
+
break
|
|
2764
|
+
}
|
|
2765
|
+
|
|
2766
|
+
guard let device = currentCamera else {
|
|
2767
|
+
throw CameraControllerError.noCamerasAvailable
|
|
2768
|
+
}
|
|
2769
|
+
|
|
2770
|
+
switch device.whiteBalanceMode {
|
|
2771
|
+
case .locked:
|
|
2772
|
+
return "LOCK"
|
|
2773
|
+
case .autoWhiteBalance:
|
|
2774
|
+
return "AUTO"
|
|
2775
|
+
case .continuousAutoWhiteBalance:
|
|
2776
|
+
return "CONTINUOUS"
|
|
2777
|
+
@unknown default:
|
|
2778
|
+
return "CONTINUOUS"
|
|
2779
|
+
}
|
|
2780
|
+
}
|
|
2781
|
+
|
|
2782
|
+
func setWhiteBalanceMode(mode: String) throws {
|
|
2783
|
+
var currentCamera: AVCaptureDevice?
|
|
2784
|
+
switch currentCameraPosition {
|
|
2785
|
+
case .front:
|
|
2786
|
+
currentCamera = self.frontCamera
|
|
2787
|
+
case .rear:
|
|
2788
|
+
currentCamera = self.rearCamera
|
|
2789
|
+
default:
|
|
2790
|
+
break
|
|
2791
|
+
}
|
|
2792
|
+
|
|
2793
|
+
guard let device = currentCamera else {
|
|
2794
|
+
throw CameraControllerError.noCamerasAvailable
|
|
2795
|
+
}
|
|
2796
|
+
|
|
2797
|
+
let normalized = mode.uppercased()
|
|
2798
|
+
let desiredMode: AVCaptureDevice.WhiteBalanceMode?
|
|
2799
|
+
switch normalized {
|
|
2800
|
+
case "LOCK":
|
|
2801
|
+
desiredMode = .locked
|
|
2802
|
+
case "AUTO":
|
|
2803
|
+
desiredMode = .autoWhiteBalance
|
|
2804
|
+
case "CONTINUOUS":
|
|
2805
|
+
desiredMode = .continuousAutoWhiteBalance
|
|
2806
|
+
case "CUSTOM":
|
|
2807
|
+
throw CameraControllerError.invalidOperation
|
|
2808
|
+
default:
|
|
2809
|
+
throw CameraControllerError.invalidOperation
|
|
2810
|
+
}
|
|
2811
|
+
|
|
2812
|
+
guard let finalMode = desiredMode, device.isWhiteBalanceModeSupported(finalMode) else {
|
|
2813
|
+
throw CameraControllerError.invalidOperation
|
|
2814
|
+
}
|
|
2815
|
+
|
|
2816
|
+
do {
|
|
2817
|
+
try device.lockForConfiguration()
|
|
2818
|
+
device.whiteBalanceMode = finalMode
|
|
2819
|
+
device.unlockForConfiguration()
|
|
2820
|
+
} catch {
|
|
2821
|
+
throw CameraControllerError.invalidOperation
|
|
2822
|
+
}
|
|
2823
|
+
}
|
|
2824
|
+
|
|
2672
2825
|
private func activeVideoDevice() -> AVCaptureDevice? {
|
|
2673
2826
|
switch currentCameraPosition {
|
|
2674
2827
|
case .front:
|
|
@@ -2914,38 +3067,16 @@ extension CameraController: UIGestureRecognizerDelegate {
|
|
|
2914
3067
|
|
|
2915
3068
|
@objc
|
|
2916
3069
|
func handleTap(_ tap: UITapGestureRecognizer) {
|
|
2917
|
-
guard let
|
|
2918
|
-
|
|
2919
|
-
let point = tap.location(in: tap.view)
|
|
2920
|
-
let devicePoint = self.previewLayer?.captureDevicePointConverted(fromLayerPoint: point)
|
|
2921
|
-
|
|
2922
|
-
// Show focus indicator at the tap point if not disabled
|
|
2923
|
-
if !self.disableFocusIndicator, let view = tap.view {
|
|
2924
|
-
showFocusIndicator(at: point, in: view)
|
|
3070
|
+
guard let devicePoint = self.previewLayer?.captureDevicePointConverted(fromLayerPoint: tap.location(in: tap.view)) else {
|
|
3071
|
+
return
|
|
2925
3072
|
}
|
|
2926
3073
|
|
|
2927
3074
|
do {
|
|
2928
|
-
try
|
|
2929
|
-
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
device.focusPointOfInterest = CGPoint(x: CGFloat(devicePoint?.x ?? 0), y: CGFloat(devicePoint?.y ?? 0))
|
|
2934
|
-
device.focusMode = focusMode
|
|
2935
|
-
}
|
|
2936
|
-
// Skip exposure point if locked
|
|
2937
|
-
if device.exposureMode != .locked {
|
|
2938
|
-
let exposureMode = AVCaptureDevice.ExposureMode.autoExpose
|
|
2939
|
-
if device.isExposurePointOfInterestSupported && device.isExposureModeSupported(exposureMode) {
|
|
2940
|
-
device.exposurePointOfInterest = CGPoint(x: CGFloat(devicePoint?.x ?? 0), y: CGFloat(devicePoint?.y ?? 0))
|
|
2941
|
-
device.exposureMode = exposureMode
|
|
2942
|
-
device.setExposureTargetBias(0.0) { _ in }
|
|
2943
|
-
}
|
|
2944
|
-
}
|
|
2945
|
-
|
|
2946
|
-
// Turn on subject area monitor for switch to continuous focus if needed
|
|
2947
|
-
device.isSubjectAreaChangeMonitoringEnabled = true
|
|
2948
|
-
|
|
3075
|
+
try self.setFocus(
|
|
3076
|
+
at: devicePoint,
|
|
3077
|
+
showIndicator: !self.disableFocusIndicator,
|
|
3078
|
+
in: tap.view
|
|
3079
|
+
)
|
|
2949
3080
|
} catch {
|
|
2950
3081
|
debugPrint(error)
|
|
2951
3082
|
}
|
|
@@ -35,7 +35,7 @@ extension UIWindow {
|
|
|
35
35
|
*/
|
|
36
36
|
@objc(CameraPreview)
|
|
37
37
|
public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelegate {
|
|
38
|
-
private let pluginVersion: String = "8.
|
|
38
|
+
private let pluginVersion: String = "8.9.0"
|
|
39
39
|
public let identifier = "CameraPreviewPlugin"
|
|
40
40
|
public let jsName = "CameraPreview"
|
|
41
41
|
public let pluginMethods: [CAPPluginMethod] = [
|
|
@@ -90,6 +90,9 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
90
90
|
CAPPluginMethod(name: "getExposureCompensationRange", returnType: CAPPluginReturnPromise),
|
|
91
91
|
CAPPluginMethod(name: "getExposureCompensation", returnType: CAPPluginReturnPromise),
|
|
92
92
|
CAPPluginMethod(name: "setExposureCompensation", returnType: CAPPluginReturnPromise),
|
|
93
|
+
CAPPluginMethod(name: "getWhiteBalanceModes", returnType: CAPPluginReturnPromise),
|
|
94
|
+
CAPPluginMethod(name: "getWhiteBalanceMode", returnType: CAPPluginReturnPromise),
|
|
95
|
+
CAPPluginMethod(name: "setWhiteBalanceMode", returnType: CAPPluginReturnPromise),
|
|
93
96
|
CAPPluginMethod(name: "getSupportedVideoFrameRates", returnType: CAPPluginReturnPromise),
|
|
94
97
|
CAPPluginMethod(name: "getVideoFrameRate", returnType: CAPPluginReturnPromise),
|
|
95
98
|
CAPPluginMethod(name: "setVideoFrameRate", returnType: CAPPluginReturnPromise),
|
|
@@ -2392,6 +2395,58 @@ public class CameraPreview: CAPPlugin, CAPBridgedPlugin, CLLocationManagerDelega
|
|
|
2392
2395
|
}
|
|
2393
2396
|
}
|
|
2394
2397
|
|
|
2398
|
+
// MARK: - White Balance Bridge
|
|
2399
|
+
|
|
2400
|
+
@objc func getWhiteBalanceModes(_ call: CAPPluginCall) {
|
|
2401
|
+
guard isInitialized else {
|
|
2402
|
+
call.reject("Camera not initialized")
|
|
2403
|
+
return
|
|
2404
|
+
}
|
|
2405
|
+
do {
|
|
2406
|
+
let modes = try self.cameraController.getWhiteBalanceModes()
|
|
2407
|
+
call.resolve(["modes": modes])
|
|
2408
|
+
} catch {
|
|
2409
|
+
call.reject("Failed to get white balance modes: \(error.localizedDescription)")
|
|
2410
|
+
}
|
|
2411
|
+
}
|
|
2412
|
+
|
|
2413
|
+
@objc func getWhiteBalanceMode(_ call: CAPPluginCall) {
|
|
2414
|
+
guard isInitialized else {
|
|
2415
|
+
call.reject("Camera not initialized")
|
|
2416
|
+
return
|
|
2417
|
+
}
|
|
2418
|
+
do {
|
|
2419
|
+
let mode = try self.cameraController.getWhiteBalanceMode()
|
|
2420
|
+
call.resolve(["mode": mode])
|
|
2421
|
+
} catch {
|
|
2422
|
+
call.reject("Failed to get white balance mode: \(error.localizedDescription)")
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
|
|
2426
|
+
@objc func setWhiteBalanceMode(_ call: CAPPluginCall) {
|
|
2427
|
+
guard isInitialized else {
|
|
2428
|
+
call.reject("Camera not initialized")
|
|
2429
|
+
return
|
|
2430
|
+
}
|
|
2431
|
+
guard let mode = call.getString("mode") else {
|
|
2432
|
+
call.reject("mode parameter is required")
|
|
2433
|
+
return
|
|
2434
|
+
}
|
|
2435
|
+
let normalized = mode.uppercased()
|
|
2436
|
+
let allowedModes: Set<String> = ["AUTO", "LOCK", "CONTINUOUS"]
|
|
2437
|
+
guard allowedModes.contains(normalized) else {
|
|
2438
|
+
let allowedList = Array(allowedModes).sorted().joined(separator: ", ")
|
|
2439
|
+
call.reject("Invalid white balance mode: \(mode). Allowed values: \(allowedList)")
|
|
2440
|
+
return
|
|
2441
|
+
}
|
|
2442
|
+
do {
|
|
2443
|
+
try self.cameraController.setWhiteBalanceMode(mode: normalized)
|
|
2444
|
+
call.resolve()
|
|
2445
|
+
} catch {
|
|
2446
|
+
call.reject("Failed to set white balance mode: \(error.localizedDescription)")
|
|
2447
|
+
}
|
|
2448
|
+
}
|
|
2449
|
+
|
|
2395
2450
|
// MARK: - Exposure Bridge
|
|
2396
2451
|
|
|
2397
2452
|
@objc func getExposureModes(_ call: CAPPluginCall) {
|