nimiq / qr-scanner

Lightweight Javascript QR Code Scanner
https://nimiq.github.io/qr-scanner/demo
MIT License
2.42k stars 526 forks source link

pause the scanner #136

Open Timer91 opened 2 years ago

Timer91 commented 2 years ago

Perhaps, I'm not thinking in the right way, but I need to make just one API call for each QR code I scan.
But when I scan one, the callback passed to the constructor is called many times.

Should I do this check by myself or is there a way to pause the scan?

peteevans1230 commented 2 years ago

qrScanner.pause()

Timer91 commented 2 years ago

@peteevans1230 thanks your answer.

I've tried this method and the following code works.

const
    elVideo = document.querySelector( "video" )
;

QrScanner
    .listCameras(true)
    .then( devices => {
        if ( devices && devices.length ) {
            const
                qrScanner = new QrScanner( elVideo, ( result ) => {
                    // `this` is equal to `Window`, not the instance of QrScanner.
                    console.log( this );

                    qrScanner.pause();
                } )
            ;

            qrScanner.setCamera( 'environment' );
            qrScanner.start();
        }
    } );

Note that this in the callback is not equal to the QrScanner instance. It would be great to be able to do this. It would allow not to declare the function at instantiation and access to our instance from inside.

Timer91 commented 2 years ago

Btw, is there a way to pause the QR code scanner without disabling the camera?

EDIT:

I've found that way:

qrScanner._active = !1;

It would be interesting to talk about it in documentation.

Timer91 commented 2 years ago

After several tests, it does not work with _active.

In the following example, qrScanner._active is set to true. But the scanner does not scan QR code anymore.

QrScanner
    .listCameras(true)
    .then( devices => {
        if ( devices && devices.length ) {
            const
                qrScanner = new QrScanner( elVideo, ( qrCodeResult ) => {
                    /* disable QrScanner */
                    qrScanner._active = !1;

                   const
                        requestOptions = {
                            method: "POST",
                            credentials: "include",
                            headers: myHeaders,
                            body: JSON.stringify( {} )
                        };
                    ;

                    fetch( `${API}/route/`, requestOptions )
                        .then( response => response.json() )
                        .then( result => {
                            console.log( result );
                            /* enable QrScanner */
                            qrScanner._active = !0;
                        } )
                        .catch( error => console.log( "error", error ) );
                } )
            ;

            qrScanner.setCamera( "environment" );
            qrScanner.start();
        }
    } );

Any idea?

Timer91 commented 2 years ago

@peteevans1230 : I've tried your snippet, but TypeError: qrScanner.resume is not a function. I've checked in the library, this function does not exist...

It works with qrScanner.start() instead of resume.

peteevans1230 commented 2 years ago

@Timer91 my bad. While i was working on figuring out a solution to the issues i was having with this lib. I actually switched to a different lib, https://github.com/mebjas/html5-qrcode. The code snippet above was actually referencing the other lib. Sorry for the confusion.

The one referenced above is, in my humble OP, is a little more user friendly and has the features that i needed.

danimoh commented 2 years ago

Hello, if you only want to scan a single frame, the regular way would be to call qrScanner.stop() or qrScanner.destroy() afterwards. However, do i read that correctly that you want the video stream to continue? I'd be interested to know what your usecase is.

For now, continuing the video stream is not supported via the public api, but I imagine, you could set qrScanner._scanFrame = () => {}; or qrScanner._maxScansPerSecond = 0;. I've not tested this though.

RuneSP commented 2 years ago

In my use-case, we are using the camera to scan several (~20-30) QR codes with about a minute between each scan. To prevent having to initialize the camera and scanner each scan, I'm currently just toggling the scanner visibility with CSS, thus providing a better user experience without delay. But the camera feed and scanning is of course still running in the background, which I imagine puts a drain on the battery when its used for half an hour.

So if possible I'd prefer to be able to pause both the feed from the camera and the processing, and resume when a new scan is required.

I dont know if the browser camera API allows quick pause / resume of the video feed, but I guess it should be quite easy to disable the QR code detection to save some processor usage (I dont know how big of an impact it would have though).

I tried using the pause() method, but when resuming using start(), it still takes 1-2 seconds to re-initialize.

RuneSP commented 2 years ago

After several tests, it does not work with _active.

In the following example, qrScanner._active is set to true. But the scanner does not scan QR code anymore.

QrScanner
    .listCameras(true)
    .then( devices => {
        if ( devices && devices.length ) {
            const
                qrScanner = new QrScanner( elVideo, ( qrCodeResult ) => {
                    /* disable QrScanner */
                    qrScanner._active = !1;

                   const
                        requestOptions = {
                            method: "POST",
                            credentials: "include",
                            headers: myHeaders,
                            body: JSON.stringify( {} )
                        };
                    ;

                    fetch( `${API}/route/`, requestOptions )
                        .then( response => response.json() )
                        .then( result => {
                            console.log( result );
                            /* enable QrScanner */
                            qrScanner._active = !0;
                        } )
                        .catch( error => console.log( "error", error ) );
                } )
            ;

            qrScanner.setCamera( "environment" );
            qrScanner.start();
        }
    } );

Any idea?

Toggling _active does work, but you have to manually call qrScanner._scanFrame() after setting _active = true, as _scanFrame is calling itself (and setting _active to false will cause it to return)

edit: also make sure to set _active = true before calling qrScanner.stop()