Wrong characters for Aztec decoder in `Decoder.MIXED_TABLE`
alexanderpopko opened this issue · 0 comments
Hi, and many thanks to all contributers for maintaining this library!
I encountered a bug when decoding Aztec codes. Will try to supply a fix and create a pull request.
Describe the bug
Decoding Aztec codes in some cases gives wrong results, i.e., '\x01' / '\x02' / '\x03' / '\x04' / '\x05' / '\x06' / '\x07' / '\x0b' / '\x1b' / '\x1c' / '\x1d' / '\x1e' / '\x1f' / '\x7f' get decoded to '\\1' / '\\2' / '\\3' / '\\4' / '\\5' / '\\6' / '\\7' / '\\13' / '\\33' / '\\34' / '\\35' / '\\36' / '\\37' / '\\177'.
To Reproduce
Run the following script and see the expected/received output. I ran it using:
- node: 20.14.0
- @zxing/library: 0.21.1
- sharp: 0.32.6
- typescript: 4.3.5
import {
AztecCodeReader,
AztecCodeWriter,
BarcodeFormat,
BinaryBitmap,
BitMatrix,
DecodeHintType,
HybridBinarizer,
RGBLuminanceSource,
ZXingStringEncoding,
} from '@zxing/library';
import sharp from 'sharp';
ZXingStringEncoding.customDecoder = (bytes) =>
Buffer.from(bytes).toString('latin1');
function getPixelArray(bits: BitMatrix): Uint8Array {
const width = bits.getWidth();
const height = bits.getHeight();
const colours: number[] = [];
for (let x = 0; x < width; x++) {
for (let y = 0; y < height; y++) {
colours.push(bits.get(x, y) ? 0 : 255);
}
}
return Uint8Array.from(colours);
}
async function getResizedImage(
pixels: Uint8Array,
sourceWidth: number,
sourceHeight: number,
targetWidth: number,
targetHeight: number
) {
return await sharp(Uint8Array.from(pixels), {
raw: {
width: sourceWidth,
height: sourceHeight,
channels: 1,
},
})
.toColourspace('b-w')
.resize({ width: targetWidth, height: targetHeight, kernel: 'nearest' })
.raw()
.toBuffer({ resolveWithObject: true });
}
function encodeImage(data: string): BitMatrix {
return new AztecCodeWriter().encode(data, BarcodeFormat.AZTEC, 0, 0);
}
async function decodeImage(bits: BitMatrix) {
// It seems to be necessary to increase the image size before decoding,
// otherwise Detector.getBullsEyeCorners will throw a NotFoundException.
const { data, info } = await getResizedImage(
getPixelArray(bits),
bits.getWidth(),
bits.getHeight(),
100,
100
);
const source = new RGBLuminanceSource(
Uint8ClampedArray.from(data),
info.width,
info.height
);
const binarizer = new HybridBinarizer(source);
const image = new BinaryBitmap(binarizer);
const hints = new Map([
[DecodeHintType.PURE_BARCODE, true],
[DecodeHintType.TRY_HARDER, true],
]);
return new AztecCodeReader().decode(image, hints).getText();
}
async function main() {
const input = '\x01\x02\x03\x04\x05\x06\x07\x0b\x1b\x1c\x1d\x1e\x1f\x7f';
const output = await decodeImage(encodeImage(input));
console.log('Expected:', Buffer.from(input, 'latin1').toString('hex'));
console.log('Received:', Buffer.from(output, 'latin1').toString('hex'));
}
main().then();Expected behavior
'\x01\x02\x03\x04\x05\x06\x07\x0b\x1b\x1c\x1d\x1e\x1f\x7f' gets decoded to '\x01\x02\x03\x04\x05\x06\x07\x0b\x1b\x1c\x1d\x1e\x1f\x7f'.
Desktop (please complete the following information):
- OS: Ubuntu
- Version: 22.04.4