@momo-kits/camerakit 0.152.4 → 0.152.5
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/android/build.gradle
CHANGED
|
@@ -68,7 +68,7 @@ dependencies {
|
|
|
68
68
|
|
|
69
69
|
implementation 'com.google.mlkit:barcode-scanning:17.3.0'
|
|
70
70
|
|
|
71
|
-
implementation
|
|
71
|
+
implementation fileTree(dir: "libs", include: ["*.aar"])
|
|
72
72
|
implementation 'com.google.zxing:core:3.5.1'
|
|
73
73
|
}
|
|
74
74
|
repositories {
|
|
Binary file
|
|
@@ -10,6 +10,9 @@ import UIKit
|
|
|
10
10
|
import CoreMotion
|
|
11
11
|
import Vision
|
|
12
12
|
|
|
13
|
+
// Global OCR queue (so OCR never blocks sessionQueue)
|
|
14
|
+
let globalOCRQueue = DispatchQueue(label: "com.tesla.react-native-camera-kit.ocr", qos: .userInitiated)
|
|
15
|
+
|
|
13
16
|
/*
|
|
14
17
|
* Real camera implementation that uses AVFoundation
|
|
15
18
|
*/
|
|
@@ -21,16 +24,16 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
21
24
|
private let session = AVCaptureSession()
|
|
22
25
|
// Communicate with the session and other session objects on this queue.
|
|
23
26
|
private let sessionQueue = DispatchQueue(label: "com.tesla.react-native-camera-kit")
|
|
24
|
-
|
|
27
|
+
|
|
25
28
|
// utilities
|
|
26
29
|
private var setupResult: SetupResult = .notStarted
|
|
27
30
|
private var isSessionRunning: Bool = false
|
|
28
31
|
private var backgroundRecordingId: UIBackgroundTaskIdentifier = .invalid
|
|
29
|
-
|
|
32
|
+
|
|
30
33
|
private var videoDeviceInput: AVCaptureDeviceInput?
|
|
31
34
|
private let photoOutput = AVCapturePhotoOutput()
|
|
32
35
|
private let metadataOutput = AVCaptureMetadataOutput()
|
|
33
|
-
|
|
36
|
+
|
|
34
37
|
private var resizeMode: ResizeMode = .cover
|
|
35
38
|
private var flashMode: FlashMode = .auto
|
|
36
39
|
private var torchMode: TorchMode = .off
|
|
@@ -45,23 +48,25 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
45
48
|
private var lastOnZoom: Double?
|
|
46
49
|
private var zoom: Double?
|
|
47
50
|
private var maxZoom: Double?
|
|
48
|
-
|
|
51
|
+
|
|
49
52
|
private var deviceOrientation = UIDeviceOrientation.unknown
|
|
50
53
|
private var motionManager: CMMotionManager?
|
|
51
|
-
|
|
54
|
+
|
|
52
55
|
// KVO observation
|
|
53
56
|
private var adjustingFocusObservation: NSKeyValueObservation?
|
|
54
57
|
|
|
55
58
|
// Keep delegate objects in memory to avoid collecting them before photo capturing finishes
|
|
56
59
|
private var inProgressPhotoCaptureDelegates = [Int64: PhotoCaptureDelegate]()
|
|
57
|
-
|
|
60
|
+
|
|
58
61
|
private var onTextRead: ((_ text: String) -> Void)?
|
|
59
62
|
private let videoDataOutput = AVCaptureVideoDataOutput()
|
|
60
63
|
private var textRequest: VNRecognizeTextRequest?
|
|
61
64
|
private var textDetectionEnabled = false
|
|
62
65
|
private var lastTextProcess = Date.distantPast
|
|
63
66
|
private let textThrottle: TimeInterval = 0.35 // seconds
|
|
64
|
-
|
|
67
|
+
|
|
68
|
+
private var zoomStartedAt: Double = 1.0
|
|
69
|
+
|
|
65
70
|
// MARK: - Lifecycle
|
|
66
71
|
|
|
67
72
|
func cameraRemovedFromSuperview() {
|
|
@@ -87,15 +92,15 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
87
92
|
UIDevice.current.endGeneratingDeviceOrientationNotifications()
|
|
88
93
|
#endif
|
|
89
94
|
}
|
|
90
|
-
|
|
95
|
+
|
|
91
96
|
deinit {
|
|
92
97
|
removeObservers()
|
|
93
98
|
}
|
|
94
|
-
|
|
99
|
+
|
|
95
100
|
// MARK: - Public
|
|
96
101
|
|
|
97
102
|
func setup(cameraType: CameraType, supportedBarcodeType: [CodeFormat]) {
|
|
98
|
-
|
|
103
|
+
|
|
99
104
|
// Setup the capture session with priority on basic video preview first
|
|
100
105
|
sessionQueue.async {
|
|
101
106
|
self.setupResult = self.setupBasicVideoInput(cameraType: cameraType)
|
|
@@ -117,7 +122,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
117
122
|
self.setVideoOrientationToInterfaceOrientation()
|
|
118
123
|
}
|
|
119
124
|
}
|
|
120
|
-
|
|
125
|
+
|
|
121
126
|
DispatchQueue.global(qos: .utility).async {
|
|
122
127
|
self.initializeMotionManager()
|
|
123
128
|
}
|
|
@@ -125,37 +130,36 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
125
130
|
}
|
|
126
131
|
|
|
127
132
|
// MARK: - Private optimization methods
|
|
128
|
-
|
|
133
|
+
|
|
129
134
|
private func setupBasicVideoInput(cameraType: CameraType) -> SetupResult {
|
|
130
135
|
guard let videoDevice = self.getBestDevice(for: cameraType),
|
|
131
136
|
let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice) else {
|
|
132
137
|
return .sessionConfigurationFailed
|
|
133
138
|
}
|
|
134
|
-
|
|
139
|
+
|
|
135
140
|
session.beginConfiguration()
|
|
136
141
|
defer { session.commitConfiguration() }
|
|
137
|
-
|
|
142
|
+
|
|
138
143
|
if session.canAddInput(videoDeviceInput) {
|
|
139
144
|
session.addInput(videoDeviceInput)
|
|
140
145
|
self.videoDeviceInput = videoDeviceInput
|
|
141
146
|
self.resetZoom(forDevice: videoDevice)
|
|
142
147
|
return .success
|
|
143
|
-
} else {
|
|
144
|
-
return .sessionConfigurationFailed
|
|
145
148
|
}
|
|
149
|
+
return .sessionConfigurationFailed
|
|
146
150
|
}
|
|
147
|
-
|
|
151
|
+
|
|
148
152
|
private func setupAdditionalOutputs(supportedBarcodeType: [CodeFormat]) {
|
|
149
153
|
session.beginConfiguration()
|
|
150
154
|
defer { session.commitConfiguration() }
|
|
151
|
-
|
|
155
|
+
|
|
152
156
|
// Add photo output
|
|
153
157
|
if #available(iOS 13.0, *) {
|
|
154
|
-
if let maxPhotoQualityPrioritization {
|
|
158
|
+
if let maxPhotoQualityPrioritization = maxPhotoQualityPrioritization {
|
|
155
159
|
photoOutput.maxPhotoQualityPrioritization = maxPhotoQualityPrioritization.avQualityPrioritization
|
|
156
160
|
}
|
|
157
161
|
}
|
|
158
|
-
|
|
162
|
+
|
|
159
163
|
if session.canAddOutput(photoOutput) {
|
|
160
164
|
session.addOutput(photoOutput)
|
|
161
165
|
|
|
@@ -165,12 +169,12 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
165
169
|
}
|
|
166
170
|
}
|
|
167
171
|
}
|
|
168
|
-
|
|
172
|
+
|
|
169
173
|
// Add metadata output for barcode scanning
|
|
170
174
|
if self.session.canAddOutput(metadataOutput) {
|
|
171
175
|
self.session.addOutput(metadataOutput)
|
|
172
176
|
metadataOutput.setMetadataObjectsDelegate(self, queue: DispatchQueue.main)
|
|
173
|
-
|
|
177
|
+
|
|
174
178
|
let availableTypes = self.metadataOutput.availableMetadataObjectTypes
|
|
175
179
|
let filteredTypes = supportedBarcodeType
|
|
176
180
|
.map { $0.toAVMetadataObjectType() }
|
|
@@ -178,21 +182,39 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
178
182
|
|
|
179
183
|
metadataOutput.metadataObjectTypes = filteredTypes
|
|
180
184
|
}
|
|
181
|
-
|
|
185
|
+
|
|
182
186
|
// add for text detections
|
|
183
187
|
if (textRequest != nil && self.session.canAddOutput(self.videoDataOutput)) {
|
|
184
188
|
self.session.addOutput(self.videoDataOutput)
|
|
185
189
|
}
|
|
186
190
|
}
|
|
187
|
-
|
|
188
|
-
|
|
191
|
+
|
|
192
|
+
// MARK: - Pause / Resume non-essential outputs
|
|
193
|
+
private func pauseNonEssentialOutputs() {
|
|
194
|
+
videoDataOutput.setSampleBufferDelegate(nil, queue: nil)
|
|
195
|
+
metadataOutput.rectOfInterest = CGRect(x: 0, y: 0, width: 0, height: 0)
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private func resumeNonEssentialOutputs() {
|
|
199
|
+
if textDetectionEnabled {
|
|
200
|
+
videoDataOutput.setSampleBufferDelegate(self, queue: globalOCRQueue)
|
|
201
|
+
}
|
|
202
|
+
// Restore real rect of interest
|
|
203
|
+
if let scanner = scannerFrameSize, scanner != .zero {
|
|
204
|
+
metadataOutput.rectOfInterest =
|
|
205
|
+
cameraPreview.previewLayer.metadataOutputRectConverted(fromLayerRect: scanner)
|
|
206
|
+
} else {
|
|
207
|
+
metadataOutput.rectOfInterest = CGRect(x: 0, y: 0, width: 1, height: 1)
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
|
|
189
211
|
func zoomPinchStart() {
|
|
190
212
|
sessionQueue.async {
|
|
191
213
|
guard let videoDevice = self.videoDeviceInput?.device else { return }
|
|
192
214
|
self.zoomStartedAt = videoDevice.videoZoomFactor
|
|
193
215
|
}
|
|
194
216
|
}
|
|
195
|
-
|
|
217
|
+
|
|
196
218
|
func zoomPinchChange(pinchScale: CGFloat) {
|
|
197
219
|
guard !pinchScale.isNaN else { return }
|
|
198
220
|
|
|
@@ -201,7 +223,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
201
223
|
|
|
202
224
|
let desiredZoomFactor = (self.zoomStartedAt / self.defaultZoomFactor(for: videoDevice)) * pinchScale
|
|
203
225
|
let zoomForDevice = self.getValidZoom(forDevice: videoDevice, zoom: desiredZoomFactor)
|
|
204
|
-
|
|
226
|
+
|
|
205
227
|
if zoomForDevice != self.normalizedZoom(for: videoDevice) {
|
|
206
228
|
// Only trigger zoom changes if it's an uncontrolled component (zoom isn't manually set)
|
|
207
229
|
// otherwise it's likely to cause issues inf. loops
|
|
@@ -212,14 +234,14 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
212
234
|
}
|
|
213
235
|
}
|
|
214
236
|
}
|
|
215
|
-
|
|
237
|
+
|
|
216
238
|
func update(maxZoom: Double?) {
|
|
217
239
|
self.maxZoom = maxZoom
|
|
218
240
|
|
|
219
241
|
// Re-update zoom value in case the max was increased
|
|
220
242
|
self.update(zoom: self.zoom)
|
|
221
243
|
}
|
|
222
|
-
|
|
244
|
+
|
|
223
245
|
func update(zoom: Double?) {
|
|
224
246
|
sessionQueue.async {
|
|
225
247
|
self.zoom = zoom
|
|
@@ -230,7 +252,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
230
252
|
self.setZoomFor(videoDevice, to: zoomForDevice)
|
|
231
253
|
}
|
|
232
254
|
}
|
|
233
|
-
|
|
255
|
+
|
|
234
256
|
/**
|
|
235
257
|
`desiredZoom` can be nil when we want to notify what the zoom factor really is
|
|
236
258
|
*/
|
|
@@ -251,11 +273,11 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
251
273
|
lastOnZoom = desiredOrCameraZoom
|
|
252
274
|
self.onZoomCallback?(["zoom": desiredOrCameraZoom])
|
|
253
275
|
}
|
|
254
|
-
|
|
276
|
+
|
|
255
277
|
func update(onZoom: RCTDirectEventBlock?) {
|
|
256
278
|
self.onZoomCallback = onZoom
|
|
257
279
|
}
|
|
258
|
-
|
|
280
|
+
|
|
259
281
|
func focus(at touchPoint: CGPoint, focusBehavior: FocusBehavior) {
|
|
260
282
|
DispatchQueue.main.async {
|
|
261
283
|
let devicePoint = self.cameraPreview.previewLayer.captureDevicePointConverted(fromLayerPoint: touchPoint)
|
|
@@ -270,7 +292,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
270
292
|
self.resetFocus = nil
|
|
271
293
|
self.focusFinished = nil
|
|
272
294
|
}
|
|
273
|
-
|
|
295
|
+
|
|
274
296
|
do {
|
|
275
297
|
try videoDevice.lockForConfiguration()
|
|
276
298
|
|
|
@@ -293,11 +315,11 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
293
315
|
}
|
|
294
316
|
}
|
|
295
317
|
}
|
|
296
|
-
|
|
318
|
+
|
|
297
319
|
func update(onOrientationChange: RCTDirectEventBlock?) {
|
|
298
320
|
self.onOrientationChange = onOrientationChange
|
|
299
321
|
}
|
|
300
|
-
|
|
322
|
+
|
|
301
323
|
func update(torchMode: TorchMode) {
|
|
302
324
|
sessionQueue.async {
|
|
303
325
|
self.torchMode = torchMode
|
|
@@ -314,11 +336,11 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
314
336
|
}
|
|
315
337
|
}
|
|
316
338
|
}
|
|
317
|
-
|
|
339
|
+
|
|
318
340
|
func update(flashMode: FlashMode) {
|
|
319
341
|
self.flashMode = flashMode
|
|
320
342
|
}
|
|
321
|
-
|
|
343
|
+
|
|
322
344
|
func update(maxPhotoQualityPrioritization: MaxPhotoQualityPrioritization?) {
|
|
323
345
|
guard #available(iOS 13.0, *) else { return }
|
|
324
346
|
guard maxPhotoQualityPrioritization != self.maxPhotoQualityPrioritization else { return }
|
|
@@ -329,7 +351,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
329
351
|
self.photoOutput.maxPhotoQualityPrioritization = maxPhotoQualityPrioritization?.avQualityPrioritization ?? .balanced
|
|
330
352
|
}
|
|
331
353
|
}
|
|
332
|
-
|
|
354
|
+
|
|
333
355
|
func update(cameraType: CameraType) {
|
|
334
356
|
sessionQueue.async {
|
|
335
357
|
if self.videoDeviceInput?.device.position == cameraType.avPosition {
|
|
@@ -343,14 +365,14 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
343
365
|
let videoDeviceInput = try? AVCaptureDeviceInput(device: videoDevice) else {
|
|
344
366
|
return
|
|
345
367
|
}
|
|
346
|
-
|
|
368
|
+
|
|
347
369
|
self.removeObservers()
|
|
348
370
|
self.session.beginConfiguration()
|
|
349
371
|
defer { self.session.commitConfiguration() }
|
|
350
372
|
|
|
351
373
|
// Remove the existing device input first, since using the front and back camera simultaneously is not supported.
|
|
352
374
|
self.session.removeInput(currentViewDeviceInput)
|
|
353
|
-
|
|
375
|
+
|
|
354
376
|
if self.session.canAddInput(videoDeviceInput) {
|
|
355
377
|
self.session.addInput(videoDeviceInput)
|
|
356
378
|
self.resetZoom(forDevice: videoDevice)
|
|
@@ -359,14 +381,14 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
359
381
|
// If it fails, put back current camera
|
|
360
382
|
self.session.addInput(currentViewDeviceInput)
|
|
361
383
|
}
|
|
362
|
-
|
|
384
|
+
|
|
363
385
|
self.addObservers()
|
|
364
386
|
|
|
365
387
|
// We need to reapply the configuration after reloading the camera
|
|
366
388
|
self.update(torchMode: self.torchMode)
|
|
367
389
|
}
|
|
368
390
|
}
|
|
369
|
-
|
|
391
|
+
|
|
370
392
|
func update(resizeMode: ResizeMode) {
|
|
371
393
|
DispatchQueue.main.async {
|
|
372
394
|
switch resizeMode {
|
|
@@ -377,24 +399,28 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
377
399
|
}
|
|
378
400
|
}
|
|
379
401
|
}
|
|
380
|
-
|
|
402
|
+
|
|
381
403
|
func capturePicture(onWillCapture: @escaping () -> Void,
|
|
382
|
-
|
|
383
|
-
|
|
404
|
+
onSuccess: @escaping (_ imageData: Data, _ thumbnailData: Data?, _ dimensions: CMVideoDimensions) -> Void,
|
|
405
|
+
onError: @escaping (_ message: String) -> Void) {
|
|
384
406
|
/*
|
|
385
407
|
Retrieve the video preview layer's video orientation on the main queue before
|
|
386
408
|
entering the session queue. Do this to ensure that UI elements are accessed on
|
|
387
409
|
the main thread and session configuration is done on the session queue.
|
|
388
410
|
*/
|
|
411
|
+
|
|
412
|
+
// Pause OCR + barcode before capturing
|
|
413
|
+
self.pauseNonEssentialOutputs()
|
|
414
|
+
|
|
389
415
|
DispatchQueue.main.async { [weak self] in
|
|
390
416
|
guard let self = self else {
|
|
391
417
|
onError("Camera was deallocated")
|
|
392
418
|
return
|
|
393
419
|
}
|
|
394
|
-
|
|
420
|
+
|
|
395
421
|
let videoPreviewLayerOrientation =
|
|
396
422
|
self.videoOrientation(from: self.deviceOrientation) ?? self.cameraPreview.previewLayer.connection?.videoOrientation
|
|
397
|
-
|
|
423
|
+
|
|
398
424
|
self.sessionQueue.async { [weak self] in
|
|
399
425
|
guard let self = self else {
|
|
400
426
|
onError("Camera was deallocated")
|
|
@@ -407,14 +433,14 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
407
433
|
onError("Camera session is not running")
|
|
408
434
|
return
|
|
409
435
|
}
|
|
410
|
-
|
|
436
|
+
|
|
411
437
|
// Ensure photo output has an active video connection
|
|
412
438
|
guard let photoOutputConnection = self.photoOutput.connection(with: .video) else {
|
|
413
439
|
print("Cannot capture photo: no video connection available")
|
|
414
440
|
onError("Camera connection is not available")
|
|
415
441
|
return
|
|
416
442
|
}
|
|
417
|
-
|
|
443
|
+
|
|
418
444
|
// Verify the connection is active and enabled
|
|
419
445
|
guard photoOutputConnection.isActive && photoOutputConnection.isEnabled else {
|
|
420
446
|
print("Cannot capture photo: video connection is not active or enabled")
|
|
@@ -443,30 +469,33 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
443
469
|
// Use weak self to prevent crash if camera is deallocated during capture
|
|
444
470
|
self?.inProgressPhotoCaptureDelegates[uniqueID] = nil
|
|
445
471
|
onSuccess(imageData, thumbnailData, dimensions)
|
|
472
|
+
self?.resumeNonEssentialOutputs()
|
|
446
473
|
},
|
|
447
474
|
onCaptureError: { [weak self] uniqueID, errorMessage in
|
|
448
475
|
// Use weak self to prevent crash if camera is deallocated during capture
|
|
449
476
|
self?.inProgressPhotoCaptureDelegates[uniqueID] = nil
|
|
450
477
|
onError(errorMessage)
|
|
478
|
+
self?.resumeNonEssentialOutputs()
|
|
451
479
|
}
|
|
452
480
|
)
|
|
453
|
-
|
|
481
|
+
|
|
454
482
|
self.inProgressPhotoCaptureDelegates[photoCaptureDelegate.requestedPhotoSettings.uniqueID] = photoCaptureDelegate
|
|
455
483
|
self.photoOutput.capturePhoto(with: settings, delegate: photoCaptureDelegate)
|
|
456
484
|
}
|
|
457
485
|
}
|
|
458
486
|
}
|
|
459
|
-
|
|
487
|
+
|
|
488
|
+
// MARK: - Barcode scanning
|
|
460
489
|
func isBarcodeScannerEnabled(_ isEnabled: Bool,
|
|
461
490
|
supportedBarcodeTypes supportedBarcodeType: [CodeFormat],
|
|
462
491
|
onBarcodeRead: ((_ barcode: String,_ codeFormat:CodeFormat) -> Void)?) {
|
|
463
492
|
sessionQueue.async {
|
|
464
493
|
self.onBarcodeRead = onBarcodeRead
|
|
494
|
+
|
|
495
|
+
let availableTypes = self.metadataOutput.availableMetadataObjectTypes
|
|
465
496
|
let newTypes: [AVMetadataObject.ObjectType]
|
|
466
497
|
if isEnabled && onBarcodeRead != nil {
|
|
467
|
-
|
|
468
|
-
newTypes = supportedBarcodeType.map { $0.toAVMetadataObjectType() }
|
|
469
|
-
.filter { availableTypes.contains($0) }
|
|
498
|
+
newTypes = supportedBarcodeType.map { $0.toAVMetadataObjectType() }.filter { availableTypes.contains($0) }
|
|
470
499
|
} else {
|
|
471
500
|
newTypes = []
|
|
472
501
|
}
|
|
@@ -479,11 +508,11 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
479
508
|
}
|
|
480
509
|
}
|
|
481
510
|
}
|
|
482
|
-
|
|
511
|
+
|
|
483
512
|
func update(barcodeFrameSize: CGSize?) {
|
|
484
513
|
self.barcodeFrameSize = barcodeFrameSize
|
|
485
514
|
}
|
|
486
|
-
|
|
515
|
+
|
|
487
516
|
func update(scannerFrameSize: CGRect?) {
|
|
488
517
|
guard self.scannerFrameSize != scannerFrameSize else { return }
|
|
489
518
|
self.sessionQueue.async {
|
|
@@ -491,7 +520,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
491
520
|
if !self.session.isRunning {
|
|
492
521
|
return
|
|
493
522
|
}
|
|
494
|
-
|
|
523
|
+
|
|
495
524
|
DispatchQueue.main.async {
|
|
496
525
|
var visibleRect: CGRect?
|
|
497
526
|
if scannerFrameSize != nil && scannerFrameSize != .zero {
|
|
@@ -510,7 +539,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
510
539
|
}
|
|
511
540
|
}
|
|
512
541
|
}
|
|
513
|
-
|
|
542
|
+
|
|
514
543
|
|
|
515
544
|
func isTextDetectionEnabled(_ isEnabled: Bool, onTextRead: ((String) -> Void)?) {
|
|
516
545
|
sessionQueue.async {
|
|
@@ -525,37 +554,39 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
525
554
|
self.textRequest?.recognitionLanguages = ["en", "fr", "de", "es", "vi"]
|
|
526
555
|
self.textRequest?.recognitionLevel = .accurate
|
|
527
556
|
self.textRequest?.usesLanguageCorrection = false
|
|
528
|
-
|
|
557
|
+
|
|
529
558
|
self.videoDataOutput.alwaysDiscardsLateVideoFrames = true
|
|
530
|
-
self.videoDataOutput.setSampleBufferDelegate(self, queue:
|
|
559
|
+
self.videoDataOutput.setSampleBufferDelegate(self, queue: globalOCRQueue)
|
|
531
560
|
self.videoDataOutput.videoSettings = [
|
|
532
561
|
kCVPixelBufferPixelFormatTypeKey as String: kCVPixelFormatType_420YpCbCr8BiPlanarFullRange
|
|
533
562
|
]
|
|
534
|
-
|
|
563
|
+
|
|
535
564
|
} else {
|
|
536
565
|
self.textRequest = nil
|
|
537
566
|
}
|
|
538
567
|
}
|
|
539
568
|
}
|
|
540
|
-
|
|
569
|
+
|
|
541
570
|
// AVCaptureVideoDataOutputSampleBufferDelegate
|
|
542
571
|
func captureOutput(_ output: AVCaptureOutput, didOutput sampleBuffer: CMSampleBuffer, from connection: AVCaptureConnection) {
|
|
543
572
|
guard textDetectionEnabled, let request = textRequest else { return }
|
|
544
573
|
let now = Date()
|
|
545
574
|
if now.timeIntervalSince(lastTextProcess) < textThrottle { return }
|
|
546
575
|
lastTextProcess = now
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
576
|
+
|
|
577
|
+
globalOCRQueue.async {
|
|
578
|
+
guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
|
|
579
|
+
var requestOptions: [VNImageOption: Any] = [:]
|
|
580
|
+
|
|
581
|
+
let handler = VNImageRequestHandler(cvPixelBuffer: pixelBuffer, orientation: .up, options: requestOptions)
|
|
582
|
+
do {
|
|
583
|
+
try handler.perform([request])
|
|
584
|
+
} catch {
|
|
585
|
+
// ignore OCR errors; don't crash the pipeline
|
|
586
|
+
}
|
|
556
587
|
}
|
|
557
588
|
}
|
|
558
|
-
|
|
589
|
+
|
|
559
590
|
// MARK: - AVCaptureMetadataOutputObjectsDelegate
|
|
560
591
|
|
|
561
592
|
func metadataOutput(_ output: AVCaptureMetadataOutput, didOutput metadataObjects: [AVMetadataObject], from connection: AVCaptureConnection) {
|
|
@@ -569,7 +600,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
569
600
|
|
|
570
601
|
onBarcodeRead?(codeStringValue,barcodeType)
|
|
571
602
|
}
|
|
572
|
-
|
|
603
|
+
|
|
573
604
|
// MARK: - Private
|
|
574
605
|
|
|
575
606
|
private func videoOrientation(from deviceOrientation: UIDeviceOrientation) -> AVCaptureVideoOrientation? {
|
|
@@ -588,7 +619,7 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
588
619
|
@unknown default: return nil
|
|
589
620
|
}
|
|
590
621
|
}
|
|
591
|
-
|
|
622
|
+
|
|
592
623
|
private func videoOrientation(from interfaceOrientation: UIInterfaceOrientation) -> AVCaptureVideoOrientation {
|
|
593
624
|
switch interfaceOrientation {
|
|
594
625
|
case .portrait:
|
|
@@ -603,14 +634,14 @@ class RealCamera: NSObject, CameraProtocol, AVCaptureMetadataOutputObjectsDelega
|
|
|
603
634
|
@unknown default: return .portrait
|
|
604
635
|
}
|
|
605
636
|
}
|
|
606
|
-
|
|
637
|
+
|
|
607
638
|
private func getBestDevice(for cameraType: CameraType) -> AVCaptureDevice? {
|
|
608
639
|
if let device = AVCaptureDevice.default(.builtInWideAngleCamera, for: .video, position: cameraType.avPosition) {
|
|
609
640
|
return device // single-lens/physical device
|
|
610
641
|
}
|
|
611
642
|
return nil
|
|
612
643
|
}
|
|
613
|
-
|
|
644
|
+
|
|
614
645
|
private func defaultZoomFactor(for videoDevice: AVCaptureDevice) -> CGFloat {
|
|
615
646
|
let fallback = 1.0
|
|
616
647
|
guard #available(iOS 13.0, *) else { return fallback }
|
package/package.json
CHANGED
|
@@ -1,41 +1,41 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
}
|
|
2
|
+
"name": "@momo-kits/camerakit",
|
|
3
|
+
"version": "0.152.5",
|
|
4
|
+
"repository": {
|
|
5
|
+
"type": "git",
|
|
6
|
+
"url": "https://github.com/teslamotors/react-native-camera-kit.git"
|
|
7
|
+
},
|
|
8
|
+
"publishConfig": {
|
|
9
|
+
"registry": "https://registry.npmjs.org/"
|
|
10
|
+
},
|
|
11
|
+
"description": "A high performance, fully featured, rock solid camera library for React Native applications",
|
|
12
|
+
"nativePackage": true,
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "echo",
|
|
15
|
+
"test": "jest",
|
|
16
|
+
"lint": "yarn eslint -c .eslintrc.js"
|
|
17
|
+
},
|
|
18
|
+
"main": "./src/index.ts",
|
|
19
|
+
"dependencies": {},
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"devDependencies": {
|
|
22
|
+
"react": "19.0.0",
|
|
23
|
+
"react-native": "0.80.1"
|
|
24
|
+
},
|
|
25
|
+
"peerDependencies": {
|
|
26
|
+
"react": "*",
|
|
27
|
+
"react-native": "*"
|
|
28
|
+
},
|
|
29
|
+
"engines": {
|
|
30
|
+
"node": ">=18"
|
|
31
|
+
},
|
|
32
|
+
"codegenConfig": {
|
|
33
|
+
"name": "rncamerakit_specs",
|
|
34
|
+
"type": "all",
|
|
35
|
+
"jsSrcsDir": "src/specs",
|
|
36
|
+
"android": {
|
|
37
|
+
"javaPackageName": "com.rncamerakit"
|
|
38
|
+
}
|
|
39
|
+
},
|
|
40
|
+
"packageManager": "yarn@1.22.22"
|
|
41
|
+
}
|