capacitor-camera-view 2.0.1 → 2.1.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.
Files changed (28) hide show
  1. package/README.md +19 -9
  2. package/android/build.gradle +8 -5
  3. package/android/src/main/java/com/michaelwolz/capacitorcameraview/CameraView.kt +217 -126
  4. package/android/src/main/java/com/michaelwolz/capacitorcameraview/CameraViewPlugin.kt +70 -30
  5. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/CameraResult.kt +47 -0
  6. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/CameraSessionConfiguration.kt +11 -1
  7. package/android/src/main/java/com/michaelwolz/capacitorcameraview/utils.kt +94 -5
  8. package/dist/docs.json +81 -0
  9. package/dist/esm/definitions.d.ts +44 -0
  10. package/dist/esm/definitions.js.map +1 -1
  11. package/dist/esm/web.d.ts +7 -1
  12. package/dist/esm/web.js +67 -2
  13. package/dist/esm/web.js.map +1 -1
  14. package/dist/plugin.cjs.js +68 -2
  15. package/dist/plugin.cjs.js.map +1 -1
  16. package/dist/plugin.js +68 -2
  17. package/dist/plugin.js.map +1 -1
  18. package/ios/Sources/CameraViewPlugin/CameraError.swift +97 -2
  19. package/ios/Sources/CameraViewPlugin/CameraEvents.swift +109 -0
  20. package/ios/Sources/CameraViewPlugin/CameraSessionConfiguration.swift +29 -2
  21. package/ios/Sources/CameraViewPlugin/CameraViewManager+BarcodeScan.swift +30 -41
  22. package/ios/Sources/CameraViewPlugin/CameraViewManager+PhotoCapture.swift +45 -13
  23. package/ios/Sources/CameraViewPlugin/CameraViewManager+VideoDataOutput.swift +4 -3
  24. package/ios/Sources/CameraViewPlugin/CameraViewManager.swift +193 -59
  25. package/ios/Sources/CameraViewPlugin/CameraViewPlugin.swift +83 -84
  26. package/ios/Sources/CameraViewPlugin/TempFileManager.swift +181 -0
  27. package/ios/Sources/CameraViewPlugin/Utils.swift +102 -0
  28. package/package.json +17 -17
@@ -5,39 +5,34 @@ extension CameraViewManager: AVCaptureMetadataOutputObjectsDelegate {
5
5
  /// Set up metadata output for the capture session in case it's not configured yet
6
6
  /// Make sure to call `captureSession.beginConfiguration` before calling this
7
7
  ///
8
+ /// - Parameter barcodeTypes: Optional array of specific barcode types to detect.
9
+ /// If nil, all supported types are detected (backwards compatible).
8
10
  /// - Throws: An error if the output cannot be set.
9
- internal func setupMetadataOutput() throws {
10
- let metadataOutput = AVCaptureMetadataOutput()
11
+ internal func setupMetadataOutput(barcodeTypes: [AVMetadataObject.ObjectType]? = nil) throws {
12
+ let requestedBarcodeTypes = barcodeTypes ?? ALL_SUPPORTED_BARCODE_TYPES
11
13
 
12
- if (captureSession.outputs.contains { $0 is AVCaptureMetadataOutput }) {
13
- // Nothing todo, we already have an output
14
- return
15
- }
14
+ let metadataOutput: AVCaptureMetadataOutput
16
15
 
17
- if !captureSession.canAddOutput(metadataOutput) {
18
- throw CameraError.outputAdditionFailed
19
- }
16
+ if let existingOutput = captureSession.outputs.first(where: { $0 is AVCaptureMetadataOutput }) as? AVCaptureMetadataOutput {
17
+ metadataOutput = existingOutput
18
+ } else {
19
+ let newOutput = AVCaptureMetadataOutput()
20
+ if !captureSession.canAddOutput(newOutput) {
21
+ throw CameraError.outputAdditionFailed
22
+ }
20
23
 
21
- captureSession.addOutput(metadataOutput)
24
+ captureSession.addOutput(newOutput)
25
+ newOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
26
+ metadataOutput = newOutput
27
+ }
22
28
 
23
- metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
29
+ let supportedTypes = Set(metadataOutput.availableMetadataObjectTypes)
30
+ let resolvedTypes = requestedBarcodeTypes.filter { supportedTypes.contains($0) }
24
31
 
25
- // Set all available barcode types
26
- metadataOutput.metadataObjectTypes = [
27
- .qr,
28
- .code128,
29
- .code39,
30
- .code39Mod43,
31
- .code93,
32
- .ean8,
33
- .ean13,
34
- .interleaved2of5,
35
- .itf14,
36
- .pdf417,
37
- .aztec,
38
- .dataMatrix,
39
- .upce
40
- ]
32
+ if metadataOutput.metadataObjectTypes != resolvedTypes {
33
+ // Update the metadata output with the resolved types only if they differ from the current configuration
34
+ metadataOutput.metadataObjectTypes = resolvedTypes
35
+ }
41
36
  }
42
37
 
43
38
  /// Remove the metadata output if in case it is already configured, e.g. because
@@ -80,21 +75,15 @@ extension CameraViewManager: AVCaptureMetadataOutputObjectsDelegate {
80
75
  return
81
76
  }
82
77
 
83
- let boundingRect: [String: Double] = [
84
- "x": Double(transformedMetadataObject.bounds.origin.x),
85
- "y": Double(transformedMetadataObject.bounds.origin.y),
86
- "width": Double(transformedMetadataObject.bounds.width),
87
- "height": Double(transformedMetadataObject.bounds.height)
88
- ]
78
+ let boundingRect = BarcodeDetectedEvent.BoundingRect(
79
+ x: Double(transformedMetadataObject.bounds.origin.x),
80
+ y: Double(transformedMetadataObject.bounds.origin.y),
81
+ width: Double(transformedMetadataObject.bounds.width),
82
+ height: Double(transformedMetadataObject.bounds.height)
83
+ )
89
84
 
90
- NotificationCenter.default.post(
91
- name: Notification.Name("barcodeDetected"),
92
- object: nil,
93
- userInfo: [
94
- "value": barcodeValue,
95
- "type": barcodeType,
96
- "boundingRect": boundingRect
97
- ]
85
+ eventEmitter.emitBarcodeDetected(
86
+ BarcodeDetectedEvent(value: barcodeValue, type: barcodeType, boundingRect: boundingRect)
98
87
  )
99
88
  }
100
89
  }
@@ -13,19 +13,22 @@ extension CameraViewManager: AVCapturePhotoCaptureDelegate {
13
13
  // use outputs for taking photos here we don't need a new one
14
14
  return
15
15
  }
16
-
16
+
17
17
  // Balanced should be a good choice for most use cases
18
18
  avPhotoOutput.maxPhotoQualityPrioritization = .balanced
19
-
19
+
20
20
  if !captureSession.canAddOutput(avPhotoOutput) {
21
21
  throw CameraError.outputAdditionFailed
22
22
  }
23
-
23
+
24
24
  captureSession.addOutput(avPhotoOutput)
25
25
  }
26
-
26
+
27
27
  /// Delegate method called when a photo has been captured via `AVCapturePhotoCaptureDelegate`
28
28
  ///
29
+ /// This method handles both the legacy UIImage-based callback and the optimized Data-based
30
+ /// callback to eliminate double JPEG encoding when possible.
31
+ ///
29
32
  /// - Parameters:
30
33
  /// - output: The photo output that captured the photo.
31
34
  /// - photo: The captured photo.
@@ -35,17 +38,46 @@ extension CameraViewManager: AVCapturePhotoCaptureDelegate {
35
38
  didFinishProcessingPhoto photo: AVCapturePhoto,
36
39
  error: Error?
37
40
  ) {
38
- if let error = error {
39
- photoCaptureHandler?(nil, error)
41
+ // Handle optimized Data-based callback first (avoids double encoding)
42
+ if let dataHandler = photoDataCaptureHandler {
43
+ photoDataCaptureHandler = nil
44
+
45
+ if let error = error {
46
+ dataHandler(nil, error)
47
+ return
48
+ }
49
+
50
+ guard let data = photo.fileDataRepresentation() else {
51
+ dataHandler(nil, CameraError.photoOutputError)
52
+ return
53
+ }
54
+
55
+ dataHandler(data, nil)
40
56
  return
41
57
  }
42
-
43
- guard let data = photo.fileDataRepresentation(), let image = UIImage(data: data) else {
44
- photoCaptureHandler?(nil, CameraError.photoOutputError)
45
- return
58
+
59
+ // Handle legacy UIImage-based callback
60
+ if let imageHandler = photoCaptureHandler {
61
+ photoCaptureHandler = nil
62
+
63
+ if let error = error {
64
+ imageHandler(nil, error)
65
+ return
66
+ }
67
+
68
+ guard let data = photo.fileDataRepresentation() else {
69
+ imageHandler(nil, CameraError.photoOutputError)
70
+ return
71
+ }
72
+
73
+ guard let image = UIImage(data: data) else {
74
+ imageHandler(nil, CameraError.photoOutputError)
75
+ return
76
+ }
77
+
78
+ imageHandler(image, nil)
46
79
  }
47
-
48
- photoCaptureHandler?(image, nil)
49
80
  }
50
-
81
+
51
82
  }
83
+
@@ -33,7 +33,8 @@ extension CameraViewManager: AVCaptureVideoDataOutputSampleBufferDelegate {
33
33
  captureSession.addOutput(avVideoDataOutput)
34
34
  }
35
35
 
36
- /// Capture a snapshot from the camera feed
36
+ /// Capture a snapshot from the camera feed using the shared Metal-backed CIContext.
37
+ /// Using a shared CIContext eliminates the ~80% CPU overhead of creating one per frame.
37
38
  public func captureOutput(
38
39
  _ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer,
39
40
  from connection: AVCaptureConnection
@@ -52,8 +53,8 @@ extension CameraViewManager: AVCaptureVideoDataOutputSampleBufferDelegate {
52
53
  }
53
54
 
54
55
  let ciImage = CIImage(cvPixelBuffer: imageBuffer)
55
- let context = CIContext()
56
- guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {
56
+ // Use the shared Metal-backed CIContext for efficient rendering
57
+ guard let cgImage = CameraViewManager.sharedCIContext.createCGImage(ciImage, from: ciImage.extent) else {
57
58
  completionHandler(nil, CameraError.frameCaptureError)
58
59
  return
59
60
  }