@scr2em/capacitor-scanner 6.0.24 → 6.0.26

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/README.md CHANGED
@@ -183,12 +183,14 @@ removeAllListeners() => any
183
183
  ### enableObjectDetection(...)
184
184
 
185
185
  ```typescript
186
- enableObjectDetection(options: ObjectDetectionOptions) => any
186
+ enableObjectDetection(options?: ObjectDetectionOptions | undefined) => any
187
187
  ```
188
188
 
189
- | Param | Type |
190
- | ------------- | ------------------------------------------------------------------------- |
191
- | **`options`** | <code><a href="#objectdetectionoptions">ObjectDetectionOptions</a></code> |
189
+ Enable object detection (business card). This will start detecting business cards.
190
+
191
+ | Param | Type | Description |
192
+ | ------------- | ------------------------------------------------------------------------- | --------------------------------------------- |
193
+ | **`options`** | <code><a href="#objectdetectionoptions">ObjectDetectionOptions</a></code> | - Optional configuration for object detection |
192
194
 
193
195
  **Returns:** <code>any</code>
194
196
 
@@ -201,6 +203,8 @@ enableObjectDetection(options: ObjectDetectionOptions) => any
201
203
  disableObjectDetection() => any
202
204
  ```
203
205
 
206
+ Disable object detection. This will stop detecting business cards.
207
+
204
208
  **Returns:** <code>any</code>
205
209
 
206
210
  --------------------
@@ -258,7 +262,7 @@ Set the camera zoom level.
258
262
 
259
263
  #### StartOptions
260
264
 
261
- <code>{ /** * Barcode formats to detect when barcodeDetection is enabled. */ formats?: BarcodeFormat[]; /** * Camera direction to use. Defaults to 'BACK'. */ cameraDirection?: 'BACK' | 'FRONT'; /** * Enable barcode detection on start. Defaults to false. * When enabled, the camera will automatically detect barcodes and emit 'barcodeScanned' events. */ barcodeDetection?: boolean; /** * Whether to show the highlight overlay for detected barcodes. Defaults to false. * Only applies when barcodeDetection is true. */ barcodeHighlight?: boolean; /** * Enable object detection (business card) on start. Defaults to false. * When enabled, the camera will automatically detect business cards and emit 'rectangleDetected' events. */ objectDetection?: boolean; /** * Whether to show the highlight overlay for detected business cards. Defaults to true. * Only applies when objectDetection is true. */ objectHighlight?: boolean; debounceTimeInMilli?: number; /** * Optional regex pattern to filter scanned barcodes. * If provided, only barcodes matching this pattern will be reported. */ regex?: string; /** * Optional regex flags (e.g., 'i' for case-insensitive, 'm' for multiline). */ regexFlags?: string; }</code>
265
+ <code>{ /** * Barcode formats to detect when barcodeDetection is enabled. */ formats?: BarcodeFormat[]; /** * Camera direction to use. Defaults to 'BACK'. */ cameraDirection?: 'BACK' | 'FRONT'; /** * Enable barcode detection on start. Defaults to false. * When enabled, the camera will automatically detect barcodes and emit 'barcodeScanned' events. */ barcodeDetection?: boolean; /** * Whether to show the highlight overlay for detected barcodes. Defaults to false. * Only applies when barcodeDetection is true. */ barcodeHighlight?: boolean; /** * Enable object detection (business card) on start. Defaults to false. * When enabled, the camera will automatically detect business cards and emit 'rectangleDetected' events. */ objectDetection?: boolean; /** * Whether to show the highlight overlay for detected business cards. Defaults to true. * Only applies when objectDetection is true. */ objectHighlight?: boolean; /** * Minimum interval in seconds between consecutive 'rectangleDetected' events. * Only applies when objectDetection is true. * Defaults to 0 (no throttling beyond initial stability check). */ rectangleEmitIntervalSeconds?: number; debounceTimeInMilli?: number; /** * Optional regex pattern to filter scanned barcodes. * If provided, only barcodes matching this pattern will be reported. */ regex?: string; /** * Optional regex flags (e.g., 'i' for case-insensitive, 'm' for multiline). */ regexFlags?: string; }</code>
262
266
 
263
267
 
264
268
  #### CapturePhotoOptions
@@ -293,7 +297,7 @@ Set the camera zoom level.
293
297
 
294
298
  #### ObjectDetectionOptions
295
299
 
296
- <code>{ /** * Detection types to enable. Only 'businessCard' is supported. * For barcode detection, use enableBarcodeDetection() instead. */ types: ('businessCard')[], /** * Optional padding ratio to apply around detected rectangles when cropping. * Value must be between 0 and 1, where: * - 0 = no padding * - 1 = 100% padding (not recommended) * Default is 0.01 (1%) if not specified. */ paddingRatio?: number, /** * Whether to show the highlight overlay for detected business cards. * Defaults to true. */ showHighlight?: boolean }</code>
300
+ <code>{ /** * Whether to show the highlight overlay for detected business cards. * Defaults to true. */ showHighlight?: boolean, /** * Minimum interval in seconds between consecutive 'rectangleDetected' events. * After an event is emitted, no new events will be emitted until this interval passes. * Set to 0 to emit events as soon as stability is detected. * Defaults to 0 (no throttling beyond initial stability check). */ emitIntervalSeconds?: number }</code>
297
301
 
298
302
 
299
303
  #### BarcodeDetectionOptions
@@ -140,6 +140,9 @@ public class CapacitorScannerPlugin extends Plugin {
140
140
  private long lastRectangleDetectionTime = 0; // Tracks when we last had a valid rectangle detection
141
141
  private int processingFrequency = 10; // Default: 10 rectangle detections per second
142
142
 
143
+ // Configurable interval between rectangle detection event emissions (in milliseconds)
144
+ private long rectangleEmitIntervalMs = 0; // Default: 0 (no throttling)
145
+
143
146
  /**
144
147
  * Calculates the processing interval in milliseconds based on the desired
145
148
  * frequency per second.
@@ -212,6 +215,19 @@ public class CapacitorScannerPlugin extends Plugin {
212
215
  if (enableObjectHighlight) {
213
216
  enabledHighlightTypes.add("businessCard");
214
217
  }
218
+ // Read rectangleEmitIntervalSeconds if provided
219
+ if (call.getData().has("rectangleEmitIntervalSeconds")) {
220
+ try {
221
+ double intervalSeconds = call.getData().getDouble("rectangleEmitIntervalSeconds");
222
+ rectangleEmitIntervalMs = Math.max(0, (long) (intervalSeconds * 1000));
223
+ echo("Using custom rectangleEmitIntervalSeconds: " + intervalSeconds + "s (" + rectangleEmitIntervalMs + "ms)");
224
+ } catch (Exception e) {
225
+ echo("Error parsing rectangleEmitIntervalSeconds: " + e.getMessage() + ". Using default 0ms");
226
+ rectangleEmitIntervalMs = 0;
227
+ }
228
+ } else {
229
+ rectangleEmitIntervalMs = 0;
230
+ }
215
231
  }
216
232
 
217
233
  try {
@@ -867,10 +883,8 @@ public class CapacitorScannerPlugin extends Plugin {
867
883
  long currentTime = System.currentTimeMillis();
868
884
 
869
885
  if (!rectangles.isEmpty()) {
870
- // Only notify if 1 second has passed since last notification
871
- // 1 second interval
872
- long NOTIFICATION_INTERVAL_MS = 1000;
873
- if (currentTime - lastRectangleNotificationTime >= NOTIFICATION_INTERVAL_MS) {
886
+ // Only notify if the configured interval has passed since last notification
887
+ if (currentTime - lastRectangleNotificationTime >= rectangleEmitIntervalMs) {
874
888
  // Find the largest rectangle if multiple are detected
875
889
  Rectangle largestRectangle = null;
876
890
  float largestArea = 0;
@@ -1127,6 +1141,7 @@ public class CapacitorScannerPlugin extends Plugin {
1127
1141
  lastRectangleNotificationTime = 0;
1128
1142
  lastRectangleProcessingTime = 0;
1129
1143
  lastRectangleDetectionTime = 0;
1144
+ rectangleEmitIntervalMs = 0;
1130
1145
 
1131
1146
  // Clear detection histories and caches
1132
1147
  enabledDetectionTypes.clear();
@@ -1147,9 +1162,12 @@ public class CapacitorScannerPlugin extends Plugin {
1147
1162
  @PluginMethod
1148
1163
  public void enableObjectDetection(PluginCall call) {
1149
1164
  echo("enableObjectDetection");
1150
- JSArray types = call.getArray("types");
1151
- if (types == null || types.length() == 0) {
1152
- call.reject("No detection types specified");
1165
+
1166
+ // If object detection is already enabled, just return success
1167
+ if (enabledDetectionTypes.contains("businessCard")) {
1168
+ JSObject result = new JSObject();
1169
+ result.put("enabled", true);
1170
+ call.resolve(result);
1153
1171
  return;
1154
1172
  }
1155
1173
 
@@ -1172,27 +1190,25 @@ public class CapacitorScannerPlugin extends Plugin {
1172
1190
  // Read showHighlight option (defaults to true for businessCard)
1173
1191
  boolean showHighlight = call.getBoolean("showHighlight", true);
1174
1192
 
1175
- // Only accept "businessCard" type - barcode detection is handled separately
1176
- List<String> addedTypes = new ArrayList<>();
1177
- try {
1178
- for (int i = 0; i < types.length(); i++) {
1179
- String type = types.getString(i);
1180
- if ("businessCard".equals(type)) {
1181
- enabledDetectionTypes.add(type);
1182
- if (showHighlight) {
1183
- enabledHighlightTypes.add(type);
1184
- }
1185
- addedTypes.add(type);
1186
- }
1187
- }
1188
- } catch (Exception e) {
1189
- call.reject("Error processing types array.", e);
1190
- return;
1193
+ // Enable businessCard detection
1194
+ enabledDetectionTypes.add("businessCard");
1195
+ if (showHighlight) {
1196
+ enabledHighlightTypes.add("businessCard");
1191
1197
  }
1192
1198
 
1193
- if (addedTypes.isEmpty()) {
1194
- call.reject("No valid detection types provided. Only 'businessCard' is supported. Use enableBarcodeDetection() for barcode detection.");
1195
- return;
1199
+ // Read the optional emitIntervalSeconds parameter
1200
+ if (call.getData().has("emitIntervalSeconds")) {
1201
+ try {
1202
+ double intervalSeconds = call.getData().getDouble("emitIntervalSeconds");
1203
+ rectangleEmitIntervalMs = Math.max(0, (long) (intervalSeconds * 1000));
1204
+ echo("Using custom emitIntervalSeconds: " + intervalSeconds + "s (" + rectangleEmitIntervalMs + "ms)");
1205
+ } catch (Exception e) {
1206
+ echo("Error parsing emitIntervalSeconds: " + e.getMessage() + ". Using default 0ms");
1207
+ rectangleEmitIntervalMs = 0;
1208
+ }
1209
+ } else {
1210
+ // Reset to default if not specified
1211
+ rectangleEmitIntervalMs = 0;
1196
1212
  }
1197
1213
 
1198
1214
  // Read the optional paddingRatio parameter
@@ -1222,11 +1238,6 @@ public class CapacitorScannerPlugin extends Plugin {
1222
1238
 
1223
1239
  JSObject result = new JSObject();
1224
1240
  result.put("enabled", true);
1225
- try {
1226
- result.put("types", new JSArray(addedTypes));
1227
- } catch (Exception e) {
1228
- // this should not happen
1229
- }
1230
1241
 
1231
1242
  if (enabledHighlightTypes.contains("businessCard")) {
1232
1243
  getActivity().runOnUiThread(() -> {
@@ -1261,7 +1272,6 @@ public class CapacitorScannerPlugin extends Plugin {
1261
1272
 
1262
1273
  JSObject result = new JSObject();
1263
1274
  result.put("enabled", false);
1264
- result.put("types", new JSArray());
1265
1275
  call.resolve(result);
1266
1276
  }
1267
1277
 
package/dist/docs.json CHANGED
@@ -171,17 +171,22 @@
171
171
  },
172
172
  {
173
173
  "name": "enableObjectDetection",
174
- "signature": "(options: ObjectDetectionOptions) => any",
174
+ "signature": "(options?: ObjectDetectionOptions | undefined) => any",
175
175
  "parameters": [
176
176
  {
177
177
  "name": "options",
178
- "docs": "",
179
- "type": "ObjectDetectionOptions"
178
+ "docs": "- Optional configuration for object detection",
179
+ "type": "ObjectDetectionOptions | undefined"
180
180
  }
181
181
  ],
182
182
  "returns": "any",
183
- "tags": [],
184
- "docs": "",
183
+ "tags": [
184
+ {
185
+ "name": "param",
186
+ "text": "options - Optional configuration for object detection"
187
+ }
188
+ ],
189
+ "docs": "Enable object detection (business card). This will start detecting business cards.",
185
190
  "complexTypes": [
186
191
  "ObjectDetectionOptions"
187
192
  ],
@@ -193,7 +198,7 @@
193
198
  "parameters": [],
194
199
  "returns": "any",
195
200
  "tags": [],
196
- "docs": "",
201
+ "docs": "Disable object detection. This will stop detecting business cards.",
197
202
  "complexTypes": [],
198
203
  "slug": "disableobjectdetection"
199
204
  },
@@ -339,7 +344,7 @@
339
344
  "docs": "",
340
345
  "types": [
341
346
  {
342
- "text": "{\n /**\n * Barcode formats to detect when barcodeDetection is enabled.\n */\n formats?: BarcodeFormat[];\n /**\n * Camera direction to use. Defaults to 'BACK'.\n */\n cameraDirection?: 'BACK' | 'FRONT';\n /**\n * Enable barcode detection on start. Defaults to false.\n * When enabled, the camera will automatically detect barcodes and emit 'barcodeScanned' events.\n */\n barcodeDetection?: boolean;\n /**\n * Whether to show the highlight overlay for detected barcodes. Defaults to false.\n * Only applies when barcodeDetection is true.\n */\n barcodeHighlight?: boolean;\n /**\n * Enable object detection (business card) on start. Defaults to false.\n * When enabled, the camera will automatically detect business cards and emit 'rectangleDetected' events.\n */\n objectDetection?: boolean;\n /**\n * Whether to show the highlight overlay for detected business cards. Defaults to true.\n * Only applies when objectDetection is true.\n */\n objectHighlight?: boolean;\n debounceTimeInMilli?: number;\n /**\n * Optional regex pattern to filter scanned barcodes.\n * If provided, only barcodes matching this pattern will be reported.\n */\n regex?: string;\n /**\n * Optional regex flags (e.g., 'i' for case-insensitive, 'm' for multiline).\n */\n regexFlags?: string;\n}",
347
+ "text": "{\n /**\n * Barcode formats to detect when barcodeDetection is enabled.\n */\n formats?: BarcodeFormat[];\n /**\n * Camera direction to use. Defaults to 'BACK'.\n */\n cameraDirection?: 'BACK' | 'FRONT';\n /**\n * Enable barcode detection on start. Defaults to false.\n * When enabled, the camera will automatically detect barcodes and emit 'barcodeScanned' events.\n */\n barcodeDetection?: boolean;\n /**\n * Whether to show the highlight overlay for detected barcodes. Defaults to false.\n * Only applies when barcodeDetection is true.\n */\n barcodeHighlight?: boolean;\n /**\n * Enable object detection (business card) on start. Defaults to false.\n * When enabled, the camera will automatically detect business cards and emit 'rectangleDetected' events.\n */\n objectDetection?: boolean;\n /**\n * Whether to show the highlight overlay for detected business cards. Defaults to true.\n * Only applies when objectDetection is true.\n */\n objectHighlight?: boolean;\n /**\n * Minimum interval in seconds between consecutive 'rectangleDetected' events.\n * Only applies when objectDetection is true.\n * Defaults to 0 (no throttling beyond initial stability check).\n */\n rectangleEmitIntervalSeconds?: number;\n debounceTimeInMilli?: number;\n /**\n * Optional regex pattern to filter scanned barcodes.\n * If provided, only barcodes matching this pattern will be reported.\n */\n regex?: string;\n /**\n * Optional regex flags (e.g., 'i' for case-insensitive, 'm' for multiline).\n */\n regexFlags?: string;\n}",
343
348
  "complexTypes": [
344
349
  "BarcodeFormat"
345
350
  ]
@@ -418,7 +423,7 @@
418
423
  "docs": "",
419
424
  "types": [
420
425
  {
421
- "text": "{\n /**\n * Detection types to enable. Only 'businessCard' is supported.\n * For barcode detection, use enableBarcodeDetection() instead.\n */\n types: ('businessCard')[],\n /**\n * Optional padding ratio to apply around detected rectangles when cropping.\n * Value must be between 0 and 1, where:\n * - 0 = no padding\n * - 1 = 100% padding (not recommended)\n * Default is 0.01 (1%) if not specified.\n */\n paddingRatio?: number,\n /**\n * Whether to show the highlight overlay for detected business cards.\n * Defaults to true.\n */\n showHighlight?: boolean\n}",
426
+ "text": "{\n /**\n * Whether to show the highlight overlay for detected business cards.\n * Defaults to true.\n */\n showHighlight?: boolean,\n /**\n * Minimum interval in seconds between consecutive 'rectangleDetected' events.\n * After an event is emitted, no new events will be emitted until this interval passes.\n * Set to 0 to emit events as soon as stability is detected.\n * Defaults to 0 (no throttling beyond initial stability check).\n */\n emitIntervalSeconds?: number\n}",
422
427
  "complexTypes": []
423
428
  }
424
429
  ]
@@ -17,10 +17,18 @@ export interface CapacitorScannerPlugin {
17
17
  addListener(event: 'barcodeScanned', listenerFunc: (result: BarcodeScannedEvent) => void): Promise<void>;
18
18
  addListener(event: 'rectangleDetected', listenerFunc: (result: RectangleDetectedEvent) => void): Promise<void>;
19
19
  removeAllListeners(): Promise<void>;
20
- enableObjectDetection(options: ObjectDetectionOptions): Promise<void>;
20
+ /**
21
+ * Enable object detection (business card). This will start detecting business cards.
22
+ * @param options - Optional configuration for object detection
23
+ */
24
+ enableObjectDetection(options?: ObjectDetectionOptions): Promise<{
25
+ enabled: true;
26
+ }>;
27
+ /**
28
+ * Disable object detection. This will stop detecting business cards.
29
+ */
21
30
  disableObjectDetection(): Promise<{
22
31
  enabled: false;
23
- types: [];
24
32
  }>;
25
33
  /**
26
34
  * Enable barcode detection. This will start detecting barcodes.
@@ -49,24 +57,18 @@ export declare type BarcodeDetectionOptions = {
49
57
  showHighlight?: boolean;
50
58
  };
51
59
  export declare type ObjectDetectionOptions = {
52
- /**
53
- * Detection types to enable. Only 'businessCard' is supported.
54
- * For barcode detection, use enableBarcodeDetection() instead.
55
- */
56
- types: ('businessCard')[];
57
- /**
58
- * Optional padding ratio to apply around detected rectangles when cropping.
59
- * Value must be between 0 and 1, where:
60
- * - 0 = no padding
61
- * - 1 = 100% padding (not recommended)
62
- * Default is 0.01 (1%) if not specified.
63
- */
64
- paddingRatio?: number;
65
60
  /**
66
61
  * Whether to show the highlight overlay for detected business cards.
67
62
  * Defaults to true.
68
63
  */
69
64
  showHighlight?: boolean;
65
+ /**
66
+ * Minimum interval in seconds between consecutive 'rectangleDetected' events.
67
+ * After an event is emitted, no new events will be emitted until this interval passes.
68
+ * Set to 0 to emit events as soon as stability is detected.
69
+ * Defaults to 0 (no throttling beyond initial stability check).
70
+ */
71
+ emitIntervalSeconds?: number;
70
72
  };
71
73
  export declare type StartOptions = {
72
74
  /**
@@ -97,6 +99,12 @@ export declare type StartOptions = {
97
99
  * Only applies when objectDetection is true.
98
100
  */
99
101
  objectHighlight?: boolean;
102
+ /**
103
+ * Minimum interval in seconds between consecutive 'rectangleDetected' events.
104
+ * Only applies when objectDetection is true.
105
+ * Defaults to 0 (no throttling beyond initial stability check).
106
+ */
107
+ rectangleEmitIntervalSeconds?: number;
100
108
  debounceTimeInMilli?: number;
101
109
  /**
102
110
  * Optional regex pattern to filter scanned barcodes.
@@ -1 +1 @@
1
- {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AA4JA,MAAM,CAAN,IAAY,aAYX;AAZD,WAAY,aAAa;IACvB,gCAAe,CAAA;IACf,mCAAkB,CAAA;IAClB,mCAAkB,CAAA;IAClB,qCAAoB,CAAA;IACpB,2CAA0B,CAAA;IAC1B,+BAAc,CAAA;IACd,iCAAgB,CAAA;IAChB,gCAAe,CAAA;IACf,mCAAkB,CAAA;IAClB,mCAAkB,CAAA;IAClB,+BAAc,CAAA;AAChB,CAAC,EAZW,aAAa,KAAb,aAAa,QAYxB","sourcesContent":["export interface CapacitorScannerPlugin {\n /**\n * Start the camera preview with optional barcode and object detection.\n * @param options - Configuration options for the camera and detection\n */\n start(options?: StartOptions): Promise<void>;\n\n /**\n * Stop the camera preview and all detection.\n */\n stop(): Promise<void>;\n\n openSettings(): Promise<void>;\n\n capturePhoto(options?: CapturePhotoOptions): Promise<CapturePhotoResult>;\n\n checkPermissions(): Promise<PermissionsResult>;\n\n requestPermissions(): Promise<PermissionsResult>;\n\n flipCamera(): Promise<void>;\n\n toggleFlash(): Promise<FlashResult>;\n\n addListener(event: 'barcodeScanned', listenerFunc: (result: BarcodeScannedEvent) => void): Promise<void>;\n\n addListener(event: 'rectangleDetected', listenerFunc: (result: RectangleDetectedEvent) => void): Promise<void>;\n\n removeAllListeners(): Promise<void>;\n\n enableObjectDetection(options: ObjectDetectionOptions): Promise<void>;\n\n disableObjectDetection(): Promise<{ enabled: false, types: [] }>;\n\n /**\n * Enable barcode detection. This will start detecting barcodes.\n * @param options - Optional configuration for barcode detection\n */\n enableBarcodeDetection(options?: BarcodeDetectionOptions): Promise<{ enabled: true }>;\n\n /**\n * Disable barcode detection. This will stop detecting barcodes and clear cached barcodes.\n */\n disableBarcodeDetection(): Promise<{ enabled: false }>;\n\n /**\n * Set the camera zoom level.\n * @param options - The zoom options containing the level (1, 2, or 3)\n */\n zoom(options: ZoomOptions): Promise<ZoomResult>;\n}\n\nexport type BarcodeDetectionOptions = {\n /**\n * Whether to show the highlight overlay for detected barcodes.\n * Defaults to false.\n */\n showHighlight?: boolean;\n}\n\nexport type ObjectDetectionOptions = {\n /**\n * Detection types to enable. Only 'businessCard' is supported.\n * For barcode detection, use enableBarcodeDetection() instead.\n */\n types: ('businessCard')[],\n /**\n * Optional padding ratio to apply around detected rectangles when cropping.\n * Value must be between 0 and 1, where:\n * - 0 = no padding\n * - 1 = 100% padding (not recommended)\n * Default is 0.01 (1%) if not specified.\n */\n paddingRatio?: number,\n /**\n * Whether to show the highlight overlay for detected business cards.\n * Defaults to true.\n */\n showHighlight?: boolean\n}\n\nexport type StartOptions = {\n /**\n * Barcode formats to detect when barcodeDetection is enabled.\n */\n formats?: BarcodeFormat[];\n /**\n * Camera direction to use. Defaults to 'BACK'.\n */\n cameraDirection?: 'BACK' | 'FRONT';\n /**\n * Enable barcode detection on start. Defaults to false.\n * When enabled, the camera will automatically detect barcodes and emit 'barcodeScanned' events.\n */\n barcodeDetection?: boolean;\n /**\n * Whether to show the highlight overlay for detected barcodes. Defaults to false.\n * Only applies when barcodeDetection is true.\n */\n barcodeHighlight?: boolean;\n /**\n * Enable object detection (business card) on start. Defaults to false.\n * When enabled, the camera will automatically detect business cards and emit 'rectangleDetected' events.\n */\n objectDetection?: boolean;\n /**\n * Whether to show the highlight overlay for detected business cards. Defaults to true.\n * Only applies when objectDetection is true.\n */\n objectHighlight?: boolean;\n debounceTimeInMilli?: number;\n /**\n * Optional regex pattern to filter scanned barcodes.\n * If provided, only barcodes matching this pattern will be reported.\n */\n regex?: string;\n /**\n * Optional regex flags (e.g., 'i' for case-insensitive, 'm' for multiline).\n */\n regexFlags?: string;\n};\n\nexport type BarcodeScannedEvent = { scannedCode: string; format: string };\n\n\nexport type RectangleDetectedEvent = {\n detected: true\n};\n\nexport type CapturePhotoOptions = {\n /**\n * The desired quality of the captured image, expressed as a value between 0.0 (lowest quality, smallest file size)\n * and 1.0 (highest quality, largest file size). Defaults to 1.0.\n * This parameter directly influences the compression level of the resulting JPEG image.\n */\n qualityRatio?: number;\n};\n\nexport type PermissionsResult = { camera: 'prompt' | 'denied' | 'granted' };\n\nexport type CapturePhotoResult = { imageBase64: string };\n\nexport type FlashResult = { enabled: boolean };\n\nexport type ZoomOptions = {\n /**\n * The zoom level to set. Must be 1, 2, or 3.\n * - 1 = 1.0x (no zoom)\n * - 2 = 2.0x\n * - 3 = 3.0x\n */\n level: 1 | 2 | 3;\n};\n\nexport type ZoomResult = { level: number };\n\nexport enum BarcodeFormat {\n Aztec = 'AZTEC',\n Code39 = 'CODE_39',\n Code93 = 'CODE_93',\n Code128 = 'CODE_128',\n DataMatrix = 'DATA_MATRIX',\n Ean8 = 'EAN_8',\n Ean13 = 'EAN_13',\n Itf14 = 'ITF14',\n Pdf417 = 'PDF_417',\n QrCode = 'QR_CODE',\n UpcE = 'UPC_E',\n}\n\ndeclare global {\n interface PluginRegistry {\n QRScanner: CapacitorScannerPlugin;\n }\n}"]}
1
+ {"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":"AAmKA,MAAM,CAAN,IAAY,aAYX;AAZD,WAAY,aAAa;IACvB,gCAAe,CAAA;IACf,mCAAkB,CAAA;IAClB,mCAAkB,CAAA;IAClB,qCAAoB,CAAA;IACpB,2CAA0B,CAAA;IAC1B,+BAAc,CAAA;IACd,iCAAgB,CAAA;IAChB,gCAAe,CAAA;IACf,mCAAkB,CAAA;IAClB,mCAAkB,CAAA;IAClB,+BAAc,CAAA;AAChB,CAAC,EAZW,aAAa,KAAb,aAAa,QAYxB","sourcesContent":["export interface CapacitorScannerPlugin {\n /**\n * Start the camera preview with optional barcode and object detection.\n * @param options - Configuration options for the camera and detection\n */\n start(options?: StartOptions): Promise<void>;\n\n /**\n * Stop the camera preview and all detection.\n */\n stop(): Promise<void>;\n\n openSettings(): Promise<void>;\n\n capturePhoto(options?: CapturePhotoOptions): Promise<CapturePhotoResult>;\n\n checkPermissions(): Promise<PermissionsResult>;\n\n requestPermissions(): Promise<PermissionsResult>;\n\n flipCamera(): Promise<void>;\n\n toggleFlash(): Promise<FlashResult>;\n\n addListener(event: 'barcodeScanned', listenerFunc: (result: BarcodeScannedEvent) => void): Promise<void>;\n\n addListener(event: 'rectangleDetected', listenerFunc: (result: RectangleDetectedEvent) => void): Promise<void>;\n\n removeAllListeners(): Promise<void>;\n\n /**\n * Enable object detection (business card). This will start detecting business cards.\n * @param options - Optional configuration for object detection\n */\n enableObjectDetection(options?: ObjectDetectionOptions): Promise<{ enabled: true }>;\n\n /**\n * Disable object detection. This will stop detecting business cards.\n */\n disableObjectDetection(): Promise<{ enabled: false }>;\n\n /**\n * Enable barcode detection. This will start detecting barcodes.\n * @param options - Optional configuration for barcode detection\n */\n enableBarcodeDetection(options?: BarcodeDetectionOptions): Promise<{ enabled: true }>;\n\n /**\n * Disable barcode detection. This will stop detecting barcodes and clear cached barcodes.\n */\n disableBarcodeDetection(): Promise<{ enabled: false }>;\n\n /**\n * Set the camera zoom level.\n * @param options - The zoom options containing the level (1, 2, or 3)\n */\n zoom(options: ZoomOptions): Promise<ZoomResult>;\n}\n\nexport type BarcodeDetectionOptions = {\n /**\n * Whether to show the highlight overlay for detected barcodes.\n * Defaults to false.\n */\n showHighlight?: boolean;\n}\n\nexport type ObjectDetectionOptions = {\n /**\n * Whether to show the highlight overlay for detected business cards.\n * Defaults to true.\n */\n showHighlight?: boolean,\n /**\n * Minimum interval in seconds between consecutive 'rectangleDetected' events.\n * After an event is emitted, no new events will be emitted until this interval passes.\n * Set to 0 to emit events as soon as stability is detected.\n * Defaults to 0 (no throttling beyond initial stability check).\n */\n emitIntervalSeconds?: number\n}\n\nexport type StartOptions = {\n /**\n * Barcode formats to detect when barcodeDetection is enabled.\n */\n formats?: BarcodeFormat[];\n /**\n * Camera direction to use. Defaults to 'BACK'.\n */\n cameraDirection?: 'BACK' | 'FRONT';\n /**\n * Enable barcode detection on start. Defaults to false.\n * When enabled, the camera will automatically detect barcodes and emit 'barcodeScanned' events.\n */\n barcodeDetection?: boolean;\n /**\n * Whether to show the highlight overlay for detected barcodes. Defaults to false.\n * Only applies when barcodeDetection is true.\n */\n barcodeHighlight?: boolean;\n /**\n * Enable object detection (business card) on start. Defaults to false.\n * When enabled, the camera will automatically detect business cards and emit 'rectangleDetected' events.\n */\n objectDetection?: boolean;\n /**\n * Whether to show the highlight overlay for detected business cards. Defaults to true.\n * Only applies when objectDetection is true.\n */\n objectHighlight?: boolean;\n /**\n * Minimum interval in seconds between consecutive 'rectangleDetected' events.\n * Only applies when objectDetection is true.\n * Defaults to 0 (no throttling beyond initial stability check).\n */\n rectangleEmitIntervalSeconds?: number;\n debounceTimeInMilli?: number;\n /**\n * Optional regex pattern to filter scanned barcodes.\n * If provided, only barcodes matching this pattern will be reported.\n */\n regex?: string;\n /**\n * Optional regex flags (e.g., 'i' for case-insensitive, 'm' for multiline).\n */\n regexFlags?: string;\n};\n\nexport type BarcodeScannedEvent = { scannedCode: string; format: string };\n\n\nexport type RectangleDetectedEvent = {\n detected: true\n};\n\nexport type CapturePhotoOptions = {\n /**\n * The desired quality of the captured image, expressed as a value between 0.0 (lowest quality, smallest file size)\n * and 1.0 (highest quality, largest file size). Defaults to 1.0.\n * This parameter directly influences the compression level of the resulting JPEG image.\n */\n qualityRatio?: number;\n};\n\nexport type PermissionsResult = { camera: 'prompt' | 'denied' | 'granted' };\n\nexport type CapturePhotoResult = { imageBase64: string };\n\nexport type FlashResult = { enabled: boolean };\n\nexport type ZoomOptions = {\n /**\n * The zoom level to set. Must be 1, 2, or 3.\n * - 1 = 1.0x (no zoom)\n * - 2 = 2.0x\n * - 3 = 3.0x\n */\n level: 1 | 2 | 3;\n};\n\nexport type ZoomResult = { level: number };\n\nexport enum BarcodeFormat {\n Aztec = 'AZTEC',\n Code39 = 'CODE_39',\n Code93 = 'CODE_93',\n Code128 = 'CODE_128',\n DataMatrix = 'DATA_MATRIX',\n Ean8 = 'EAN_8',\n Ean13 = 'EAN_13',\n Itf14 = 'ITF14',\n Pdf417 = 'PDF_417',\n QrCode = 'QR_CODE',\n UpcE = 'UPC_E',\n}\n\ndeclare global {\n interface PluginRegistry {\n QRScanner: CapacitorScannerPlugin;\n }\n}"]}
@@ -76,20 +76,16 @@ public class CapacitorScannerPlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureMetad
76
76
  }()
77
77
 
78
78
  @objc func enableObjectDetection(_ call: CAPPluginCall) {
79
- guard let types = call.getArray("types", String.self) else {
80
- call.reject("Missing or invalid 'type' parameter. Expected array of strings.")
81
- return
82
- }
83
-
84
- // Only accept "businessCard" - barcode detection is handled separately
85
- let filteredTypes = types.filter { $0 == "businessCard" }
86
-
87
- if filteredTypes.isEmpty {
88
- call.reject("No valid detection types provided. Only 'businessCard' is supported. Use enableBarcodeDetection() for barcode detection.")
79
+ // If object detection is already enabled, just return success
80
+ if self.enabledDetectionTypes.contains("businessCard") {
81
+ call.resolve([
82
+ "enabled": true,
83
+ ])
89
84
  return
90
85
  }
91
86
 
92
87
  let showHighlight = call.getBool("showHighlight", true)
88
+ let emitIntervalSeconds = call.getDouble("emitIntervalSeconds") ?? 0
93
89
 
94
90
  DispatchQueue.main.async {
95
91
  self.enabledDetectionTypes.insert("businessCard")
@@ -100,15 +96,17 @@ public class CapacitorScannerPlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureMetad
100
96
  self.rectangleDetector?.delegate = self
101
97
  }
102
98
 
99
+ // Set the emit interval
100
+ self.rectangleDetector?.setEmitInterval(emitIntervalSeconds)
101
+
103
102
  if showHighlight {
104
103
  self.enabledHighlightTypes.insert("businessCard")
104
+ self.rectangleDetector?.isHighlightEnabled = true
105
105
  self.setupOverlayView()
106
- self.rectangleDetector?.enableHighlight()
107
106
  }
108
107
 
109
108
  call.resolve([
110
109
  "enabled": true,
111
- "types": filteredTypes,
112
110
  ])
113
111
  }
114
112
  }
@@ -124,14 +122,17 @@ public class CapacitorScannerPlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureMetad
124
122
 
125
123
  call.resolve([
126
124
  "enabled": false,
127
- "types": [],
128
125
  ])
129
126
  }
130
127
  }
131
128
 
132
129
  private func setupOverlayView() {
133
130
  guard let cameraView = self.cameraView,
134
- let previewLayer = self.previewLayer else { return }
131
+ let previewLayer = self.previewLayer else {
132
+ print("[CapacitorScanner] setupOverlayView: cameraView or previewLayer is nil")
133
+ return
134
+ }
135
+ print("[CapacitorScanner] setupOverlayView: setting up overlay")
135
136
 
136
137
  // Remove existing overlay if present
137
138
  self.overlayView?.removeFromSuperview()
@@ -432,6 +433,9 @@ public class CapacitorScannerPlugin: CAPPlugin, CAPBridgedPlugin, AVCaptureMetad
432
433
  if enableObjectHighlight {
433
434
  self.rectangleDetector?.isHighlightEnabled = true
434
435
  }
436
+ // Set emit interval if provided
437
+ let emitInterval = call.getDouble("rectangleEmitIntervalSeconds") ?? 0
438
+ self.rectangleDetector?.setEmitInterval(emitInterval)
435
439
  }
436
440
 
437
441
  // Handle Regex Filter
@@ -33,6 +33,9 @@ class RectangleDetector {
33
33
  private let stabilityThreshold: CGFloat = 0.2 // Max movement (normalized) to be considered stable
34
34
  private let stabilityDuration: TimeInterval = 0.8 // Seconds of stability before emitting event
35
35
 
36
+ /// Minimum interval between consecutive event emissions. Set via `setEmitInterval(_:)`.
37
+ private var emitIntervalSeconds: TimeInterval = 0
38
+
36
39
  // MARK: - State
37
40
 
38
41
  private(set) var lastDetectedRectangle: DetectedRectangle?
@@ -42,7 +45,7 @@ class RectangleDetector {
42
45
  // Stability tracking
43
46
  private var previousCorners: RectangleCorners?
44
47
  private var stabilityStartTime: Date?
45
- private var hasEmittedForCurrentStability: Bool = false
48
+ private var lastEmitTime: Date?
46
49
 
47
50
  private var smoother: RectangleSmoother?
48
51
  private weak var overlayParentLayer: CALayer?
@@ -70,6 +73,7 @@ class RectangleDetector {
70
73
 
71
74
  /// Configure the detector with overlay support
72
75
  func configure(overlayLayer: CALayer, previewLayer: AVCaptureVideoPreviewLayer) {
76
+ print("[RectangleDetector] configure called, isHighlightEnabled: \(isHighlightEnabled)")
73
77
  self.overlayParentLayer = overlayLayer
74
78
  self.previewLayer = previewLayer
75
79
 
@@ -91,6 +95,11 @@ class RectangleDetector {
91
95
  smoother = nil
92
96
  }
93
97
 
98
+ /// Set the minimum interval between consecutive event emissions
99
+ func setEmitInterval(_ seconds: TimeInterval) {
100
+ emitIntervalSeconds = max(0, seconds)
101
+ }
102
+
94
103
  /// Update the current pixel buffer for snapshot capture
95
104
  func updatePixelBuffer(_ pixelBuffer: CVPixelBuffer) {
96
105
  self.currentPixelBuffer = pixelBuffer
@@ -114,7 +123,7 @@ class RectangleDetector {
114
123
  currentPixelBuffer = nil
115
124
  previousCorners = nil
116
125
  stabilityStartTime = nil
117
- hasEmittedForCurrentStability = false
126
+ lastEmitTime = nil
118
127
  smoother?.clear()
119
128
  smoother = nil
120
129
  }
@@ -122,7 +131,11 @@ class RectangleDetector {
122
131
  // MARK: - Private Implementation
123
132
 
124
133
  private func setupSmoother() {
125
- guard let parentLayer = overlayParentLayer, smoother == nil else { return }
134
+ guard let parentLayer = overlayParentLayer, smoother == nil else {
135
+ print("[RectangleDetector] setupSmoother: skipped (parentLayer nil: \(overlayParentLayer == nil), smoother exists: \(smoother != nil))")
136
+ return
137
+ }
138
+ print("[RectangleDetector] setupSmoother: creating smoother")
126
139
  smoother = RectangleSmoother()
127
140
  smoother?.setup(in: parentLayer)
128
141
  }
@@ -191,14 +204,13 @@ class RectangleDetector {
191
204
  // MARK: - Stability Tracking
192
205
 
193
206
  private func updateStability(with corners: RectangleCorners) {
194
- print("[RectangleDetector] updateStability - hasPrevious: \(previousCorners != nil), timerActive: \(stabilityStartTime != nil), hasEmitted: \(hasEmittedForCurrentStability)")
207
+ print("[RectangleDetector] updateStability - hasPrevious: \(previousCorners != nil), timerActive: \(stabilityStartTime != nil)")
195
208
 
196
209
  // First detection - just store corners, don't start timer yet
197
210
  guard let previous = previousCorners else {
198
211
  print("[RectangleDetector] First detection - storing corners, no timer yet")
199
212
  previousCorners = corners
200
213
  stabilityStartTime = nil
201
- hasEmittedForCurrentStability = false
202
214
  return
203
215
  }
204
216
 
@@ -213,7 +225,6 @@ class RectangleDetector {
213
225
  if movement >= stabilityThreshold {
214
226
  print("[RectangleDetector] Too much movement (\(movement) >= \(stabilityThreshold)) - resetting timer")
215
227
  stabilityStartTime = nil
216
- hasEmittedForCurrentStability = false
217
228
  return
218
229
  }
219
230
 
@@ -231,9 +242,22 @@ class RectangleDetector {
231
242
  let elapsed = now.timeIntervalSince(stabilityStartTime!)
232
243
  print("[RectangleDetector] Stability elapsed: \(String(format: "%.2f", elapsed))s / \(stabilityDuration)s required")
233
244
 
234
- if elapsed >= stabilityDuration && !hasEmittedForCurrentStability {
245
+ // Need to be stable for the required duration before any emission
246
+ guard elapsed >= stabilityDuration else { return }
247
+
248
+ // Check if we can emit (either first time, or interval has passed)
249
+ let canEmit: Bool
250
+ if let lastEmit = lastEmitTime {
251
+ let timeSinceLastEmit = now.timeIntervalSince(lastEmit)
252
+ canEmit = timeSinceLastEmit >= emitIntervalSeconds
253
+ print("[RectangleDetector] Time since last emit: \(String(format: "%.2f", timeSinceLastEmit))s, interval: \(emitIntervalSeconds)s")
254
+ } else {
255
+ canEmit = true
256
+ }
257
+
258
+ if canEmit {
235
259
  print("[RectangleDetector] STABLE for \(elapsed)s - emitting event")
236
- hasEmittedForCurrentStability = true
260
+ lastEmitTime = now
237
261
  delegate?.rectangleDetector(self, didDetect: corners)
238
262
  }
239
263
  }
@@ -244,7 +268,6 @@ class RectangleDetector {
244
268
  print("[RectangleDetector] No detection - resetting stability timer")
245
269
  }
246
270
  stabilityStartTime = nil
247
- hasEmittedForCurrentStability = false
248
271
  previousCorners = nil
249
272
  }
250
273
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@scr2em/capacitor-scanner",
3
- "version": "6.0.24",
3
+ "version": "6.0.26",
4
4
  "description": "scan codes",
5
5
  "main": "dist/plugin.cjs.js",
6
6
  "module": "dist/esm/index.js",