zxing-js / library

Multi-format 1D/2D barcode image processing library, usable in JavaScript ecosystem.

Home Page:https://zxing-js.github.io/library/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Hacky solution for scanning colour-inverted QR codes

TomLBarden opened this issue · comments

Apologies if this isn't suitable for a feature request, I just wanted to make sure others could find this easily.

Mostly leaving this as a note for anyone else who stumbles across this in future. It seems later releases of this library have broken the suggestion in #135, but I was able to adapt it into the below. I am not confident that what I've got here is a suitable solution to this issue, but it anyone wants to adapt this into something PR-able (or give me directions on how to do so) please feel free!

This basic premise is that there are two scanners working off the same video stream simulatenously. That way you're not having to choose between scanning a regular or inverted video stream. This solution also keeps the stream shown to the user as the regular stream.

Custom BrowserMultiFormatReader Implementation

import { BrowserMultiFormatReader } from '@zxing/browser';
import { HTMLCanvasElementLuminanceSource } from '@zxing/browser/esm/common/HTMLCanvasElementLuminanceSource';
import { BinaryBitmap, HybridBinarizer, Result } from '@zxing/library';

/**
 * A custom implementation of BrowserMultiFormatReader which inverts the colours of the
 * media source before attempting to find and decode a QR code
 */
export class BrowserMultiFormatReaderInverse extends BrowserMultiFormatReader {
  static createBinaryBitmapFromCanvas(canvas) {
    const luminanceSource = new HTMLCanvasElementLuminanceSource(canvas);
    const invertedSource = luminanceSource.invert();
    const hybridBinarizer = new HybridBinarizer(invertedSource);
    return new BinaryBitmap(hybridBinarizer);
  }

  decodeFromCanvas(canvas: HTMLCanvasElement): Result {
    const binaryBitmap = BrowserMultiFormatReaderInverse.createBinaryBitmapFromCanvas(canvas);
    return this.decodeBitmap(binaryBitmap);
  }
}

Usage


// Properties in component
@ViewChild('scanner') scanner = new ZXingScannerComponent();
invertedCodeReader: BrowserMultiFormatReaderInverse = new BrowserMultiFormatReaderInverse();

// Call this after your ZXingScannerComponent instance has successfully found a camera
this.invertedCodeReader.decodeFromVideoElement(this.scanner.previewElemRef.nativeElement, function (output, x, controls) {
  if (output !== undefined) {
    controls.stop(); // Stop the inverted code reader from scanning
    // Do something with output.getText();
  }
}.bind(this));

I'm confident that this isn't a great solution and that I'm likely overlooking something simpler (I couldn't get this.invertedCodeReader.scan() to continually scan, which seems like it would have been a better approach), but this hack does work, at least for my use case.

Yeah it's been a looooong time I'm not using ZXing in my everyday coding workflow, but I can say that's pretty plausible, given the architecture of this lib some things are pretty verbose. The for-browser implementations usually needs a little more love to work well, anyhow I would say you should give a chance to zxing-js/browser repository, maybe there's something helpfull there. I'm happy to see my "hackability" goal is working well tho haha. Stay fine.

Stale issue message