Skip to content

Commit

Permalink
Merge pull request #614 from zxing-js/bugfix/527-scan-fail
Browse files Browse the repository at this point in the history
#527 Unable to scan PDF_417 codes
  • Loading branch information
werthdavid authored Aug 21, 2024
2 parents f1c51a5 + c103ed1 commit fdeaca5
Show file tree
Hide file tree
Showing 2 changed files with 64 additions and 64 deletions.
7 changes: 5 additions & 2 deletions src/browser/BrowserCodeReader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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(<HTMLVideoElement>mediaElement);
doAutoInvert = true;
} else {
this.drawImageOnCanvas(<HTMLImageElement>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);
Expand Down
121 changes: 59 additions & 62 deletions src/browser/HTMLCanvasElementLuminanceSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -167,4 +164,4 @@ export class HTMLCanvasElementLuminanceSource extends LuminanceSource {
public invert(): LuminanceSource {
return new InvertedLuminanceSource(this);
}
}
}

0 comments on commit fdeaca5

Please sign in to comment.