1- import { type DetectedBarcode , type BarcodeFormat , BarcodeDetector } from 'barcode-detector/pure'
1+ import { type DetectedBarcode , type BarcodeFormat , BarcodeDetector , type BarcodeDetectorOptions } from 'barcode-detector/pure'
22import { eventOn } from './callforth'
33import { DropImageFetchError } from './errors'
44
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+ */
521let 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+ }
842}
943
1044type ScanHandler = ( _ : DetectedBarcode [ ] ) => void
@@ -28,7 +62,7 @@ export const keepScanning = async (
2862 }
2963) => {
3064 console . debug ( '[vue-qrcode-reader] start scanning' )
31- barcodeDetector = new BarcodeDetector ( { formats } )
65+ setScanningFormats ( formats )
3266
3367 const processFrame =
3468 ( state : { lastScanned : number ; contentBefore : string [ ] ; lastScanHadContent : boolean } ) =>
@@ -140,9 +174,12 @@ export const processFile = async (
140174 file : File ,
141175 formats : BarcodeFormat [ ] = [ 'qr_code' ]
142176) : 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 } )
146183
147184 return await barcodeDetector . detect ( file )
148185}
@@ -151,9 +188,12 @@ export const processUrl = async (
151188 url : string ,
152189 formats : BarcodeFormat [ ] = [ 'qr_code' ]
153190) : 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 } )
157197
158198 const image = await imageElementFromUrl ( url )
159199
0 commit comments