Library: how to use for node?

Created on 27 Mar 2019  路  21Comments  路  Source: zxing-js/library

how to use for nodejs?

question

Most helpful comment

136

i used the jsqr.js library has no problem,but why zxing-js always show NotFoundException ?

Ok i have been struggling for a few hours now, but figured it out. The problem is that RGBLuminanceSource expects an array of 8 bit brightness values, or 32 bit color values (widthheight values), but most if not all image decoders in Node output widthheight*4 values (RGBA every 4 bytes).

to make this compatible we have to convert it to 8 bit brightness values. here a crude example that should work just like this. if not, don't hesitate to ask me!

const { MultiFormatReader, BarcodeFormat, DecodeHintType, RGBLuminanceSource, BinaryBitmap, HybridBinarizer } = require('@zxing/library/esm5');
const fs = require('fs');
const jpeg = require('jpeg-js');

const jpegData = fs.readFileSync('in3.jpg');
const rawImageData = jpeg.decode(jpegData);


const hints = new Map();
const formats = [BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX];

hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
hints.set(DecodeHintType.TRY_HARDER, true);

const reader = new MultiFormatReader();

reader.setHints(hints);



const len = rawImageData.width * rawImageData.height;

const luminancesUint8Array = new Uint8Array(len);

for(let i = 0; i < len; i++){
    luminancesUint8Array[i] = ((rawImageData.data[i*4]+rawImageData.data[i*4+1]*2+rawImageData.data[i*4+2]) / 4) & 0xFF;
}

const luminanceSource = new RGBLuminanceSource(luminancesUint8Array, rawImageData.width, rawImageData.height);

console.log(luminanceSource)

const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));


const decoded = reader.decode(binaryBitmap);

console.log(decoded)

All 21 comments

why it's show NotFoundException: No MultiFormat Readers were able to detect the code.

That error means that the library couldn't detect your code, it could be a bad input data or just a real bad code.

no,i can sure the qrcode image is no problem

this is my code

async deCodeFromUrl() {
        const hints = new Map();
        const formats = [BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX,BarcodeFormat.MAXICODE/*, ...*/];
        const CHARSET = 'utf-8';
        hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
        hints.set(DecodeHintType.CHARACTER_SET,CHARSET);
        hints.set(DecodeHintType.TRY_HARDER, true);
        hints.set(DecodeHintType.PURE_BARCODE, true);
        const reader = new MultiFormatReader();
        reader.setHints(hints);
        const response = await axios.get('https://upload.wikimedia.org/wikipedia/commons/5/5b/Qr-1.png', {
            responseType: 'arraybuffer'
        });
        const luminanceSource = new RGBLuminanceSource(new Uint8ClampedArray(response.data), 500, 500);
        const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));
        try {
            const text = reader.decode(binaryBitmap).getText();
            console.log(`text:${text}`);
        } catch (e) {
            console.error(e);
        }
    }

136

i used the jsqr.js library has no problem,but why zxing-js always show NotFoundException ?

Can you set up a demo?

async deCodeFromUrl() {
const hints = new Map();
const formats = [BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX,BarcodeFormat.MAXICODE/, .../];
const CHARSET = 'utf-8';
hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
hints.set(DecodeHintType.CHARACTER_SET,CHARSET);
hints.set(DecodeHintType.TRY_HARDER, true);
hints.set(DecodeHintType.PURE_BARCODE, true);
const reader = new MultiFormatReader();
reader.setHints(hints);
const response = await axios.get('https://upload.wikimedia.org/wikipedia/commons/5/5b/Qr-1.png', {
responseType: 'arraybuffer'
});
const luminanceSource = new RGBLuminanceSource(new Uint8ClampedArray(response.data), 220, 220);
const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));
try {
const text = reader.decode(binaryBitmap).getText();
console.log(text:${text});
} catch (e) {
console.error(e);
}
}

@odahcam

can you run this code for node.js and decode this qrcode image correct?

i have not look for in one of your 150+ tests, all examples in docs directory was run in browser,not for nodejs

136

i used the jsqr.js library has no problem,but why zxing-js always show NotFoundException ?

Ok i have been struggling for a few hours now, but figured it out. The problem is that RGBLuminanceSource expects an array of 8 bit brightness values, or 32 bit color values (widthheight values), but most if not all image decoders in Node output widthheight*4 values (RGBA every 4 bytes).

to make this compatible we have to convert it to 8 bit brightness values. here a crude example that should work just like this. if not, don't hesitate to ask me!

const { MultiFormatReader, BarcodeFormat, DecodeHintType, RGBLuminanceSource, BinaryBitmap, HybridBinarizer } = require('@zxing/library/esm5');
const fs = require('fs');
const jpeg = require('jpeg-js');

const jpegData = fs.readFileSync('in3.jpg');
const rawImageData = jpeg.decode(jpegData);


const hints = new Map();
const formats = [BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX];

hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
hints.set(DecodeHintType.TRY_HARDER, true);

const reader = new MultiFormatReader();

reader.setHints(hints);



const len = rawImageData.width * rawImageData.height;

const luminancesUint8Array = new Uint8Array(len);

for(let i = 0; i < len; i++){
    luminancesUint8Array[i] = ((rawImageData.data[i*4]+rawImageData.data[i*4+1]*2+rawImageData.data[i*4+2]) / 4) & 0xFF;
}

const luminanceSource = new RGBLuminanceSource(luminancesUint8Array, rawImageData.width, rawImageData.height);

console.log(luminanceSource)

const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));


const decoded = reader.decode(binaryBitmap);

console.log(decoded)

Thanks @SeanDylanGoff for the example code, you can also find more about Node usage in the tests, they're pure Node code using the Sharp library to handle image files.

@SeanDylanGoff I was able to make use of your example using Typescript/NodeJS after a couple minor change from using a Uint8Array to using a Uint8ClampedArray and the order of the RGBLuminanceSource constructor. Here's what I've got for decoding a base64 jpeg with a serialized object as the text.

This is with "@zxing/library": "^0.15.1"

import jpeg from "jpeg-js";
import { MultiFormatReader, BarcodeFormat, DecodeHintType, RGBLuminanceSource, BinaryBitmap, HybridBinarizer } from '@zxing/library/esm5';

async function scanQR(base64: string): Promise<any> {

  const buff = Buffer.from(base64.substr(23), 'base64');
  console.log("created buff");
  const dimensions = sizeOf(buff);

  const rawImageData = jpeg.decode(buff);

  const hints = new Map();
  const formats = [BarcodeFormat.QR_CODE, BarcodeFormat.DATA_MATRIX];

  hints.set(DecodeHintType.POSSIBLE_FORMATS, formats);
  hints.set(DecodeHintType.TRY_HARDER, true);

  const reader = new MultiFormatReader();

  reader.setHints(hints);

  const len = rawImageData.width * rawImageData.height;

  const luminancesUint8Array = new Uint8ClampedArray(len);

  for(let i = 0; i < len; i++){
    luminancesUint8Array[i] = ((rawImageData.data[i*4]+rawImageData.data[i*4+1]*2+rawImageData.data[i*4+2]) / 4) & 0xFF;
  }

  const luminanceSource = new RGBLuminanceSource(luminancesUint8Array, rawImageData.width, rawImageData.height);

  console.log(luminanceSource)

  const binaryBitmap = new BinaryBitmap(new HybridBinarizer(luminanceSource));


  const qrCode = reader.decode(binaryBitmap);

  console.log(qrCode);

  if (qrCode) {
    return JSON.parse(qrCode.getText());
  } else {
    console.error("failed to decode qr code.");
  }
}

Thanks for this great piece of code! I just edited it so it could be a function instead of a method.

FYI for anyone using the above code with typescript and tslint you will need to make the following change to prevent tslint build warnings:

Change this part

  for(let i = 0; i < len; i++){
    luminancesUint8Array[i] = ((rawImageData.data[i*4]+rawImageData.data[i*4+1]*2+rawImageData.data[i*4+2]) / 4) & 0xFF;
  }

to this

        for (let i = 0; i < len; i++) {
            // tslint:disable-next-line:no-bitwise
            luminancesUint8Array[i] = ((rawImageData.data[i * 4] + rawImageData.data[i * 4 + 1] * 2 + rawImageData.data[i * 4 + 2]) / 4) & 0xFF;
        }

i dont understand how gonna works with readFileSync in node js

You gonna read some file with readFileSync and then will get the result and apply the necessary logic to transform it in a valid image byte array, then wrap it in a Luminance Source and then pass it to the library inside a BinaryBitmap and get a decode attempt result. I don't record any written code that does that, but these are the basic steps.

Well, I don't quite understand this conversion from 4 to 8 bits.

const luminancesUint8Array = new Uint8Array(len);

for(let i = 0; i < len; i++){
    luminancesUint8Array[i] = ((rawImageData.data[i*4]+rawImageData.data[i*4+1]*2+rawImageData.data[i*4+2]) / 4) & 0xFF;
}

Is it not supposed to be *4 for the third index ?

for(let i = 0; i < len; i++){
    luminancesUint8Array[i] = ((rawImageData.data[i*4]+rawImageData.data[i*4+1]*2+rawImageData.data[i*4+2]*4) / 4) & 0xFF;
}

Edit: ignore the previous code since it will set the luminance with much higher values (255*7/4)

Sincerely, I don't know. I would have to read some content about this to tell you what I think. The first example you shared doesn't work?

Yes, it does (>90% detection). But I didn't understand the principle of converting color to luminance.
Based on this topic : https://stackoverflow.com/questions/596216/formula-to-determine-brightness-of-rgb-color
There are multiple formulas to achieve it (Luminance (standard for certain colour spaces): (0.2126R + 0.7152G + 0.0722*B))

I think that @SeanDylanGoff used something simpler that looks like this formula for faster calculations.

The formula worked for me since I'm working on grayscaled images [(R1+G2+B*1)/4]. Maybe it would be better to use this one for coloured images.

for(let i = 0; i < len; i++){
    luminancesUint8Array[i] = ((rawImageData.data[i*4]*2+rawImageData.data[i*4+1]*7+rawImageData.data[i*4+2]) / 10) & 0xFF;
}

Sorry if this is not the case.

That's in fact pretty clever. I never had the chance to go deeper in the luminances, but this is certainty something to look for as ImageCapture is getting more and more popular and for performance reasons we will have to create a luminance for it too for avoiding using canvas when decoding from stream tracks.

I have driver's license and there is more then one different type of barcode on card. but, I want to scan and decode only pdf417 barcode via video streaming in pure JavaScript. I added hints also to scan and decode only pdf417 barcode but it's not working properly for all card. I also attached my code. Anyone suggest me if any change need to be require in my code.

Related issues

Hopingocean picture Hopingocean  路  3Comments

majestic84 picture majestic84  路  8Comments

robbelroot picture robbelroot  路  6Comments

Mazecreator picture Mazecreator  路  10Comments

mc-suchecki picture mc-suchecki  路  4Comments