capacitor-camera-view 1.0.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 (42) hide show
  1. package/CapacitorCameraView.podspec +17 -0
  2. package/LICENSE +201 -0
  3. package/Package.swift +28 -0
  4. package/README.md +654 -0
  5. package/android/build.gradle +79 -0
  6. package/android/src/main/AndroidManifest.xml +2 -0
  7. package/android/src/main/java/com/michaelwolz/capacitorcameraview/CameraView.kt +555 -0
  8. package/android/src/main/java/com/michaelwolz/capacitorcameraview/CameraViewPlugin.kt +227 -0
  9. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/BarcodeDetectionResult.kt +11 -0
  10. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/CameraDevice.kt +14 -0
  11. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/CameraSessionConfiguration.kt +10 -0
  12. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/WebBoundingRect.kt +16 -0
  13. package/android/src/main/java/com/michaelwolz/capacitorcameraview/model/ZoomFactors.kt +14 -0
  14. package/android/src/main/java/com/michaelwolz/capacitorcameraview/utils.kt +86 -0
  15. package/android/src/main/res/.gitkeep +0 -0
  16. package/dist/docs.json +968 -0
  17. package/dist/esm/definitions.d.ts +378 -0
  18. package/dist/esm/definitions.js +2 -0
  19. package/dist/esm/definitions.js.map +1 -0
  20. package/dist/esm/index.d.ts +7 -0
  21. package/dist/esm/index.js +10 -0
  22. package/dist/esm/index.js.map +1 -0
  23. package/dist/esm/utils.d.ts +45 -0
  24. package/dist/esm/utils.js +108 -0
  25. package/dist/esm/utils.js.map +1 -0
  26. package/dist/esm/web.d.ts +108 -0
  27. package/dist/esm/web.js +406 -0
  28. package/dist/esm/web.js.map +1 -0
  29. package/dist/plugin.cjs.js +530 -0
  30. package/dist/plugin.cjs.js.map +1 -0
  31. package/dist/plugin.js +533 -0
  32. package/dist/plugin.js.map +1 -0
  33. package/ios/Sources/CameraViewPlugin/CameraError.swift +39 -0
  34. package/ios/Sources/CameraViewPlugin/CameraSessionConfiguration.swift +32 -0
  35. package/ios/Sources/CameraViewPlugin/CameraViewManager+BarcodeScan.swift +91 -0
  36. package/ios/Sources/CameraViewPlugin/CameraViewManager+PhotoCapture.swift +52 -0
  37. package/ios/Sources/CameraViewPlugin/CameraViewManager+VideoDataOutput.swift +78 -0
  38. package/ios/Sources/CameraViewPlugin/CameraViewManager.swift +633 -0
  39. package/ios/Sources/CameraViewPlugin/CameraViewPlugin.swift +295 -0
  40. package/ios/Sources/CameraViewPlugin/Utils.swift +56 -0
  41. package/ios/Tests/CameraViewPluginTests/CameraViewPluginTests.swift +15 -0
  42. package/package.json +94 -0
@@ -0,0 +1,32 @@
1
+ import AVFoundation
2
+ import Capacitor
3
+
4
+ public struct CameraSessionConfiguration {
5
+ let deviceId: String?
6
+ let enableBarcodeDetection: Bool
7
+ let position: AVCaptureDevice.Position
8
+ let preferredCameraDeviceTypes: [String]?
9
+ let useTripleCameraIfAvailable: Bool
10
+ let zoomFactor: CGFloat?
11
+ }
12
+
13
+ /// Maps a Capacitor plugin call to a CameraSessionConfiguration struct.
14
+ ///
15
+ /// - Parameter call: The Capacitor plugin call.
16
+ public func sessionConfigFromPluginCall(_ call: CAPPluginCall) -> CameraSessionConfiguration {
17
+ let deviceId = call.getString("deviceId")
18
+ let enableBarcodeDetection = call.getBool("enableBarcodeDetection", false)
19
+ let position: AVCaptureDevice.Position = call.getString("position") == "front" ? .front : .back
20
+ let preferredCameraDeviceTypes = call.getArray("preferredCameraDeviceTypes") as? [String]
21
+ let useTripleCameraIfAvailable = call.getBool("useTripleCameraIfAvailable", false)
22
+ let zoomFactor = call.getDouble("zoomFactor").map { CGFloat($0) }
23
+
24
+ return CameraSessionConfiguration(
25
+ deviceId: deviceId,
26
+ enableBarcodeDetection: enableBarcodeDetection,
27
+ position: position,
28
+ preferredCameraDeviceTypes: preferredCameraDeviceTypes,
29
+ useTripleCameraIfAvailable: useTripleCameraIfAvailable,
30
+ zoomFactor: zoomFactor
31
+ )
32
+ }
@@ -0,0 +1,91 @@
1
+ import AVFoundation
2
+ import Foundation
3
+
4
+ extension CameraViewManager: AVCaptureMetadataOutputObjectsDelegate {
5
+ /// Set up metadata output for the capture session in case it's not configured yet
6
+ /// Make sure to call `captureSession.beginConfiguration` before calling this
7
+ ///
8
+ /// - Throws: An error if the output cannot be set.
9
+ internal func setupMetadataOutput() throws {
10
+ let metadataOutput = AVCaptureMetadataOutput()
11
+
12
+ if (captureSession.outputs.contains { $0 is AVCaptureMetadataOutput }) {
13
+ // Nothing todo, we already have an output
14
+ return
15
+ }
16
+
17
+ if !captureSession.canAddOutput(metadataOutput) {
18
+ throw CameraError.outputAdditionFailed
19
+ }
20
+
21
+ captureSession.addOutput(metadataOutput)
22
+
23
+ metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
24
+
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
+ ]
41
+ }
42
+
43
+ /// Delegate method called when metadata objects are detected in the camera feed
44
+ ///
45
+ /// This method processes barcode data detected in the camera stream. When a barcode is detected,
46
+ /// it extracts the barcode value and type, then emits a Capacitor event with the barcode data.
47
+ ///
48
+ /// - Parameters:
49
+ /// - output: The metadata output object that captured the data.
50
+ /// - metadataObjects: An array of detected metadata objects, potentially including barcodes.
51
+ /// - connection: The connection through which the metadata objects were captured.
52
+ public func metadataOutput(
53
+ _ output: AVCaptureMetadataOutput,
54
+ didOutput metadataObjects: [AVMetadataObject],
55
+ from connection: AVCaptureConnection
56
+ ) {
57
+ guard let metadataObject = metadataObjects.first as? AVMetadataMachineReadableCodeObject
58
+ else {
59
+ return
60
+ }
61
+ guard let barcodeValue = metadataObject.stringValue else { return }
62
+
63
+ let barcodeType = metadataObject.type.rawValue
64
+
65
+ // Transform the metadata object to the coordinate space of the video preview layer
66
+ // This is necessary to get the correct bounding box for the detected barcode
67
+ // Which in our case should always equal to the device's screen
68
+ // This way we can simply use pixel coordinates to get the bounding box of the detected barcode and easily show it in the webview
69
+ guard let transformedMetadataObject = videoPreviewLayer.transformedMetadataObject(for: metadataObject)
70
+ else {
71
+ return
72
+ }
73
+
74
+ let boundingRect: [String: Double] = [
75
+ "x": Double(transformedMetadataObject.bounds.origin.x),
76
+ "y": Double(transformedMetadataObject.bounds.origin.y),
77
+ "width": Double(transformedMetadataObject.bounds.width),
78
+ "height": Double(transformedMetadataObject.bounds.height),
79
+ ]
80
+
81
+ NotificationCenter.default.post(
82
+ name: Notification.Name("barcodeDetected"),
83
+ object: nil,
84
+ userInfo: [
85
+ "value": barcodeValue,
86
+ "type": barcodeType,
87
+ "boundingRect": boundingRect,
88
+ ]
89
+ )
90
+ }
91
+ }
@@ -0,0 +1,52 @@
1
+ import AVFoundation
2
+ import Foundation
3
+ import UIKit
4
+
5
+ extension CameraViewManager: AVCapturePhotoCaptureDelegate {
6
+ /// Set up output for the capture session in case it's not configured yet
7
+ /// Make sure to call `captureSession.beginConfiguration` before calling this
8
+ ///
9
+ /// - Throws: An error if the output cannot be set.
10
+ internal func setupPhotoOutput() throws {
11
+ if (captureSession.outputs.contains { $0 is AVCapturePhotoOutput }) {
12
+ // Nothing todo, we already have an output and since we only
13
+ // use outputs for taking photos here we don't need a new one
14
+ return
15
+ }
16
+
17
+ // Balanced should be a good choice for most use cases
18
+ avPhotoOutput.maxPhotoQualityPrioritization = .balanced
19
+
20
+ if !captureSession.canAddOutput(avPhotoOutput) {
21
+ throw CameraError.outputAdditionFailed
22
+ }
23
+
24
+ captureSession.addOutput(avPhotoOutput)
25
+ }
26
+
27
+ /// Delegate method called when a photo has been captured via `AVCapturePhotoCaptureDelegate`
28
+ ///
29
+ /// - Parameters:
30
+ /// - output: The photo output that captured the photo.
31
+ /// - photo: The captured photo.
32
+ /// - error: An error that occurred during photo capture.
33
+ public func photoOutput(
34
+ _ output: AVCapturePhotoOutput,
35
+ didFinishProcessingPhoto photo: AVCapturePhoto,
36
+ error: Error?
37
+ ) {
38
+ if let error = error {
39
+ photoCaptureHandler?(nil, error)
40
+ return
41
+ }
42
+
43
+ guard let data = photo.fileDataRepresentation(), let image = UIImage(data: data) else {
44
+ photoCaptureHandler?(nil, CameraError.photoOutputError)
45
+ return
46
+ }
47
+
48
+ photoCaptureHandler?(image, nil)
49
+ }
50
+
51
+ }
52
+
@@ -0,0 +1,78 @@
1
+ import AVFoundation
2
+ import CoreImage
3
+ import Foundation
4
+ import UIKit
5
+
6
+ extension CameraViewManager: AVCaptureVideoDataOutputSampleBufferDelegate {
7
+ /// Set up video data output for the capture session in case it's not configured yet
8
+ /// This is used for taking snapshots of the camera feed
9
+ /// Make sure to call `captureSession.beginConfiguration` before calling this
10
+ ///
11
+ /// - Throws: An error if the output cannot be set.
12
+ /// - Note: This method does not set the delegate for the output. The delegate is set
13
+ /// when a snapshot is requested.
14
+ internal func setupVideoDataOutput() throws {
15
+ if (captureSession.outputs.contains { $0 is AVCaptureVideoDataOutput }) {
16
+ // Nothing todo, we already have an output and since we only
17
+ // use video outputs for taking snapshots here we don't need a new one
18
+ return
19
+ }
20
+
21
+ // Configure video data output
22
+ avVideoDataOutput.videoSettings = [
23
+ kCVPixelBufferPixelFormatTypeKey as String: Int(kCVPixelFormatType_32BGRA)
24
+ ]
25
+ avVideoDataOutput.alwaysDiscardsLateVideoFrames = true
26
+
27
+ // We're not setting the delegate here as we'll set it only when needed for snapshot capture
28
+
29
+ if !captureSession.canAddOutput(avVideoDataOutput) {
30
+ throw CameraError.outputAdditionFailed
31
+ }
32
+
33
+ captureSession.addOutput(avVideoDataOutput)
34
+ }
35
+
36
+ /// Capture a snapshot from the camera feed
37
+ public func captureOutput(
38
+ _ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer,
39
+ from connection: AVCaptureConnection
40
+ ) {
41
+ // Only process if we have a completion handler set
42
+ guard let completionHandler = snapshotCompletionHandler else { return }
43
+
44
+ // Clear the completion handler to ensure we only capture one frame
45
+ snapshotCompletionHandler = nil
46
+
47
+ avVideoDataOutput.setSampleBufferDelegate(nil, queue: nil)
48
+
49
+ guard let imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else {
50
+ completionHandler(nil, CameraError.frameCaptureError)
51
+ return
52
+ }
53
+
54
+ let ciImage = CIImage(cvPixelBuffer: imageBuffer)
55
+ let context = CIContext()
56
+ guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else {
57
+ completionHandler(nil, CameraError.frameCaptureError)
58
+ return
59
+ }
60
+
61
+ let image = UIImage(cgImage: cgImage)
62
+ completionHandler(image, nil)
63
+ }
64
+
65
+ /// Delegate method called when a frame is dropped via `AVCaptureVideoDataOutputSampleBufferDelegate`
66
+ public func captureOutput(
67
+ _ output: AVCaptureOutput, didDrop sampleBuffer: CMSampleBuffer,
68
+ from connection: AVCaptureConnection
69
+ ) {
70
+ // If we have a completion handler and a frame was dropped, report the error
71
+ if let completionHandler = snapshotCompletionHandler {
72
+ snapshotCompletionHandler = nil
73
+ avVideoDataOutput.setSampleBufferDelegate(nil, queue: nil)
74
+
75
+ completionHandler(nil, CameraError.frameCaptureError)
76
+ }
77
+ }
78
+ }