instascan icon indicating copy to clipboard operation
instascan copied to clipboard

Support front/back-facing cameras

Open schmich opened this issue 7 years ago • 17 comments

  • Phone/mobile support
  • { video: { facingMode: "user" } }
  • { video: { facingMode: { exact: "environment" } } }
  • https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia

schmich avatar Jul 19 '16 09:07 schmich

Any updates on this? Do you need a PR? If yes, do you have any hints where to start and/or how instascan interface should behave?

robertfausk avatar Apr 03 '17 07:04 robertfausk

What do you think about passing constraints to Camera.getCameras() ?

getCameras implementation could try to getUserMedia with provided constraints and filter the camera that fulfill those constraints. see camera.js#L53

This could also be a way to fix #22, but then it would require to pass the resolution contraints to Camera contructor, to merge the resolution constraints with the default provided in start method. see camera.js#L20

If it seems ok to anyone, I'm willing to submit a PR ;)

adriengibrat avatar Jul 21 '17 21:07 adriengibrat

My workaround, until this fixed by allowing some king of custom Camera settings, is to set the first camera which contains "back" inside its name value:

if (cameras.length > 0) {
    var selectedCam = cameras[0];
    $.each(cameras, (i, c) => {
        if (c.name.indexOf('back') != -1) {
            selectedCam = c;
            return false;
        }
    });

    scanner.start(selectedCam);
} else {
    console.error('No cameras found.');
}

It always selects the rear camera.

clytras avatar Jul 28 '17 17:07 clytras

my end its working but when i try to use the rear camera it flip horizontally.. how to put it back on the usual position? thanks

souske avatar Aug 09 '17 11:08 souske

I am having an unusual problem. It doesn't matter which camera I start, it always show the front camera. I can clearly see both cameras on the array and I force to start the back camera, still, the script always start the front camera. Just downloaded the most recent version of iOS. Settings: iPhone 6s iOS 11 Safari.

Also not loading camera on Chrome and Firefox for same device/OS.

Any ideas?

Thanks

cbnt avatar Sep 13 '17 04:09 cbnt

I am having the same issue. Were you able to select the rear camera on IOS

Thanks Helen

HelenH avatar Sep 25 '17 00:09 HelenH

@cbnt @HelenH Did you solve this problem? For me I also see both cameras available but switching or preselecting to the back camera always ends in flipping back to the front camera :(

@schmich First of all thank you sooo much for this awesome project! :) Secondly, do you have any information on whether this is a common Iphone issue or how this can be fixed?

Note: Using iphone 7 with iOS 11

Smux avatar Oct 05 '17 18:10 Smux

Hi @Smux ,

Yes followed the steps in Issue #54

git clone [email protected]:schmich/instascan.git cd instascan/ npm install gulp-cli -g npm install gulp release cp dist/instascan.min.js /path/to/our/libraries/include/dir

Much thanks @schmich for this awesome project also.

HelenH avatar Oct 05 '17 22:10 HelenH

@HelenH @Smux

I fixed the issue using this fork: https://github.com/PallasKatze/instascan Still need to follow the steps in Issue #54 though

But it is working fine. Just a little issue with Android but I believe it is one specific version.

cbnt avatar Oct 05 '17 23:10 cbnt

Hi @cbnt, I want to try that too. But the minified js is that fork links to the same js as the original branch. I cannot find any minified js in the package. HOw could I do that? Is there anyone who can link one working js file? Thanks in advance.

I know this is a basic question and a bit off topic but I have been trying to produce a release js and haven't been able - installed npm on my test server but npm keeps giving errors when I try to publish.

labregowski avatar Dec 23 '17 14:12 labregowski

My workaround, until this fixed by allowing some king of custom Camera settings, is to set the first camera which contains "back" inside its name value:

if (cameras.length > 0) {
    var selectedCam = cameras[0];
    $.each(cameras, (i, c) => {
        if (c.name.indexOf('back') != -1) {
            selectedCam = c;
            return false;
        }
    });

    scanner.start(selectedCam);
} else {
    console.error('No cameras found.');
}

It always selects the rear camera.

My workaround, until this fixed by allowing some king of custom Camera settings, is to set the first camera which contains "back" inside its name value:

if (cameras.length > 0) {
    var selectedCam = cameras[0];
    $.each(cameras, (i, c) => {
        if (c.name.indexOf('back') != -1) {
            selectedCam = c;
            return false;
        }
    });

    scanner.start(selectedCam);
} else {
    console.error('No cameras found.');
}

It always selects the rear camera.

@clytras nice solution! But what happens if the mobile phone has more than one back camera?

I've tried this solution and with the first back camera of the array the vision is horrible with a lot of zoom. I am not able to scan anything.

But, if I use the second back camera returned it works perfectly and I can scan everything.

My question is if exists a a way to detect which is the main back camera? Imagine if the website is used by different users, which means they will have different devices and the number of back cameras will be different and the order returned.

Thanks a lot.

arnaubosch avatar Feb 13 '20 08:02 arnaubosch

My workaround, until this fixed by allowing some king of custom Camera settings, is to set the first camera which contains "back" inside its name value:

if (cameras.length > 0) {
    var selectedCam = cameras[0];
    $.each(cameras, (i, c) => {
        if (c.name.indexOf('back') != -1) {
            selectedCam = c;
            return false;
        }
    });

    scanner.start(selectedCam);
} else {
    console.error('No cameras found.');
}

It always selects the rear camera.

German Iphone have different language of "Back"

ashu4code avatar Nov 28 '21 13:11 ashu4code

German Iphone have different language of "Back"

@ashu4code this is a workaround, not the solution to the problem, thus we have to adapt it to our needs.

If you face these kind of different language cases and your audience is mainly targeted on specific locales, then you can easily change the indexOf with a regular expression containing the words of the cameras you want to support.

So, instead of c.name.indexOf('back') we can have a RegExp test /back|zurück|arrière/iu.test(c.name). If you want to support older browsers that don't have Regular Expressions Unicode support, then just make a loop to search for the words you want to support.

clytras avatar Nov 28 '21 16:11 clytras

Hi guys, I have the solution and is possible set back camera for default. `let opts = { // Whether to scan continuously for QR codes. If false, use scanner.scan() to manually scan. // If true, the scanner emits the "scan" event when a QR code is scanned. Default true. continuous: true,

            // The HTML element to use for the camera's video preview. Must be a <video> element.
            // When the camera is active, this element will have the "active" CSS class, otherwise,
            // it will have the "inactive" class. By default, an invisible element will be created to
            // host the video.
            video: document.getElementById('preview'),
            
            // Whether to horizontally mirror the video preview. This is helpful when trying to
            // scan a QR code with a user-facing camera. Default true.
            mirror: false,
            
            // Whether to include the scanned image data as part of the scan result. See the "scan" event
            // for image format details. Default false.
            captureImage: false,
            
            // Only applies to continuous mode. Whether to actively scan when the tab is not active.
            // When false, this reduces CPU usage when the tab is not active. Default true.
            backgroundScan: false,
            
            // Only applies to continuous mode. The period, in milliseconds, before the same QR code
            // will be recognized in succession. Default 5000 (5 seconds).
            refractoryPeriod: 5000,
            
            // Only applies to continuous mode. The period, in rendered frames, between scans. A lower scan period
            // increases CPU usage but makes scan response faster. Default 1 (i.e. analyze every frame).
            scanPeriod: 5
        };
        let scanner = new Instascan.Scanner(opts);
        scanner.addListener('scan', function (content) {
            console.log(content);
            QRcodigo.set(content);
            scanner.stop();
        });
        Instascan.Camera.getCameras().then(function (cameras) {
            if (cameras.length > 0) {
                scanner.start(cameras[cameras.length-1]);
            } else {
                console.error('No cameras found.');
            }
        }).catch(function (e) {
            console.error(e);
        });`

BryanRiveraLivia avatar Jun 27 '22 07:06 BryanRiveraLivia

  • Phone/mobile support
  • { video: { facingMode: "user" } }
  • { video: { facingMode: { exact: "environment" } } }
  • https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia

pls help me. how to use this code to my js?

nrmnhdyt avatar Jul 06 '23 16:07 nrmnhdyt

For the new ones, I will explain step-by-step how to solve it:

  1. Clone the repository gh repo clone schmich/instascan
  2. Install the Gulp Compiler npm install gulp-cli -g. This is essential to regenerate the Instascan.min.js
  3. Enter the folder cd instascan and Install NPM dependecies npm install
  4. Go to file src/camera.js
  5. Replace the async start() method of the class Camera to:
async start() {
    let constraints = {
      audio: false,
      video: {
        facingMode: { exact: "environment" },
        mandatory: {
          sourceId: this.id,
          minWidth: 600,
          maxWidth: 800,
          minAspectRatio: 1.6
        },
        optional: []
      }
    };

    this._stream = await Camera._wrapErrors(async () => {
      return await navigator.mediaDevices.getUserMedia(constraints);
    });

    return this._stream;
  }
  1. Now let's create a new Instascan.min.js using the command: gulp release, it's will create a folder on the project called "dist" and inside of it, there is the brand-new Instascan.min.js that supports back-cameras.
  2. Now include the Instascan.min.js into your project, it will magically ✨ work!

P.S.: To generate the instascan.min.js again you need the gulp release. But this project use the old Gulp version, and this will not work in NodeJS new versions, so to solve that see this link https://stackoverflow.com/questions/55921442/how-to-fix-referenceerror-primordials-is-not-defined-in-node-js .

BONUS:

I have created a new Instascan.min.js with this capabillity. The gist is that: https://gist.github.com/brunoinds/4466253d4ec667280074c6aa3bd2dd19

And you can include it on your code using: <script src="https://gist.githubusercontent.com/brunoinds/4466253d4ec667280074c6aa3bd2dd19/raw/871a09d0533fab04651de05a0d0e994f547ae60b/instascan.min.js"></script>

brunoinds avatar Jul 19 '23 14:07 brunoinds

@brunoinds I'm using your instascan.min.js but I have this error: instascan.min.js:9 Uncaught (in promise) Error: Cannot access video stream (TypeError).

do you know why?

thanks

valeroAlb avatar Mar 06 '24 17:03 valeroAlb