diff --git a/src/browser/BrowserCodeReader.ts b/src/browser/BrowserCodeReader.ts index d9b495ba..b96c7469 100644 --- a/src/browser/BrowserCodeReader.ts +++ b/src/browser/BrowserCodeReader.ts @@ -934,14 +934,17 @@ export class BrowserCodeReader { mediaElement: HTMLVisualMediaElement ): BinaryBitmap { const ctx = this.getCaptureCanvasContext(mediaElement); - if(mediaElement instanceof HTMLVideoElement) { + // doing a scan with inverted colors on the second scan should only happen for video elements + let doAutoInvert = false; + if (mediaElement instanceof HTMLVideoElement) { this.drawFrameOnCanvas(mediaElement); + doAutoInvert = true; } else { this.drawImageOnCanvas(mediaElement); } const canvas = this.getCaptureCanvas(mediaElement); - const luminanceSource = new HTMLCanvasElementLuminanceSource(canvas); + const luminanceSource = new HTMLCanvasElementLuminanceSource(canvas, doAutoInvert); const hybridBinarizer = new HybridBinarizer(luminanceSource); return new BinaryBitmap(hybridBinarizer); diff --git a/src/browser/HTMLCanvasElementLuminanceSource.ts b/src/browser/HTMLCanvasElementLuminanceSource.ts index 99c6f45b..4695ae2c 100644 --- a/src/browser/HTMLCanvasElementLuminanceSource.ts +++ b/src/browser/HTMLCanvasElementLuminanceSource.ts @@ -10,74 +10,71 @@ export class HTMLCanvasElementLuminanceSource extends LuminanceSource { private buffer: Uint8ClampedArray; private static DEGREE_TO_RADIANS = Math.PI / 180; - private static FRAME_INDEX = true; + private static FRAME_INDEX = true; private tempCanvasElement: HTMLCanvasElement = null; - public constructor(private canvas: HTMLCanvasElement) { - super(canvas.width, canvas.height); - this.buffer = HTMLCanvasElementLuminanceSource.makeBufferFromCanvasImageData(canvas); + public constructor(private canvas: HTMLCanvasElement, doAutoInvert: boolean = false) { + super(canvas.width, canvas.height); + this.buffer = HTMLCanvasElementLuminanceSource.makeBufferFromCanvasImageData(canvas, doAutoInvert); } - private static makeBufferFromCanvasImageData(canvas: HTMLCanvasElement): Uint8ClampedArray { - const imageData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); - return HTMLCanvasElementLuminanceSource.toGrayscaleBuffer(imageData.data, canvas.width, canvas.height); + private static makeBufferFromCanvasImageData(canvas: HTMLCanvasElement, doAutoInvert: boolean = false): Uint8ClampedArray { + const imageData = canvas.getContext('2d').getImageData(0, 0, canvas.width, canvas.height); + return HTMLCanvasElementLuminanceSource.toGrayscaleBuffer(imageData.data, canvas.width, canvas.height, doAutoInvert); } - private static toGrayscaleBuffer(imageBuffer: Uint8ClampedArray, width: number, height: number): Uint8ClampedArray { - const grayscaleBuffer = new Uint8ClampedArray(width * height); - HTMLCanvasElementLuminanceSource.FRAME_INDEX = !HTMLCanvasElementLuminanceSource.FRAME_INDEX; - if(HTMLCanvasElementLuminanceSource.FRAME_INDEX) - { - for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) { - let gray; - const alpha = imageBuffer[i + 3]; - // The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent - // black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a - // barcode image. Force any such pixel to be white: - if (alpha === 0) { - gray = 0xFF; - } else { - const pixelR = imageBuffer[i]; - const pixelG = imageBuffer[i + 1]; - const pixelB = imageBuffer[i + 2]; - // .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC), - // (306*R) >> 10 is approximately equal to R*0.299, and so on. - // 0x200 >> 10 is 0.5, it implements rounding. - gray = (306 * pixelR + - 601 * pixelG + - 117 * pixelB + - 0x200) >> 10; - } - grayscaleBuffer[j] = gray; - } - } - else - { - for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) { - let gray; - const alpha = imageBuffer[i + 3]; - // The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent - // black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a - // barcode image. Force any such pixel to be white: - if (alpha === 0) { - gray = 0xFF; - } else { - const pixelR = imageBuffer[i]; - const pixelG = imageBuffer[i + 1]; - const pixelB = imageBuffer[i + 2]; - // .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC), - // (306*R) >> 10 is approximately equal to R*0.299, and so on. - // 0x200 >> 10 is 0.5, it implements rounding. - gray = (306 * pixelR + - 601 * pixelG + - 117 * pixelB + - 0x200) >> 10; - } - grayscaleBuffer[j] = 0xFF - gray; - } - } - return grayscaleBuffer; + private static toGrayscaleBuffer(imageBuffer: Uint8ClampedArray, width: number, height: number, doAutoInvert: boolean = false): Uint8ClampedArray { + const grayscaleBuffer = new Uint8ClampedArray(width * height); + HTMLCanvasElementLuminanceSource.FRAME_INDEX = !HTMLCanvasElementLuminanceSource.FRAME_INDEX; + if (HTMLCanvasElementLuminanceSource.FRAME_INDEX || !doAutoInvert) { + for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) { + let gray; + const alpha = imageBuffer[i + 3]; + // The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent + // black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a + // barcode image. Force any such pixel to be white: + if (alpha === 0) { + gray = 0xFF; + } else { + const pixelR = imageBuffer[i]; + const pixelG = imageBuffer[i + 1]; + const pixelB = imageBuffer[i + 2]; + // .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC), + // (306*R) >> 10 is approximately equal to R*0.299, and so on. + // 0x200 >> 10 is 0.5, it implements rounding. + gray = (306 * pixelR + + 601 * pixelG + + 117 * pixelB + + 0x200) >> 10; + } + grayscaleBuffer[j] = gray; + } + } else { + for (let i = 0, j = 0, length = imageBuffer.length; i < length; i += 4, j++) { + let gray; + const alpha = imageBuffer[i + 3]; + // The color of fully-transparent pixels is irrelevant. They are often, technically, fully-transparent + // black (0 alpha, and then 0 RGB). They are often used, of course as the "white" area in a + // barcode image. Force any such pixel to be white: + if (alpha === 0) { + gray = 0xFF; + } else { + const pixelR = imageBuffer[i]; + const pixelG = imageBuffer[i + 1]; + const pixelB = imageBuffer[i + 2]; + // .299R + 0.587G + 0.114B (YUV/YIQ for PAL and NTSC), + // (306*R) >> 10 is approximately equal to R*0.299, and so on. + // 0x200 >> 10 is 0.5, it implements rounding. + gray = (306 * pixelR + + 601 * pixelG + + 117 * pixelB + + 0x200) >> 10; + } + grayscaleBuffer[j] = 0xFF - gray; + } + } + return grayscaleBuffer; } public getRow(y: number /*int*/, row: Uint8ClampedArray): Uint8ClampedArray { @@ -167,4 +164,4 @@ export class HTMLCanvasElementLuminanceSource extends LuminanceSource { public invert(): LuminanceSource { return new InvertedLuminanceSource(this); } -} \ No newline at end of file +}