ngx-scanner icon indicating copy to clipboard operation
ngx-scanner copied to clipboard

Detect qr code within certain rectangular area of camera

Open ajaxsys opened this issue 5 years ago • 32 comments

Is your feature request related to a problem? Please describe. Hi, it is difficult while scanning one of many qr codes in same page(e.g. https://goo.gl/LZ6Sx3).

Describe the solution you'd like Is it posible to detect qr code within certain rectangular area of camera(not the whole camara)? Image like: https://i.stack.imgur.com/lMxRq.jpg

Thank you.

ajaxsys avatar Aug 01 '18 06:08 ajaxsys

Not yet. 😞 Some folks has done it for the BrowserCodeReader in the library package, they implemented a method override where they crop the image stream before sending it to the decoder method. But here we didn't done anything like that yet.

odahcam avatar Aug 01 '18 11:08 odahcam

Looks that it's a nice idea that crop the image stream before sending it to the decoder method. could you please show the code of folk which had done this feature?

ajaxsys avatar Aug 01 '18 12:08 ajaxsys

I'll have to search for it, I'll post here ASAP, you're also welcome to the Gitter chat. 🙂

odahcam avatar Aug 01 '18 14:08 odahcam

Is there any reason for why BrowserCodeReader is re-implemented in ngx-scanner instead of just extended from zxing-js/library? In library, a protected drawImageOnCanvas method was created, so that it could be extended to allow for example custom cropping functionality to be added by extending it. But since ngx-scanner does not extend BrowserCodeReader from library, we lose that feature here. :/

linusbrolin avatar Aug 29 '18 11:08 linusbrolin

Hey @linusbrolin at the time we created this little guy here, the library's class wasn't that good, so @werthdavid had to reimplement it to create a nicer experience on this package. I'm curerntly working on improve that BrowserCodeReader with the code we developed here, it'll take a few days but we will get there and then we can just use that class.

odahcam avatar Aug 29 '18 12:08 odahcam

@ajaxsys Hello,Have you solved this problem? I am also full screen scan now. I want to sweep the code collection area only in the center part. Thank you.

bestbelief avatar Sep 05 '18 09:09 bestbelief

@bestbelief I fix this problem by create a dynamic canvas(crop a square area) for BinaryBitmap. It's not the best way, but works.

Sample code(a bit dirty):

https://gist.github.com/ajaxsys/cf18c534e1455c737278c74770edc9be

ajaxsys avatar Sep 07 '18 13:09 ajaxsys

@ajaxsys Thank you for your reply, though the link you gave is not open.

bestbelief avatar Sep 10 '18 07:09 bestbelief

@bestbelief It's a public gist...

ajaxsys avatar Sep 13 '18 02:09 ajaxsys

OK, I think it's possible to restrict access elsewhere. Thank you for your reply.

bestbelief avatar Sep 13 '18 13:09 bestbelief

The link is working fine here, it may be a problem with your network/proxy or something like that.

odahcam avatar Sep 13 '18 17:09 odahcam

I think so. It seems that I need to find out why.

bestbelief avatar Sep 14 '18 01:09 bestbelief

Good luck then. 🙂

odahcam avatar Sep 14 '18 14:09 odahcam

As I said in #139:

We could implement some injection token for the MultiformatCodeReader so you could implement your own code reader (maybe by extending the default) and adding the custom crop functionality before the decode.

The base library and the crop as implemented there: https://github.com/zxing-js/library/issues/39

odahcam avatar Oct 10 '18 16:10 odahcam

@ajaxsys how can I use you patch, do you have a demo ?

zhanglongchina avatar Oct 13 '19 00:10 zhanglongchina

There's no patch, he just overwritten one method from the library, as his gist shows.

odahcam avatar Oct 13 '19 20:10 odahcam

Since #172 is marked as duplicare if this bug. So here's this issue we ran into.

--snip-- I ran into this same issue with multiple barcodes & am in the same boat as you guys are. (This snapshot use barcode "code39" for vin scanning)

20190313_171712 -snip--

fletchsod-developer avatar Oct 13 '19 21:10 fletchsod-developer

Since some of you guys are having some trouble to access the workaround gist by @ajaxsys, I'm pasting it here:

// Patch for node_modules/@zxing/ngx-scanner/esm5/zxing-ngx-scanner.js
BrowserCodeReader.prototype.createBinaryBitmap = function (mediaElement) {
        if (undefined === this.canvasElementContext) {
            this.prepareCaptureCanvas();
        }
        this.canvasElementContext.drawImage(mediaElement, 0, 0);
        // FIXME byHo
        // var luminanceSource = new HTMLCanvasElementLuminanceSource(this.canvasElement);
        // var hybridBinarizer = new HybridBinarizer(luminanceSource);
        // return new BinaryBitmap(hybridBinarizer);
        
        const allWidth = this.canvasElement.width;
        const allHeight = this.canvasElement.height;
        const left = allWidth/4;
        const top = Math.min(allWidth, allHeight)/4;
        const squareSize = Math.min(allWidth, allHeight) / 2;
        // const crop = all.crop(left, top, squareSize, squareSize);

        var canvas1 = document.createElement("canvas");
        canvas1.width = squareSize;
        canvas1.height = squareSize;
        var ctx1 = canvas1.getContext("2d");
        ctx1.rect(0, 0, squareSize, squareSize);
        ctx1.fillStyle = 'white';
        ctx1.fill();
        // ctx1.putImageData(crop.binarizer.source, 0, 0);
        ctx1.putImageData(
            this.canvasElementContext.getImageData(left, top, squareSize, squareSize), 
            0, 0);

        $('.dstImg').attr('src', canvas1.toDataURL("image/png"));
        // $('.dstImg').each((i, img) => 
        //     this.canvasElementContext.drawImage(img, left, top, squareSize, squareSize, 0, 0, squareSize, squareSize));

        var luminanceSource = new HTMLCanvasElementLuminanceSource(canvas1);
        var hybridBinarizer = new HybridBinarizer(luminanceSource);

        // hybridBinarizer.source.buffer = crop.binarizer.source;
        // hybridBinarizer.source.width = squareSize;
        // hybridBinarizer.source.height = squareSize;
        return new BinaryBitmap(hybridBinarizer);
    };

odahcam avatar Oct 13 '19 21:10 odahcam

One problem is we're using NPM. It's not like we can patch it this way. The cloud web app we're using is too integrated & it get deployed over to 4 stages of environment to the servers, gate, dev, demo & production

fletchsod-developer avatar Oct 13 '19 22:10 fletchsod-developer

look forward to the new release which will add the feature

zhanglongchina avatar Oct 14 '19 03:10 zhanglongchina

@fletchsod-developer you can patch this way even with NPM. It is not a clean way to solve the issue, but you can use it 'till there's a better way of doing it.

odahcam avatar Oct 14 '19 16:10 odahcam

Hello @odahcam! Where should the workaround go? Do we have to edit the ngx-scanner code in node_modules? Thanks!

pedromsfernandes avatar Apr 18 '20 19:04 pedromsfernandes

Do we have to edit the ngx-scanner code in node_modules?

No.

Where should the workaround go?

Place it in the component .ts file where you gonna use <zxing-scanner> component.

odahcam avatar Apr 19 '20 05:04 odahcam

Place it in the component .ts file where you gonna use <zxing-scanner> component.

How? Where inside the class or outside? ts is complaining that it lacks a lot of classes, etc.

takashi1kun avatar Jul 07 '20 11:07 takashi1kun

Place it in the component .ts file where you gonna use <zxing-scanner> component.

How? Where inside the class or outside? ts is complaining that it lacks a lot of classes, etc.

test.component.ts

import { BrowserCodeReader, HTMLCanvasElementLuminanceSource, HybridBinarizer, BinaryBitmap } from '@zxing/library';

BrowserCodeReader.prototype.createBinaryBitmap = function (mediaElement) {
  const captureCanvasContext = this.getCaptureCanvasContext(mediaElement);
  this.drawImageOnCanvas(captureCanvasContext, mediaElement);
  const captureCanvas = this.getCaptureCanvas(mediaElement);

  const allWidth = captureCanvas.width;
  const allHeight = captureCanvas.height;
  const squareSize = Math.min(allWidth, allHeight) / 2;
  const top = (allHeight - squareSize) / 2;
  const left = (allWidth - squareSize) / 2;

  document.getElementById('scan-area').style.width = `${squareSize}px`;
  document.getElementById('scan-area').style.height = `${squareSize}px`;

  const canvas = document.createElement('canvas');
  canvas.width = squareSize;
  canvas.height = squareSize;
  const ctx = canvas.getContext('2d');
  ctx.rect(0, 0, squareSize, squareSize);
  ctx.fillStyle = 'white';
  ctx.fill();

  ctx.putImageData(captureCanvasContext.getImageData(left, top, squareSize, squareSize), 0, 0);

  const luminanceSource = new HTMLCanvasElementLuminanceSource(canvas);
  const hybridBinarizer = new HybridBinarizer(luminanceSource);

  return new BinaryBitmap(hybridBinarizer);
};
@Component({
  selector: 'app-test',
  templateUrl: './test.component.html',
  styleUrls: ['./test.component.scss'],
})
export class TestComponent implements OnInit {
  currentDevice: MediaDeviceInfo = null;

  constructor() {

  }

  ngOnInit(): void {

  }

  onCodeResult(resultString: string) {
    console.log(resultString);
  }
}

test.component.html

<zxing-scanner [(device)]="currentDevice" (scanSuccess)="onCodeResult($event)"></zxing-scanner>
<div id="scan-area"></div>

test.component.scss

zxing-scanner::ng-deep video {
  position: fixed;
  right: 0;
  bottom: 0;
  width: 100%;
  height: 100%;
}

#scan-area {
  background-color: rgba(255, 255, 255, 0.25);
  border: 1px solid red;
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

lucaboy avatar Aug 23 '20 13:08 lucaboy

Trying to solve this problem as well in Angular 8. I attempted to use the workaround gist but it says that BrowserCodeReader and HTMLCanvasElementLuminanceSource are deprecated. I tried to fix the workaround by adding @zxing/browser but I couldn't get it to work. Please help!

developer-temple avatar Oct 22 '20 14:10 developer-temple

This package is not making use of the zxing/browser yet, so it won't work with that one now. Just ignore the deprecations for this workaround, it is not a clean solution anyways. To really solve this issue we will have to implement zoom and cropping controls in the zxing/browser so it can be used by this package in future versions.

odahcam avatar Oct 24 '20 21:10 odahcam

Any status update on the above ? I have been trying to get the scanner to work with a rectangle box eg using sample code (test.component.ts, test.component.scss and test.component.html). Am I missing something here ?

SgElite avatar May 18 '21 07:05 SgElite

@SgElite - If all else fail then try this similiar script at the very bottom on this link for example written by bburns at https://github.com/zxing-js/library/issues/39 . It should not be too hard to rewrite it in TypeScript. I will add another script example there shortly.

fletchsod-developer avatar May 18 '21 13:05 fletchsod-developer

@fletchsod-developer - Thanks for your help, appreciated. Looking forward to see the typescript example.

SgElite avatar May 29 '21 20:05 SgElite