@scr2em/capacitor-scanner 6.0.33 → 6.0.34
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.
|
@@ -246,31 +246,24 @@ public class CapacitorScannerPlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureMetad
|
|
|
246
246
|
AVVideoCompressionPropertiesKey: [AVVideoQualityKey: qualityNumber]])
|
|
247
247
|
|
|
248
248
|
let maxPrioritization = photoOutput.maxPhotoQualityPrioritization
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
249
|
+
if maxPrioritization.rawValue >= AVCapturePhotoOutput.QualityPrioritization.quality.rawValue {
|
|
250
|
+
photoSettings.photoQualityPrioritization = .quality
|
|
251
|
+
} else if maxPrioritization.rawValue >= AVCapturePhotoOutput.QualityPrioritization.balanced.rawValue {
|
|
252
252
|
photoSettings.photoQualityPrioritization = .balanced
|
|
253
253
|
} else {
|
|
254
|
-
// Use the lowest prioritization (.speed)
|
|
255
254
|
photoSettings.photoQualityPrioritization = .speed
|
|
256
255
|
}
|
|
257
256
|
|
|
257
|
+
// Enable high-resolution capture for sharper photos
|
|
258
|
+
photoSettings.isHighResolutionPhotoEnabled = true
|
|
259
|
+
|
|
258
260
|
} else {
|
|
259
261
|
print("JPEG codec not supported for photo capture. Using default settings.")
|
|
260
262
|
// photoSettings remains the default initialized one
|
|
261
263
|
}
|
|
262
264
|
|
|
263
265
|
self.capturePhotoCall = call
|
|
264
|
-
|
|
265
|
-
// If business card detection is enabled, wait for 1 second before capturing
|
|
266
|
-
if self.enabledDetectionTypes.contains("businessCard") {
|
|
267
|
-
DispatchQueue.main.asyncAfter(deadline: .now() + 0.6) {
|
|
268
|
-
photoOutput.capturePhoto(with: photoSettings, delegate: self)
|
|
269
|
-
}
|
|
270
|
-
} else {
|
|
271
|
-
// Otherwise capture immediately
|
|
272
|
-
photoOutput.capturePhoto(with: photoSettings, delegate: self)
|
|
273
|
-
}
|
|
266
|
+
photoOutput.capturePhoto(with: photoSettings, delegate: self)
|
|
274
267
|
}
|
|
275
268
|
|
|
276
269
|
public func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) {
|
|
@@ -297,37 +290,22 @@ public class CapacitorScannerPlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureMetad
|
|
|
297
290
|
if self.enabledDetectionTypes.contains("businessCard"),
|
|
298
291
|
isRectangleCurrentlyDetected,
|
|
299
292
|
let detectedRect = self.rectangleDetector?.lastDetectedRectangle {
|
|
300
|
-
//
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
return
|
|
306
|
-
}
|
|
307
|
-
let base64String = croppedImageData.base64EncodedString()
|
|
308
|
-
self.capturePhotoCall?.resolve(["imageBase64": "data:image/jpeg;base64, \(base64String)"])
|
|
309
|
-
} else {
|
|
310
|
-
let base64String = imageData.base64EncodedString()
|
|
311
|
-
self.capturePhotoCall?.resolve(["imageBase64": "data:image/jpeg;base64, \(base64String)"])
|
|
312
|
-
}
|
|
313
|
-
} else {
|
|
314
|
-
// Use the captured photo if no snapshot available
|
|
315
|
-
guard let image = UIImage(data: imageData) else {
|
|
316
|
-
self.capturePhotoCall?.reject("Unable to create image from data")
|
|
317
|
-
return
|
|
318
|
-
}
|
|
293
|
+
// Always use the high-resolution captured photo for cropping (not the video frame snapshot)
|
|
294
|
+
guard let image = UIImage(data: imageData) else {
|
|
295
|
+
self.capturePhotoCall?.reject("Unable to create image from data")
|
|
296
|
+
return
|
|
297
|
+
}
|
|
319
298
|
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
}
|
|
325
|
-
let base64String = croppedImageData.base64EncodedString()
|
|
326
|
-
self.capturePhotoCall?.resolve(["imageBase64": "data:image/jpeg;base64, \(base64String)"])
|
|
327
|
-
} else {
|
|
328
|
-
let base64String = imageData.base64EncodedString()
|
|
329
|
-
self.capturePhotoCall?.resolve(["imageBase64": "data:image/jpeg;base64, \(base64String)"])
|
|
299
|
+
if let croppedImage = self.cropImage(image, toRectangle: detectedRect) {
|
|
300
|
+
guard let croppedImageData = croppedImage.jpegData(compressionQuality: 0.9) else {
|
|
301
|
+
self.capturePhotoCall?.reject("Unable to convert cropped image to data")
|
|
302
|
+
return
|
|
330
303
|
}
|
|
304
|
+
let base64String = croppedImageData.base64EncodedString()
|
|
305
|
+
self.capturePhotoCall?.resolve(["imageBase64": "data:image/jpeg;base64, \(base64String)"])
|
|
306
|
+
} else {
|
|
307
|
+
let base64String = imageData.base64EncodedString()
|
|
308
|
+
self.capturePhotoCall?.resolve(["imageBase64": "data:image/jpeg;base64, \(base64String)"])
|
|
331
309
|
}
|
|
332
310
|
} else {
|
|
333
311
|
// No rectangle detected, return original image
|
|
@@ -540,6 +518,8 @@ public class CapacitorScannerPlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureMetad
|
|
|
540
518
|
self.photoOutput = photoOutput
|
|
541
519
|
if captureSession.canAddOutput(photoOutput) {
|
|
542
520
|
captureSession.addOutput(photoOutput)
|
|
521
|
+
photoOutput.maxPhotoQualityPrioritization = .quality
|
|
522
|
+
photoOutput.isHighResolutionCaptureEnabled = true
|
|
543
523
|
} else {
|
|
544
524
|
call.reject("Unable to add photo output to capture session")
|
|
545
525
|
return
|
|
@@ -1066,7 +1046,6 @@ extension CapacitorScannerPlugin: AVCaptureVideoDataOutputSampleBufferDelegate {
|
|
|
1066
1046
|
if !isThrottled,
|
|
1067
1047
|
self.enabledDetectionTypes.contains("businessCard"),
|
|
1068
1048
|
let detector = self.rectangleDetector {
|
|
1069
|
-
detector.updatePixelBuffer(pixelBuffer)
|
|
1070
1049
|
requests.append(detector.visionRequest)
|
|
1071
1050
|
}
|
|
1072
1051
|
|
|
@@ -18,14 +18,6 @@ struct RectangleCorners {
|
|
|
18
18
|
/// Handles rectangle/business card detection using Vision framework
|
|
19
19
|
class RectangleDetector {
|
|
20
20
|
|
|
21
|
-
// MARK: - Types
|
|
22
|
-
|
|
23
|
-
/// Stores detected rectangle with optional snapshot for cropping
|
|
24
|
-
struct DetectedRectangle {
|
|
25
|
-
let observation: VNRectangleObservation
|
|
26
|
-
let snapshot: UIImage?
|
|
27
|
-
}
|
|
28
|
-
|
|
29
21
|
// MARK: - Configuration
|
|
30
22
|
|
|
31
23
|
private let confidenceThreshold: Float = 0.8
|
|
@@ -38,10 +30,8 @@ class RectangleDetector {
|
|
|
38
30
|
|
|
39
31
|
// MARK: - State
|
|
40
32
|
|
|
41
|
-
private(set) var lastDetectedRectangle:
|
|
33
|
+
private(set) var lastDetectedRectangle: VNRectangleObservation?
|
|
42
34
|
private(set) var lastDetectionTime: Date?
|
|
43
|
-
private var currentPixelBuffer: CVPixelBuffer?
|
|
44
|
-
private let ciContext = CIContext(options: nil)
|
|
45
35
|
|
|
46
36
|
// Stability tracking
|
|
47
37
|
private var previousCorners: RectangleCorners?
|
|
@@ -100,11 +90,6 @@ class RectangleDetector {
|
|
|
100
90
|
emitIntervalSeconds = max(0, seconds)
|
|
101
91
|
}
|
|
102
92
|
|
|
103
|
-
/// Update the current pixel buffer for snapshot capture
|
|
104
|
-
func updatePixelBuffer(_ pixelBuffer: CVPixelBuffer) {
|
|
105
|
-
self.currentPixelBuffer = pixelBuffer
|
|
106
|
-
}
|
|
107
|
-
|
|
108
93
|
/// Check for detection timeout and update overlay
|
|
109
94
|
func checkTimeout() {
|
|
110
95
|
smoother?.checkTimeout()
|
|
@@ -120,7 +105,6 @@ class RectangleDetector {
|
|
|
120
105
|
func reset() {
|
|
121
106
|
lastDetectedRectangle = nil
|
|
122
107
|
lastDetectionTime = nil
|
|
123
|
-
currentPixelBuffer = nil
|
|
124
108
|
previousCorners = nil
|
|
125
109
|
stabilityStartTime = nil
|
|
126
110
|
lastEmitTime = nil
|
|
@@ -157,8 +141,8 @@ class RectangleDetector {
|
|
|
157
141
|
return
|
|
158
142
|
}
|
|
159
143
|
|
|
160
|
-
// Store rectangle
|
|
161
|
-
|
|
144
|
+
// Store rectangle observation for cropping
|
|
145
|
+
lastDetectedRectangle = bestCandidate
|
|
162
146
|
|
|
163
147
|
// Update detection time
|
|
164
148
|
lastDetectionTime = Date()
|
|
@@ -287,34 +271,4 @@ class RectangleDetector {
|
|
|
287
271
|
}
|
|
288
272
|
}
|
|
289
273
|
|
|
290
|
-
private func captureSnapshot(for observation: VNRectangleObservation) {
|
|
291
|
-
guard let pixelBuffer = currentPixelBuffer else {
|
|
292
|
-
lastDetectedRectangle = DetectedRectangle(observation: observation, snapshot: nil)
|
|
293
|
-
return
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
let ciImage = CIImage(cvPixelBuffer: pixelBuffer)
|
|
297
|
-
|
|
298
|
-
guard let cgImage = ciContext.createCGImage(ciImage, from: ciImage.extent) else {
|
|
299
|
-
lastDetectedRectangle = DetectedRectangle(observation: observation, snapshot: nil)
|
|
300
|
-
return
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
// Create UIImage with correct orientation
|
|
304
|
-
let deviceOrientation = UIDevice.current.orientation
|
|
305
|
-
let uiOrientation: UIImage.Orientation
|
|
306
|
-
switch deviceOrientation {
|
|
307
|
-
case .landscapeLeft:
|
|
308
|
-
uiOrientation = .right
|
|
309
|
-
case .landscapeRight:
|
|
310
|
-
uiOrientation = .left
|
|
311
|
-
case .portraitUpsideDown:
|
|
312
|
-
uiOrientation = .down
|
|
313
|
-
default:
|
|
314
|
-
uiOrientation = .up
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
let snapshot = UIImage(cgImage: cgImage, scale: 1.0, orientation: uiOrientation)
|
|
318
|
-
lastDetectedRectangle = DetectedRectangle(observation: observation, snapshot: snapshot)
|
|
319
|
-
}
|
|
320
274
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@scr2em/capacitor-scanner",
|
|
3
|
-
"version": "6.0.
|
|
3
|
+
"version": "6.0.34",
|
|
4
4
|
"description": "scan codes",
|
|
5
5
|
"main": "dist/plugin.cjs.js",
|
|
6
6
|
"module": "dist/esm/index.js",
|
|
@@ -29,23 +29,6 @@
|
|
|
29
29
|
"plugin",
|
|
30
30
|
"native"
|
|
31
31
|
],
|
|
32
|
-
"scripts": {
|
|
33
|
-
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
34
|
-
"verify:ios": "xcodebuild -scheme CapacitorScanner -destination generic/platform=iOS",
|
|
35
|
-
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
36
|
-
"verify:web": "npm run build",
|
|
37
|
-
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
38
|
-
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
39
|
-
"eslint": "eslint . --ext ts",
|
|
40
|
-
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
41
|
-
"swiftlint": "node-swiftlint",
|
|
42
|
-
"docgen": "docgen --api CapacitorScannerPlugin --output-readme README.md --output-json dist/docs.json",
|
|
43
|
-
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
44
|
-
"clean": "rimraf ./dist",
|
|
45
|
-
"watch": "tsc --watch",
|
|
46
|
-
"prepublishOnly": "npm run build",
|
|
47
|
-
"prepare": "npm run build"
|
|
48
|
-
},
|
|
49
32
|
"devDependencies": {
|
|
50
33
|
"@capacitor/android": "6.0.0",
|
|
51
34
|
"@capacitor/cli": "6.0.0",
|
|
@@ -78,5 +61,20 @@
|
|
|
78
61
|
"android": {
|
|
79
62
|
"src": "android"
|
|
80
63
|
}
|
|
64
|
+
},
|
|
65
|
+
"scripts": {
|
|
66
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
67
|
+
"verify:ios": "xcodebuild -scheme CapacitorScanner -destination generic/platform=iOS",
|
|
68
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
69
|
+
"verify:web": "npm run build",
|
|
70
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
71
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
72
|
+
"eslint": "eslint . --ext ts",
|
|
73
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\" --plugin=prettier-plugin-java",
|
|
74
|
+
"swiftlint": "node-swiftlint",
|
|
75
|
+
"docgen": "docgen --api CapacitorScannerPlugin --output-readme README.md --output-json dist/docs.json",
|
|
76
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.mjs",
|
|
77
|
+
"clean": "rimraf ./dist",
|
|
78
|
+
"watch": "tsc --watch"
|
|
81
79
|
}
|
|
82
80
|
}
|