mebjas / mebjas.github.io

Repository for hosting my personal home page and blog.
https://blog.minhazav.dev
Apache License 2.0
13 stars 6 forks source link

HTML5 QR Code scanning with javascript - launched v1.0.1 | Minhaz’s Blog #3

Open utterances-bot opened 4 years ago

utterances-bot commented 4 years ago

HTML5 QR Code scanning with javascript - launched v1.0.1 | Minhaz’s Blog

In 2015 I had written an HTML5 based QR code scanning library as a jQuery extension. Recently I realised there was some consistent traffic on my Github Project and the demo page. As I dug more into what was going on and I was embarrassed to see the poor design and obsolete support to the latest HTML APIs around Camera. I recently fixed some of the issues and refactored the javascript library that is now independent of jQuery and supports Promise based APIs. In this article I’ll explain how to use the new version of the library, some changes and reasons for them and existing issues and plan to fix them.

https://blog.minhazav.dev/HTML5-QR-Code-scanning-launched-v1.0.1/

mirkoprog commented 4 years ago

with android mobile browser not found any camera, work only from pc windows, but if i open your demo its also work from mobile. please help me

mebjas commented 4 years ago

with android mobile browser not found any camera, work only from pc windows, but if i open your demo its also work from mobile. please help me

@mirkoprog - I'd recommend creating an issue at mebjas/html5-qrcode/issues with more details on browser, OS - where it works, where it not works, if you have error logs add that too and if there are screenshots that would be helpful too.

Happy to look into it.

ziobit commented 4 years ago

I have the exact same problem but anyway, all your links on the top page points to a 404 :)

Apr 4, 2020 • html javascript jquery qrcode camera promise

Demo works, trying to integrate it, when no syntax errors in the console, I get "Unable to query any cameras. Reason: unable to query supported devices." but the same browser, same session, if I open the demo, it works

mebjas commented 4 years ago

@ziobit

I have the exact same problem but anyway, all your links on the top page points to a 404 :)

Can you point which links don't work? I will fix them.

Demo works, trying to integrate it, when no syntax errors in the console, I get "Unable to query any cameras. Reason: unable to query supported devices." but the same browser, same session, if I open the demo, it works

Can you point me to how you are using it, maybe I can spot the issue.

mirkoprog commented 4 years ago

i have open a issue: https://github.com/mebjas/html5-qrcode/issues/25 there you can find my code

ziobit commented 4 years ago

(1) Regarding the 404, it's totally not important and not high priority for anybody, but just check the source code here:

html javascript jquery qrcode camera promise

All those links href are invalid and point to a 404.

(2) Small typo: in all the examples, you wrote "Start scaning", with a missing "n" :)

(3) Regarding my main issue, not working, if I simply copy/paste your html code, create the corresponding needed js files (in particular the qrcode) on my server, it simply cannot enumerate the cameras. I even copied the (useless, I had to read the js code to understand what they were doing :) :) :) anchorize and instapage js files, to no avail. No errors nor warnings on the browser console either. I put some printouts at the beginning/end of the ready event and it goes there and it goes out, so it's executing the initialization. But don't worry, it's working on your page, so of course it's something I am doing wrong, no need to worry :) It's just weird, basically I have a mirror of your page and resources and with no (apparent) error anywhere, still it does not work. PS: this morning I tried the new 1.0.5 version, same result. Working on your server, not enumerating the cameras on mine (both on pc and on mobile).

mebjas commented 4 years ago

@mirkoprog - let's take this further on the issue you created. @ziobit (1) Oh yes, this is a known problem - for some reason Github is not creating the pages for categories while Jekyll can do this for local version. I didn't get time to prioritise and fix it - it's Github + Jekyll blog issue.

(2) Fixed it, thanks for pointing.

(3) I see, it's related to http and https - I will see if this can be identified at the library level and thrown out as error so developers don't have to spend time figuring this out. For starters I'll update the README of the project. I just need to know if the file based scanning also don't work with http.

Also, I just noticed cloning the demo page is one way to try it, but IMO the demo code is very embarrassing, and I'll try to improve it asap.

keanwalker commented 4 years ago

hi, thanks for the completed QR code scanner. I tried just refer to the minified version, but could not load the back camera of phone. however, if I refer the both JS on your demo site, is working like charm. Perhaps you are missing something in the minified version?

mebjas commented 4 years ago

@keanwalker - Can you check your console logs to see if there are some errors?

I just tested using the minified js on the master branch and it seemed to work fine for me. Are you using a specific version of the package?

keanwalker commented 4 years ago

Hey, yes i got it from master branch. It returns "Error getting userMedia, error = NotReadableError: Could not start video source". and I force to set the cameras[i] to 1 to get the back camera. but using your js codes below, is working fine.

https://blog.minhazav.dev/assets/research/html5qrcode/qrcode.js https://blog.minhazav.dev/assets/research/html5qrcode/html5qrcode.js

mebjas commented 4 years ago

@keanwalker I see, I think it's related to an issue that was fixed today with pull/42. The issues are described in:

I merged the pull request today only, so master was little behind while I had already deployed the changes with fix to demo page.

If you are no longer able having the issue in the demo page it's kind of a good sign that the issues/38 might have got fixed as well with the PR#42. Would you mind adding a comment in issues/38 if you are no longer finding the issue either in the demo code or the minified/html5-qrcode.min.js in master now?

Once again, the minified code was updated just today in master and might no longer have this issue.

keanwalker commented 4 years ago

hi mebjas, yes working now. thanks. i will add comment in issues/38.

cuici commented 4 years ago

Hi, thanks for your work. Is-it possible to scan a barcode ?

mebjas commented 4 years ago

@cuici no not right now :(

But you could file a feature request here

cfcoderatcodefactory commented 4 years ago

Hi! Love this app! Questions: I would like to use the whole viewport and not a «standard» QR Code Scanner frame. Is it in any way possible to 1) get the location (coordinates) and size (width and height) of the QR-code inside the viewport/camera viewfinder?

mebjas commented 4 years ago

@cfcoderatcodefactory

I would like to use the whole viewport

For this you can call the start method without qrbox config. In that case it'd treat entire viewport for scanning.

const html5QrCode = new Html5Qrcode(/* element id */ "reader");
html5QrCode.start(
  cameraId, 
  {
    fps: 10,    // Optional frame per seconds for qr code scanning
    // <--  no qrbox set
  },
  qrCodeMessage => {
    // do something when code is read
  },
  errorMessage => {
    // parse error, ignore it.
  })
.catch(err => {
  // Start failed, handle it.
});

For the second part - please file a feature request at https://github.com/mebjas/html5-qrcode/issues I'll try to take it up from there - at the moment this functionality doesn't exist.

breizhim commented 4 years ago

I had to rename "devices" variable to "cameras" to make it works. "devices" is undefined (using your mini JS version).

cfcoderatcodefactory commented 4 years ago

Hi again, thanks for your prompt reply on my previous question. Amazing reponse time! A couple more: 1) I would like the scanned image (while developing/adapting your code to my needs) to be drawn to a canvas. How do I go about achieving that? 2) I have removed the 'qrbox' config from the start method. But where do I ensure that the video/scanning window is not larger than the viewport?

cfcoderatcodefactory commented 4 years ago

…PS: In my question 1 in previous comment: A visible canvas.

cfcoderatcodefactory commented 4 years ago

…aaand another PS to my question 1: When i QR Code is recognized I want to continue the «live feed» in the video window, but render a «still» image in the canvas.

mebjas commented 4 years ago

@cfcoderatcodefactory Could you share more on what is the final goal? As for visible canvas - as of now the tech works like this

There is a <video> element which renders the live feed. Based on scanning frequency it copies the video screenshot to a <canvas> which is hidden. If you want access to the canvas I think it'd not be possible from library as it abstracts that - but as a hack you can access the canvas from HTML DOM.

It'd always be created with <canvas id="qr-canvas" /> with JS you can access it.

Hope this helps. I dont understand the second question though.

mebjas commented 4 years ago

@breizhim could you share where the mistake is or send a pull request to fix that?

breizhim commented 4 years ago

@mebjas I had to rename "devices" variable by "cameras" in your example:

function listcamera() {
    Html5Qrcode.getCameras().then(cameras => {
           if (cameras && cameras.length) {
               var cameraId = cameras[0].id;

The devices variable was "undefined". By replace it to cameras it works.

BUT, I have another problem : the camera is working, I have the white field of scan in the middle, BUT it won't trigger when I show him a QR Code... (I still using your example). I have no JS error... the script can't find patterns.

mebjas commented 4 years ago

@breizhim The name of variable doesn't matter as far as you use the same variable inside the lambda, like

function listcamera() {
    Html5Qrcode.getCameras().then(randomName => {
           if (randomName && randomName.length) {
               var cameraId = randomName[0].id;

As for the QR code not scanning maybe you can share some video or provide description of the environment - like OS, device, browser etc

antheroo commented 4 years ago

Hi Minhaz, thanks for sharing this! Got it working in a jiff, but I encountered an error with the qrcode.decode() as I didn't realize that 'qrcode' was being used by this library and I had something else assigned as qrcode. Perhaps it would be helpful to mention that in the Readme :)

mebjas commented 4 years ago

@antheroo That's a great point - I think the library should abstract qrcode - would you mind raising an Issue or Feature request for this - https://github.com/mebjas/html5-qrcode/issues

antheroo commented 4 years ago

@antheroo That's a great point - I think the library should abstract qrcode - would you mind raising an Issue or Feature request for this - https://github.com/mebjas/html5-qrcode/issues

Done! https://github.com/mebjas/html5-qrcode/issues/51#issue-628156832

breizhim commented 4 years ago

@mebjas Ok I got it, but in your example you invoke first "cameras" then "devices", two different variables name :

Html5Qrcode.getCameras().then(cameras => {
  /**
   * devices would be an array of objects of type:
   * { id: "id", label: "label" }
   */
  if (devices && devices.length) {
    var cameraId = devices[0].id;
    // .. use this to start scanning.
  }

Well, for the detection issue, i past my code:

<html>
<head>
    <meta charset="UTF-8">
    <script type="text/javascript" src="qrcode/html5-qrcode.min.js"></script>
</head>
<body>
TEST
<button type="button" onclick="listcamera()">List cameras</button>
<div id="reader" width="600px"></div>
<script>
function listcamera() {
    Html5Qrcode.getCameras().then(cameras => {
        if (cameras && cameras.length) {
            cameraId = cameras[0].id;
            scan(cameraId);
        }

    }).catch(err => {
            // handle err 
                alert(err);
    });
}

function scan(cameraId) {
const html5Qr = new Html5Qrcode("reader");
html5Qr.start(
   cameraId, // retreived in the previous step.
   {
      fps: 10,    // sets the framerate to 10 frame per second 
      qrbox: 250  // sets only 250 X 250 region of viewfinder to
                  // scannable, rest shaded.
 },
 qrCodeMessage => {     // do something when code is read. For example:
     console.log(`QR Code detected: ${qrCodeMessage}`);
 },
 errorMessage => {     // parse error, ideally ignore it. For example:
     console.log(`QR Code no longer in front of camera.`);
 })
 .catch(err => {     // Start failed, handle it. For example, 
     console.log(`Unable to start scanning, error: ${err}`);
 });
}
</script>
</body>
</html>

--> The video works, but there is not detection nor JS error. I use Firefox 76.0.1, Win10.

BTW, thank you for your work ;)

breizhim commented 4 years ago

@mebjas Precision : I checked the javascript console. It stuck at "QR Code no longer in front of camera.".

mebjas commented 4 years ago

@breizhim

Ok I got it, but in your example you invoke first "cameras" then "devices", two different variables name :

fixed this example, thanks for pointing this out!

Your code example looks correct, one thing to try would be - once the code is running, open debugger, inspect element and go to <div> with id reader - you'll see a <canvas> which is hidden, mark it as not hidden from debugger and see if what you see in the canvas is same as what is shown inside the box in the video.

mebjas commented 4 years ago

@breizhim also worthwhile to check if https://blog.minhazav.dev/research/html5-qrcode is able to detect qr code in your browser and device

breizhim commented 4 years ago

@mebjas Well ... your demo works. But It seems that the canvas in the "reader" div stay white ... oO THe canvas on your demo works. What's the hell ^^

antheroo commented 4 years ago

@breizhim @mebjas I realized when the div is too large the detection doesn't work. Also, I don't think 'width' is a valid div html attribute. Try changing it to:

// change from:
<div id="reader" width="600px"></div>

// to:
<div id="reader" style="width:600px;"></div>
breizhim commented 4 years ago

@antheroo @mebjas Oooook, you're right :) It's why the video was displayed in full-screen instead of small window. It works. btw i don't understand how the canvas is linked to div technically. Thank you for the fix !

antheroo commented 4 years ago

@breizhim @mebjas I took a look at the source code and I believe there are a couple of bugs that caused this problem. Bugs which caused the wrong region of the video to be drawn to the canvas, due to wrong scaling.

Problem 1: In setupVideo videoWidth and videoHeight is (wrongly?) assigned clientWidth and clientHeight

// original
const videoWidth = videoElement.clientWidth;
const videoHeight = videoElement.clientHeight;

// correct?
const videoWidth = videoElement.videoWidth;
const videoHeight = videoElement.videoHeight;

Problem 2: In drawImage sx and sy also needs to be scaled accordingly

// Original
$this._context.drawImage(
  $this._videoElement,
  /* sx= */ $this._qrRegion.x,
  /* sy= */ $this._qrRegion.y,
  /* sWidth= */ sWidthOffset,
  /* sHeight= */ sHeightOffset,
  /* dx= */ 0,
  /* dy= */  0,
  /* dWidth= */ $this._qrRegion.width,
  /* dHeight= */ $this._qrRegion.height);

// Correction
  /* sx= */ $this._qrRegion.x * widthRatio,
  /* sy= */ $this._qrRegion.y * heightRatio,
mebjas commented 4 years ago

@antheroo @breizhim Thanks for raising this concern, let's see if this is a bug as the canvas region issue was supposed to be fixed with https://github.com/mebjas/html5-qrcode/pull/28

Let's take this discussion from here to the github project? Can one of you create the issue in https://github.com/mebjas/html5-qrcode/issues and tag the rest of us involved in this discussion and let's take it from there.

mebjas commented 4 years ago

Update

I have just implemented a full scanner on top of Html5Qrcode called Html5QrcodeScanner - it comes with default UI so you don't have to implement the user interface. You can use it like this:

[1] Create a container in HTML

<div id="qr-reader" style="width:500px"></div>

[2] Include the javascript

<script src="https://raw.githubusercontent.com/mebjas/html5-qrcode/master/minified/html5-qrcode.min.js"></script>

[3] Initialise the script

<script>
function onScanSuccess(qrCodeMessage) {
    // handle on success condition with the decoded message
}

var html5QrcodeScanner = new Html5QrcodeScanner(
    "qr-reader", { fps: 10, qrbox: 250 });
html5QrcodeScanner.render(onScanSuccess);
</script>

This is what is done in the latest update to demo - https://blog.minhazav.dev/research/html5-qrcode

You can download the latest js from Github master branch or from here - https://github.com/mebjas/html5-qrcode/releases/tag/v1.1.0

jfabaf commented 4 years ago

@mebjas same issue with Android and the last Chrome version. My code is:

<div style="width: 500px" id="reader"></div>

function onScanSuccess(qrCodeMessage) {
                // handle on success condition with the decoded message
                alert('Funciona!');
            }

            var html5QrcodeScanner = new Html5QrcodeScanner(
                "reader", {fps: 10, qrbox: 250});
            html5QrcodeScanner.render(onScanSuccess);

And the result is:

https://i.ibb.co/dDG5F2f/IMG-20200615-010155.jpg

JMLucas96 commented 3 years ago

Fantastic! Is there a way to translate or change default text? Like "Start Scanning"... Thank you!

imSurya-georgian commented 3 years ago

Hey, I have implemented this QR Code functionality. It is working in chrome, safari on mac. When i tried using it in mobile safari browser works fine but not in chrome. Chrome is giving us error when requesting permission... 'unable to query supported devices'. Can you help me

jfabaf commented 3 years ago

@mebjas same issue with Android and the last Chrome version. My code is:

<div style="width: 500px" id="reader"></div>

function onScanSuccess(qrCodeMessage) {
                // handle on success condition with the decoded message
                alert('Funciona!');
            }

            var html5QrcodeScanner = new Html5QrcodeScanner(
                "reader", {fps: 10, qrbox: 250});
            html5QrcodeScanner.render(onScanSuccess);

And the result is:

https://i.ibb.co/dDG5F2f/IMG-20200615-010155.jpg

The problem was the HTTP protocol. You need HTTPS in order to use the camera.

mebjas commented 3 years ago

@jfabaf Yes, it only works with https - it's a policy around browsers for camera access.

@JMLucas96

Fantastic! Is there a way to translate or change default text? Like "Start Scanning"... Thank you!

As of now there is no way to change the strings in the library but for your use case you can find and replace "Start Scanning" in minified/html5-qrcode.min.js as a work around

@imSurya-georgian

I have implemented this QR Code functionality. It is working in chrome, safari on mac. When i tried using it in mobile safari browser works fine but not in chrome. Chrome is giving us error when requesting permission... 'unable to query supported devices'. Can you help me

This is a problem with Chrome on IOS in fact webkit on IOS doesn't support camera access for any browser other than Safari. As a consequence chrome doesn't support camera access. The workaround for users is to use the file scanning approach - such that they can either a select a qr code image from file system or capture an image using the stock camera.

I am hoping Apple and Google resolve this issue asap, although it has been open for a while now.

siderisltd commented 3 years ago

@mebjas I've tried including both scripts: This one is from the library docs

This one I found in one of your comments under this issue

On IPhone X on Safari is running perfectly. On Android 8.0 and latest Chrome is not working at all. I am getting "unable to query supported devices" The behavior is the same from the IPhone and Chrome..

This is my code but the problem is in Html5Qrcode.getCameras as it's throwing... I am experiencing the same behavior with Chrome on your demo with the IPhone -> https://blog.minhazav.dev/research/html5-qrcode On my Android the demo is running well, but even with the end to end implementation locally it's not and I still get unable to query supported devices.

Admiration for your work. The documentation is perfect and it's usage is very simple, but the cross browser support is a bit misleading the people. It might be a good idea to say it's not supported until it is.

    Html5Qrcode.getCameras().then(cameras => {
        alert(JSON.stringify(cameras));
        if (cameras && cameras.length) {
            let backCamera = cameras.find(d => d.label.toLowerCase().indexOf('back') >= 0);
            if (backCamera) {
                //alert(backCamera.id);

                const html5QrCode = new Html5Qrcode("qr-reader");
                html5QrCode.start(
                    backCamera.id,
                    {
                        fps: 80,   
                        qrbox: 200 
                    },
                    qrCodeMessage => {
                        html5QrCode.stop().then(ignore => {
                            // QR Code scanning is stopped.
                        }).catch(err => {
                            // Stop failed, handle it.
                        });

                        window.location.href = qrCodeMessage;
                    },
                    errorMessage => {
                        // parse error, ignore it.
                    })
                    .catch(err => {
                        // Start failed, handle it.
                    });
            }
        }
    }).catch(err => {
        alert(err);
    });
cfcoderatcodefactory commented 3 years ago

Try: fps: 24 or fps: 10 or do not specify fps at all.

siderisltd commented 3 years ago

That's not related at all. The configuration is passed on later stage. Html5Qrcode.getCameras() is throwing an error before that. I tried the end to end with 10 and without but it's not working too..

siderisltd commented 3 years ago

@mebjas the problem is that my page was not accessed via https.. Maybe you should check that out. Even though I accessed it via https, I am getting "NotReadableError: Could not start video source on android 8.0"

lance-cfa commented 3 years ago

Is it possible to configure the camera options to only allow the back or front camera so that the user does not have to select a camera?

siderisltd commented 3 years ago

@lance-cfa yes - please take a look at my code above

        Html5Qrcode.getCameras().then(cameras => {
            $('#preview-container-ios').css('display', 'block');
            if (cameras && cameras.length) {
                let backCamera = cameras.find(d => d.label.toLowerCase().indexOf('back') >= 0);
mebjas commented 3 years ago

@lance-cfa @siderisltd

I have added this feature in latest version of the library (see changelog) - with this you can directly pass the facing mode you'd like to request

Link to demo: https://blog.minhazav.dev/research/h5q-direct (this is WIP, but shows how it works).

Released as v1.2.1: https://github.com/mebjas/html5-qrcode/releases/tag/V1.2.1 npm: https://www.npmjs.com/package/html5-qrcode

You can pass this as facingMode in Html5Qrcode class in place of the cameraId

const html5QrCode = new Html5Qrcode("#reader");
const qrCodeSuccessCallback = message => { /* handle success */ }
const config = { fps: 10, qrbox: 250 };

// If you want to prefer front camera
html5QrCode.start({ facingMode: "user" }, config, qrCodeSuccessCallback);

// If you want to prefer back camera
html5QrCode.start({ facingMode: "environment" }, config, qrCodeSuccessCallback);

// Select front camera or fail with `OverconstrainedError`.
html5QrCode.start({ facingMode: { exact: "user"} }, config, qrCodeSuccessCallback);

// Select back camera or fail with `OverconstrainedError`.
html5QrCode.start({ facingMode: { exact: "environment"} }, config, qrCodeSuccessCallback);

This is however not supported for Html5QrcodeScanner as I am still trying to collect requirements on how it'd be useful to everyone - if you have some opinions please add it to

https://github.com/mebjas/html5-qrcode/issues/65 where this issue is being tracked.

mebjas commented 3 years ago

@siderisltd

@mebjas the problem is that my page was not accessed via https.. Maybe you should check that out. Even though I accessed it via https, I am getting "NotReadableError: Could not start video source on android 8.0"

Yes this is a known requirement and mentioned in https://github.com/mebjas/html5-qrcode#start-scanning - but looks like it'd be useful if the library threw appropriate error at when trying it out so speed up debugging.

Would you mind filing a feature request for this (with some context) at https://github.com/mebjas/html5-qrcode/issues/new/choose - to help others?