capacitor-camera-view 2.0.1 → 2.0.2

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.
@@ -11,7 +11,7 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
11
11
  .builtInDualCamera,
12
12
  .builtInDualWideCamera,
13
13
  .builtInTripleCamera,
14
- .builtInTrueDepthCamera
14
+ .builtInTrueDepthCamera,
15
15
  ]
16
16
 
17
17
  /// A camera implementation that handles camera session management and photo capture.
@@ -66,8 +66,12 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
66
66
  webView: UIView,
67
67
  completion: @escaping (Error?) -> Void
68
68
  ) {
69
- if let preferredCameraDeviceTypes = configuration.preferredCameraDeviceTypes {
70
- self.preferredCameraDeviceTypes = convertToNativeCameraTypes(preferredCameraDeviceTypes)
69
+ if let preferredCameraDeviceTypes = configuration
70
+ .preferredCameraDeviceTypes
71
+ {
72
+ self.preferredCameraDeviceTypes = convertToNativeCameraTypes(
73
+ preferredCameraDeviceTypes
74
+ )
71
75
  }
72
76
 
73
77
  DispatchQueue.global(qos: .userInitiated).async { [weak self] in
@@ -110,7 +114,8 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
110
114
  await self.upgradeToTripleCameraIfAvailable()
111
115
  }
112
116
  }
113
- })
117
+ }
118
+ )
114
119
  }
115
120
  }
116
121
 
@@ -123,18 +128,18 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
123
128
 
124
129
  DispatchQueue.global(qos: .userInitiated).async { [weak self] in
125
130
  self?.captureSession.stopRunning()
126
- }
127
131
 
128
- DispatchQueue.main.async { [weak self] in
129
- guard let self = self else { return }
130
- self.videoPreviewLayer.removeFromSuperlayer()
131
- self.webView?.isOpaque = true
132
- self.webView?.backgroundColor = nil
133
- self.webView = nil
134
-
135
- if let blurOverlayView = self.blurOverlayView {
136
- blurOverlayView.removeFromSuperview()
137
- self.blurOverlayView = nil
132
+ DispatchQueue.main.async { [weak self] in
133
+ guard let self = self else { return }
134
+ self.videoPreviewLayer.removeFromSuperlayer()
135
+ self.webView?.isOpaque = true
136
+ self.webView?.backgroundColor = nil
137
+ self.webView = nil
138
+
139
+ if let blurOverlayView = self.blurOverlayView {
140
+ blurOverlayView.removeFromSuperview()
141
+ self.blurOverlayView = nil
142
+ }
138
143
  }
139
144
 
140
145
  completion?()
@@ -168,9 +173,11 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
168
173
 
169
174
  // Ensure proper orientation
170
175
  if let photoConnection = avPhotoOutput.connection(with: .video),
171
- let previewConnection = videoPreviewLayer.connection {
176
+ let previewConnection = videoPreviewLayer.connection
177
+ {
172
178
  if photoConnection.isVideoOrientationSupported {
173
- photoConnection.videoOrientation = previewConnection.videoOrientation
179
+ photoConnection.videoOrientation =
180
+ previewConnection.videoOrientation
174
181
  }
175
182
  }
176
183
 
@@ -181,7 +188,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
181
188
  /// Capture a snapshot of the current camera view. This is faster than actually processing a
182
189
  /// photo via capturePhoto
183
190
  /// - Parameter completion: called with the captured UIImage or an error.
184
- public func captureSnapshot(completion: @escaping (UIImage?, Error?) -> Void) {
191
+ public func captureSnapshot(
192
+ completion: @escaping (UIImage?, Error?) -> Void
193
+ ) {
185
194
  guard currentCameraDevice != nil else {
186
195
  completion(nil, CameraError.cameraUnavailable)
187
196
  return
@@ -194,24 +203,33 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
194
203
 
195
204
  // Ensure proper orientation
196
205
  if let videoConnection = avVideoDataOutput.connection(with: .video),
197
- let previewConnection = videoPreviewLayer.connection {
206
+ let previewConnection = videoPreviewLayer.connection
207
+ {
198
208
  if videoConnection.isVideoOrientationSupported {
199
- videoConnection.videoOrientation = previewConnection.videoOrientation
209
+ videoConnection.videoOrientation =
210
+ previewConnection.videoOrientation
200
211
  }
201
212
  }
202
213
 
203
214
  // Create a serial queue for sample buffer processing
204
- let sampleBufferQueue = DispatchQueue(label: "com.michaelwolz.capacitorcameraview.snapshotQueue")
215
+ let sampleBufferQueue = DispatchQueue(
216
+ label: "com.michaelwolz.capacitorcameraview.snapshotQueue"
217
+ )
205
218
 
206
219
  // Set the delegate for a single frame capture
207
220
  snapshotCompletionHandler = completion
208
- avVideoDataOutput.setSampleBufferDelegate(self, queue: sampleBufferQueue)
221
+ avVideoDataOutput.setSampleBufferDelegate(
222
+ self,
223
+ queue: sampleBufferQueue
224
+ )
209
225
  }
210
226
 
211
227
  /// Flips the camera to the opposite position (front to back or back to front).
212
228
  public func flipCamera() throws {
213
- let currentPosition: AVCaptureDevice.Position = currentCameraDevice?.position ?? .back
214
- let newPosition: AVCaptureDevice.Position = currentPosition == .back ? .front : .back
229
+ let currentPosition: AVCaptureDevice.Position =
230
+ currentCameraDevice?.position ?? .back
231
+ let newPosition: AVCaptureDevice.Position =
232
+ currentPosition == .back ? .front : .back
215
233
 
216
234
  let newCamera = try getCameraDevice(for: newPosition)
217
235
  try setInput(with: newCamera)
@@ -222,7 +240,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
222
240
  /// - Parameter mode: The desired flash mode (.on, .of, or .auto).
223
241
  /// - Throws: An error if the flash mode cannot be set or is not supported.
224
242
  public func setFlashMode(_ mode: AVCaptureDevice.FlashMode) throws {
225
- guard let camera = currentCameraDevice else { throw CameraError.cameraUnavailable }
243
+ guard let camera = currentCameraDevice else {
244
+ throw CameraError.cameraUnavailable
245
+ }
226
246
  guard camera.hasFlash else { throw CameraError.unsupportedFlashMode }
227
247
  guard avPhotoOutput.supportedFlashModes.contains(mode)
228
248
  else {
@@ -275,7 +295,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
275
295
  /// - level: The torch intensity level (0.0 to 1.0)
276
296
  /// - Throws: An error if the torch mode cannot be set or is not supported.
277
297
  public func setTorchMode(enabled: Bool, level: Float = 1.0) throws {
278
- guard let camera = currentCameraDevice else { throw CameraError.cameraUnavailable }
298
+ guard let camera = currentCameraDevice else {
299
+ throw CameraError.cameraUnavailable
300
+ }
279
301
  guard camera.hasTorch else { throw CameraError.torchUnavailable }
280
302
 
281
303
  do {
@@ -297,7 +319,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
297
319
  /// because some devices report very high zoom factors that aren't useful.
298
320
  ///
299
321
  /// - Returns: A tuple containing the minimum, maximum, and current zoom factors.
300
- public func getSupportedZoomFactors() -> (min: CGFloat, max: CGFloat, current: CGFloat) {
322
+ public func getSupportedZoomFactors() -> (
323
+ min: CGFloat, max: CGFloat, current: CGFloat
324
+ ) {
301
325
  guard let currentDevice = currentCameraDevice else {
302
326
  return (
303
327
  min: 1.0,
@@ -307,7 +331,10 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
307
331
  }
308
332
 
309
333
  let minZoomFactor = currentDevice.minAvailableVideoZoomFactor
310
- let maxZoomFactor = min(currentDevice.activeFormat.videoMaxZoomFactor, 10.0)
334
+ let maxZoomFactor = min(
335
+ currentDevice.activeFormat.videoMaxZoomFactor,
336
+ 10.0
337
+ )
311
338
  let currentZoomFactor = currentDevice.videoZoomFactor
312
339
 
313
340
  return (
@@ -324,10 +351,15 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
324
351
  /// - ramp: If enabled the zoom will be applied via ramp
325
352
  /// - Throws: An error if the zoom factor cannot be set.
326
353
  public func setZoomFactor(_ factor: CGFloat, ramp: Bool = true) throws {
327
- guard let device = currentCameraDevice else { throw CameraError.cameraUnavailable }
354
+ guard let device = currentCameraDevice else {
355
+ throw CameraError.cameraUnavailable
356
+ }
328
357
 
329
358
  let supportedZoomFactors = getSupportedZoomFactors()
330
- guard factor >= supportedZoomFactors.min && factor <= supportedZoomFactors.max else {
359
+ guard
360
+ factor >= supportedZoomFactors.min
361
+ && factor <= supportedZoomFactors.max
362
+ else {
331
363
  throw CameraError.zoomFactorOutOfRange
332
364
  }
333
365
 
@@ -349,7 +381,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
349
381
  ///
350
382
  /// - Parameters:
351
383
  /// - configuration: The configuration object for the camera session.
352
- private func initiateCaptureSession(configuration: CameraSessionConfiguration) throws {
384
+ private func initiateCaptureSession(
385
+ configuration: CameraSessionConfiguration
386
+ ) throws {
353
387
  captureSession.beginConfiguration()
354
388
  defer { captureSession.commitConfiguration() }
355
389
 
@@ -418,7 +452,6 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
418
452
  }
419
453
  }
420
454
 
421
-
422
455
  /// Enables barcode detection by adding metadata output to the running session.
423
456
  /// Somehow adding the metadata output with the session not being started yet
424
457
  /// caused issues on some devices (iPad 7th Gen) where the session would just
@@ -468,19 +501,26 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
468
501
  /// - position: The position of the camera device to get
469
502
  /// - Returns: The camera device for the specified position
470
503
  /// - Throws: An error if no camera device is found.
471
- private func getCameraDevice(for position: AVCaptureDevice.Position?) throws -> AVCaptureDevice {
504
+ private func getCameraDevice(for position: AVCaptureDevice.Position?) throws
505
+ -> AVCaptureDevice
506
+ {
472
507
  let preferredDevices = getPreferredCameraDevices()
473
508
 
474
509
  // First try to get the best match based on the users preferred camera device types
475
- if let match = preferredDevices.first(where: { $0.position == position }) {
510
+ if let match = preferredDevices.first(where: { $0.position == position }
511
+ ) {
476
512
  return match
477
513
  }
478
514
 
479
515
  // If we haven't found one we try to get a best match for the position by iterating all supported device types
480
516
  // Only doing this when preferredCameraDeviceTypes size differs from SUPPORTED_CAMERA_DEVICE_TYPES, otherwise
481
517
  // we don't have to initialize a new discovery session
482
- if preferredCameraDeviceTypes.count < SUPPORTED_CAMERA_DEVICE_TYPES.count,
483
- let match = getAvailableDevices().first(where: { $0.position == position }) {
518
+ if preferredCameraDeviceTypes.count
519
+ < SUPPORTED_CAMERA_DEVICE_TYPES.count,
520
+ let match = getAvailableDevices().first(where: {
521
+ $0.position == position
522
+ })
523
+ {
484
524
  return match
485
525
  }
486
526
 
@@ -490,8 +530,12 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
490
530
  }
491
531
 
492
532
  // Log when we're falling back to a device with different position than requested
493
- if let requestedPosition = position, device.position != requestedPosition {
494
- print("Warning: Falling back to camera at position \(device.position) when \(requestedPosition) was requested")
533
+ if let requestedPosition = position,
534
+ device.position != requestedPosition
535
+ {
536
+ print(
537
+ "Warning: Falling back to camera at position \(device.position) when \(requestedPosition) was requested"
538
+ )
495
539
  }
496
540
 
497
541
  return device
@@ -503,8 +547,14 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
503
547
  /// - deviceId: The unique identifier of the camera device to get
504
548
  /// - Returns: The camera device for the specified position
505
549
  /// - Throws: An error if no camera device is found.
506
- private func getCameraDeviceById(_ deviceId: String) throws -> AVCaptureDevice {
507
- guard let device = getAvailableDevices().first(where: { $0.uniqueID == deviceId }) else {
550
+ private func getCameraDeviceById(_ deviceId: String) throws
551
+ -> AVCaptureDevice
552
+ {
553
+ guard
554
+ let device = getAvailableDevices().first(where: {
555
+ $0.uniqueID == deviceId
556
+ })
557
+ else {
508
558
  throw CameraError.cameraUnavailable
509
559
  }
510
560
  return device
@@ -519,7 +569,10 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
519
569
  /// - view: The view that will display the camera preview.
520
570
  /// - completion: The completion handler after successfully adding the previewLayer to the provided view
521
571
  /// - Throws: An error if the preview layer cannot be set up.
522
- private func displayPreview(on view: UIView, completion: @escaping (Error?) -> Void) {
572
+ private func displayPreview(
573
+ on view: UIView,
574
+ completion: @escaping (Error?) -> Void
575
+ ) {
523
576
  guard captureSession.isRunning else {
524
577
  completion(CameraError.sessionNotRunning)
525
578
  return
@@ -580,7 +633,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
580
633
  try self.setZoomFactor(2.0, ramp: false)
581
634
  } catch {
582
635
  // Fail silently if we can't upgrade to the triple camera
583
- print("Failed to upgrade to triple camera: \(error.localizedDescription)")
636
+ print(
637
+ "Failed to upgrade to triple camera: \(error.localizedDescription)"
638
+ )
584
639
  }
585
640
 
586
641
  self.captureSession.commitConfiguration()
@@ -612,7 +667,9 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
612
667
  /// Removes the blur overlay with a fade out animation to have a smooth transition
613
668
  /// - Parameter duration: The duration of the fade out animation
614
669
  @MainActor
615
- private func removeBlurOverlayWithAnimation(duration: TimeInterval = 0.3) async {
670
+ private func removeBlurOverlayWithAnimation(duration: TimeInterval = 0.3)
671
+ async
672
+ {
616
673
  guard let blurEffectView = blurOverlayView else { return }
617
674
 
618
675
  await withCheckedContinuation { continuation in
@@ -625,7 +682,8 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
625
682
  blurEffectView.removeFromSuperview()
626
683
  self.blurOverlayView = nil
627
684
  continuation.resume()
628
- })
685
+ }
686
+ )
629
687
  }
630
688
  }
631
689
 
@@ -644,11 +702,15 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
644
702
 
645
703
  /// Updates the preview layer orientation based on the current device orientation.
646
704
  private func updatePreviewOrientation() {
647
- guard let connection = self.videoPreviewLayer.connection, connection.isVideoOrientationSupported else {
705
+ guard let connection = self.videoPreviewLayer.connection,
706
+ connection.isVideoOrientationSupported
707
+ else {
648
708
  return
649
709
  }
650
710
 
651
- let interfaceOrientation = UIApplication.shared.windows.first?.windowScene?.interfaceOrientation ?? .portrait
711
+ let interfaceOrientation =
712
+ UIApplication.shared.windows.first?.windowScene?
713
+ .interfaceOrientation ?? .portrait
652
714
  let videoOrientation: AVCaptureVideoOrientation
653
715
 
654
716
  switch interfaceOrientation {
@@ -688,7 +750,8 @@ internal let SUPPORTED_CAMERA_DEVICE_TYPES: [AVCaptureDevice.DeviceType] = [
688
750
  self,
689
751
  selector: #selector(handleAppDidBecomeActive),
690
752
  name: UIApplication.didBecomeActiveNotification,
691
- object: nil)
753
+ object: nil
754
+ )
692
755
  }
693
756
 
694
757
  /// Handles the app going to background by pausing the camera session.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "capacitor-camera-view",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "A Capacitor plugin for embedding a live camera feed directly into your app.",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",