1
- import { type DetectedBarcode , type BarcodeFormat , BarcodeDetector } from 'barcode-detector/pure'
1
+ import { type DetectedBarcode , type BarcodeFormat , BarcodeDetector , type BarcodeDetectorOptions } from 'barcode-detector/pure'
2
2
import { eventOn } from './callforth'
3
3
import { DropImageFetchError } from './errors'
4
4
5
+ declare global {
6
+ interface Window {
7
+ BarcodeDetector ?: typeof BarcodeDetector
8
+ }
9
+ }
10
+
11
+ /**
12
+ * Singleton `BarcodeDetector` instance used by `QrcodeStream`. This is firtly to avoid
13
+ * the overhead of creating a new instances for scanning each frame. And secondly, the
14
+ * instances can seamlessly be replaced in the middle of the scanning process, if the
15
+ * `formats` prop of `QrcodeStream` is changed.
16
+ *
17
+ * This instance is not used by `QrcodeCapture` and `QrcodeDropZone`, because it may not
18
+ * have the right `formats` configured. For these components we create one-off `BarcodeDetector`
19
+ * instances because it does not happen so frequently anyway (see: `processFile`/`processUrl`).
20
+ */
5
21
let barcodeDetector : BarcodeDetector
6
- export const setScanningFormats = ( formats : BarcodeFormat [ ] ) => {
7
- barcodeDetector = new BarcodeDetector ( { formats } )
22
+
23
+ /**
24
+ * Seamlessly updates the set of used barcode formats during scanning.
25
+ */
26
+ export function setScanningFormats ( formats : BarcodeFormat [ ] ) {
27
+ // Only use the `BarcodeDetector` polyfill if the API is not supported natively.
28
+ //
29
+ // Note, that we can't just monkey patch the API on load, i.e.
30
+ //
31
+ // globalThis.BarcodeDetector ??= BarcodeDetector
32
+ //
33
+ // because that is not SSR compatible. If the polyfill is applied during SSR, then
34
+ // it's actually missing at runtime. Thus, we have to check the API support at runtime:
35
+ if ( window . BarcodeDetector === undefined ) {
36
+ console . debug ( '[vue-qrcode-reader] BarcodeDetector not available: will use polyfill.' )
37
+ barcodeDetector = new BarcodeDetector ( { formats } )
38
+ } else {
39
+ console . debug ( '[vue-qrcode-reader] BarcodeDetector available: will use native API.' )
40
+ barcodeDetector = new window . BarcodeDetector ( { formats } )
41
+ }
8
42
}
9
43
10
44
type ScanHandler = ( _ : DetectedBarcode [ ] ) => void
@@ -28,7 +62,7 @@ export const keepScanning = async (
28
62
}
29
63
) => {
30
64
console . debug ( '[vue-qrcode-reader] start scanning' )
31
- barcodeDetector = new BarcodeDetector ( { formats } )
65
+ setScanningFormats ( formats )
32
66
33
67
const processFrame =
34
68
( state : { lastScanned : number ; contentBefore : string [ ] ; lastScanHadContent : boolean } ) =>
@@ -140,9 +174,12 @@ export const processFile = async (
140
174
file : File ,
141
175
formats : BarcodeFormat [ ] = [ 'qr_code' ]
142
176
) : Promise < DetectedBarcode [ ] > => {
143
- const barcodeDetector = new BarcodeDetector ( {
144
- formats
145
- } )
177
+ // To scan files/urls we use one-off `BarcodeDetector` instnaces,
178
+ // since we don't scan as often as camera frames. Note, that we
179
+ // always use the polyfill. This is because (at the time of writing)
180
+ // some browser/OS combinations don't support `Blob`/`File` inputs
181
+ // into the `detect` function.
182
+ const barcodeDetector = new BarcodeDetector ( { formats } )
146
183
147
184
return await barcodeDetector . detect ( file )
148
185
}
@@ -151,9 +188,12 @@ export const processUrl = async (
151
188
url : string ,
152
189
formats : BarcodeFormat [ ] = [ 'qr_code' ]
153
190
) : Promise < DetectedBarcode [ ] > => {
154
- const barcodeDetector = new BarcodeDetector ( {
155
- formats
156
- } )
191
+ // To scan files/urls we use one-off `BarcodeDetector` instnaces,
192
+ // since we don't scan as often as camera frames. Note, that we
193
+ // always use the polyfill. This is because (at the time of writing)
194
+ // some browser/OS combinations don't support `Blob`/`File` inputs
195
+ // into the `detect` function.
196
+ const barcodeDetector = new BarcodeDetector ( { formats } )
157
197
158
198
const image = await imageElementFromUrl ( url )
159
199
0 commit comments