Search code examples
javascripthtmlcameragetusermedia

Bad Resolution Image taken with getuserMedia() Javascript


i wanted to take screenshots from a mobilephone camera using javascript getUserMedia function but resolution is very bad.

if (navigator.mediaDevices) {
  // access the web cam
  navigator.mediaDevices.getUserMedia({
   video: {
    width: { 
     min: 1280,
    },
    height: {
     min: 720,
    },
    facingMode: {
     exact: 'environment'
    }
   }
  }).then(function(stream) {
      video.srcObject = stream;
      video.addEventListener('click', takeSnapshot);
  })
  .catch(function(error) {
      document.body.textContent = 'Could not access the camera. Error: ' + error.name;
  });
}


var video = document.querySelector('video'), canvas;

function takeSnapshot(){
  var img =  document.createElement('img');
  var context;
  var width = video.offsetWidth, height = video.offsetHeight;
  var canvas = document.createElement('canvas');
    canvas.width = width;
    canvas.height = height; 
    context = canvas.getContext('2d');          
    context.webkitImageSmoothingEnabled = false;
    context.mozImageSmoothingEnabled = false;
    context.imageSmoothingEnabled = false;
    context.drawImage(video, 0,  0, width,  height);    
    img.src = canvas.toDataURL('image/jpeg');
}

No errors-code, but resolution not good, i cannot read the text of the photo. There is a method to get real image quality from camera?


Solution

  • MediaCapture

    This is what you are using via getUserMedia.

    If you have a camera which allows a 1920x1080, 1280x720, and 640x480 resolutions only, the browser implementation of Media Capture can emulate a 480x640 feed from the 1280x720 (see MediaStream). From testing (primarily Chrome) the browser typically scales 720 down to 640 and then crops the center. Sometimes when I have used virtual camera software I see Chrome has added artificial black padding around a non supported resolution. The client sees a success message and a feed of the right dimensions but a person would see a qualitative degradation. Because of this emulation you cannot guarantee the feed is correct or not scaled. However it will typically have the correct dimensions requested.

    You can read about constraints here. It basically boils down to: Give me a resolution as close to x. Then the browser determines by its own implementation to reject the constraints and throw an error, get the resolution, or emulate the resolution.

    More information of this design is detailed in the mediacapture specification. Especially:

    The RTCPeerConnection is an interesting object because it acts simultaneously as both a sink and a source for over-the-network streams. As a sink, it has source transformational capabilities (e.g., lowering bit-rates, scaling-up / down resolutions, and adjusting frame-rates), and as a source it could have its own settings changed by a track source.

    The main reason for this is allowing n clients to have access to the same media source but may require different resolutions, bit rate, etc, thus emulation/scaling/transforming attempts to solve this problem. A negative to this is that you never truly know what the source resolution is.

    ImageCapture

    This is potentially your solution.

    If 60FPS video isn't a hard requirement and you have leway on compatibility you can poll ImageCapture to emulate a camera and receive a much clearer image from the camera.

    You would have to check for clientside support and then potentially fallback on MediaCapture.

    The API enables control over camera features such as zoom, brightness, contrast, ISO and white balance. Best of all, Image Capture allows you to access the full resolution capabilities of any available device camera or webcam. Previous techniques for taking photos on the Web have used video snapshots (MediaCapture rendered to a Canvas), which are lower resolution than that available for still images.

    https://developers.google.com/web/updates/2016/12/imagecapture

    and its polyfill:

    https://github.com/GoogleChromeLabs/imagecapture-polyfill