@@ -57,41 +57,54 @@ export class BarcodeDetectorPolyfill {
5757 * Scans an image for barcodes and returns a {@link Promise} for the result.
5858 *
5959 * @param {ImageBitmapSource } source the image to be scanned
60- * @returns {Promise<Array<DetectedBarcode>> } the scan result as described for {@link BarcodeDetector}
60+ * @returns {Promise<Array<DetectedBarcode>> } the scan result as described for {@link BarcodeDetector},
61+ * or a rejected {@link Promise} containing the error
62+ * @throws {TypeError } if the argument is not an {@link ImageBitmapSource}
6163 */
6264 // TODO Enable cache for video source, disable for others unless overridden in zbarConfig
6365 detect ( source : ImageBitmapSource ) : Promise < Array < DetectedBarcode > > {
66+ // Assert the argument type
67+ if ( ! BarcodeDetectorPolyfill . isImageBitmapSource ( source ) ) {
68+ throw new TypeError ( 'BarcodeDetector.detect() argument is not an ImageBitmapSource' )
69+ }
70+
6471 // Return an empty array immediately if the source is an object with any zero dimension,
6572 // see https://wicg.github.io/shape-detection-api/#image-sources-for-detection
6673 const intrinsic = BarcodeDetectorPolyfill . intrinsicDimensions ( source )
6774 if ( ( intrinsic . width === 0 ) || ( intrinsic . height === 0 ) ) {
6875 return Promise . resolve ( [ ] )
6976
7077 } else {
71- return Promise
72- . all ( [
73- this . toImageData ( source ) ,
74- this . getScanner ( )
75- ] )
76-
77- . then ( fulfilled => {
78- const
79- imageData : ImageData = fulfilled [ 0 ] ,
80- scanner : ZBarScanner = fulfilled [ 1 ] ;
81-
82- // Configure the image cache if so requested
83- if ( typeof this . zbarConfig . enableCache !== 'undefined' ) {
84- scanner . enableCache ( this . zbarConfig . enableCache )
85- }
86-
87- return scanRGBABuffer ( imageData . data , imageData . width , imageData . height , scanner )
88- } )
89-
90- . then ( symbols => {
91- return symbols . map ( symbol =>
92- this . toBarcodeDetectorResult ( symbol )
93- )
94- } )
78+ try {
79+ return Promise
80+ . all ( [
81+ this . toImageData ( source ) ,
82+ this . getScanner ( )
83+ ] )
84+
85+ . then ( fulfilled => {
86+ const
87+ imageData : ImageData = fulfilled [ 0 ] ,
88+ scanner : ZBarScanner = fulfilled [ 1 ] ;
89+
90+ // Configure the image cache if so requested
91+ if ( typeof this . zbarConfig . enableCache !== 'undefined' ) {
92+ scanner . enableCache ( this . zbarConfig . enableCache )
93+ }
94+
95+ return scanRGBABuffer ( imageData . data , imageData . width , imageData . height , scanner )
96+ } )
97+
98+ . then ( symbols => {
99+ return symbols . map ( symbol =>
100+ this . toBarcodeDetectorResult ( symbol )
101+ )
102+ } )
103+
104+ } catch ( error ) {
105+ // #8: return a rejected Promise if an exception occurred
106+ return Promise . reject ( error )
107+ }
95108 }
96109
97110 }
@@ -205,6 +218,24 @@ export class BarcodeDetectorPolyfill {
205218 }
206219
207220
221+ /**
222+ * Type guard for {@link external:ImageBitmapSource} and any
223+ * object having zero width or height.
224+ */
225+ private static isImageBitmapSource ( source : any ) : source is ImageBitmapSource {
226+ return ( source instanceof HTMLImageElement )
227+ || ( source instanceof HTMLVideoElement )
228+ || ( source instanceof HTMLCanvasElement )
229+ || ( source instanceof Blob )
230+ || ( source instanceof ImageData )
231+ || ( source instanceof CanvasRenderingContext2D )
232+ || ( source instanceof ImageBitmap )
233+ // Note the (lenient) equality operator
234+ || ( source && source . width == 0 )
235+ || ( source && source . height == 0 )
236+ }
237+
238+
208239 /**
209240 * Returns the intrinsic (as opposed to the rendered)
210241 * dimensions of an {@link external:ImageBitmapSource}.
0 commit comments