Skip to content

HTMLCanvasElementLuminanceSource.toGrayscaleBuffer() auto invert issues #641

Description

@Borgling

Describe the bug
When enabling TRY_HARDER I couldn't get horizontal scanning working. It would only work if the barcode was rotated 90 degrees (portrait). But disabling TRY_HARDER, it would go back to allowing me to scan horizontal barcodes again.

The issue is with HTMLCanvasElementLuminanceSource.toGrayscaleBuffer()

        static toGrayscaleBuffer(imageBuffer, width, height, doAutoInvert = false) {
            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;
        }

Which has the following line

HTMLCanvasElementLuminanceSource.FRAME_INDEX = !HTMLCanvasElementLuminanceSource.FRAME_INDEX;

Which makes the canvas capture invert every other frame ..

The issue is. If you enable TRY_HARDER, it does a second pass with a second decode. So the first try will be inverted, and the second try (by the TRY_HARDER flag) will not be inverted. This means the initial "normal" pass will always fail (as inverted), and the second rotated attempt by TRY_HARDER will always pass.

To Reproduce
Enable TRY_HARDER on a HTMLCanvasElement implementation

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions