Add Auto-Zoom to a Web QR Code Scanner

Camera zoom control on the web is limited to Chromium browsers, so automatically zooming the camera to read a tiny or distant QR code needs either the native zoom constraint or a simulated fallback. Built on dynamsoft-barcode-reader-bundle v11, Dynamsoft Camera Enhancer provides a built-in auto-zoom feature (EF_AUTO_ZOOM) that does this for you: the SDK detects a localized-but-unreadable QR code, zooms the camera in, and zooms back out when nothing is read for a few seconds.

Dynamsoft Barcode Reader is used to read QR codes and detect whether there are QR codes in the camera preview. The previous article covered manual camera zoom control on the web; this article takes it one step further and lets the scanner zoom by itself.

What you’ll build: A web QR code scanner that automatically zooms in on a tiny or distant QR code so it can be read, using dynamsoft-barcode-reader-bundle v11 with either the Camera Enhancer built-in auto-zoom feature or manual getUserMedia zoom control driven by barcode localization results.

Key Takeaways

  • Auto-zoom triggers when a QR code is detected (localized) in the camera preview but is too small to decode: zooming in increases its pixel size so the decoder succeeds.
  • dynamsoft-barcode-reader-bundle v11 ships Core, License, Utility, CaptureVisionRouter, Barcode Reader, and Camera Enhancer in a single dbr.bundle.js — one script tag instead of six.
  • Enable the built-in feature with cameraEnhancer.enableEnhancedFeatures(Dynamsoft.DCE.EnumEnhancedFeatures.EF_AUTO_ZOOM) after creating the CameraEnhancer instance.
  • The zoom level is observable at runtime through cameraEnhancer.getZoomSettings().factor.
  • To implement auto-zoom manually, listen to onLocalizedBarcodesReceived on the IntermediateResultReceiver of CaptureVisionRouter and apply track.applyConstraints({advanced: [{zoom}]}) with a computed factor.
  • Native camera zoom only works on browsers and devices that expose it; iOS Safari and Firefox do not support the zoom constraint, where the Camera Enhancer falls back to simulated zoom.

Common Developer Questions

How can I automatically zoom the camera on a web page to scan a small QR code?

Use Dynamsoft Camera Enhancer (bundled in dynamsoft-barcode-reader-bundle v11) and call enableEnhancedFeatures(Dynamsoft.DCE.EnumEnhancedFeatures.EF_AUTO_ZOOM) after creating the CameraEnhancer instance. The SDK watches each frame, zooms the camera in when a QR code is localized but too small to decode, and returns to the default zoom when no code is read for several seconds.

How does auto-zoom know that a QR code was detected but not decoded?

The QR code’s four-corner location is an intermediate result of the decoding pipeline, produced even when the final decode fails. CaptureVisionRouter exposes these through an IntermediateResultReceiver: its onLocalizedBarcodesReceived callback reports the location quadrilaterals, from which the zoom factor can be computed — either internally by EF_AUTO_ZOOM or in your own code.

Why doesn’t the browser camera zoom API work in my web scanner?

The zoom media constraint is only implemented in Chromium-based browsers (for example, Chrome on Android), and even there the camera hardware must advertise zoom in track.getCapabilities(). Firefox and iOS Safari do not expose native zoom; the Camera Enhancer’s auto-zoom still works on those browsers because it simulates zooming (CSS/WebGL) where the native API is missing.

What changed when migrating from the six separate scripts to dynamsoft-barcode-reader-bundle?

The bundle replaces dynamsoft-core, dynamsoft-license, dynamsoft-utility, dynamsoft-barcode-reader, dynamsoft-capture-vision-router, and dynamsoft-camera-enhancer with a single dist/dbr.bundle.js. Dynamsoft.CVR.CaptureVisionRouter, Dynamsoft.DCE.CameraEnhancer, Dynamsoft.Utility.MultiFrameResultCrossFilter, and the camera settings API keep the same names, so existing scanner code continues to work. Use loadWasm(["DBR"]) (capitalized) and await on LicenseManager.initLicense() to know when activation has finished.

Demo video:

Prerequisites

  • A modern desktop or mobile browser. For the manual getUserMedia zoom path in the last section, use Chrome on Android or another Chromium browser with a zoom-capable camera; the Camera Enhancer EF_AUTO_ZOOM path also works where native zoom is missing by simulating it.
  • Get a 30-day free trial license for Dynamsoft Barcode Reader if you want to run the code in this article on your own domain.

Step 1: Build a Web QR Code Scanner

First, let’s create a web QR code scanner.

  1. Create a new HTML file with the following template:

    <!DOCTYPE html>
    <html>
    <head>
      <title>QR Code Scanner with Auto-Zoom</title>
      <meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=0" />
      <style>
        #enhancerUIContainer {
          height: 480px;
          max-width: 100%;
        }
    
        .results {
          border: 1px black solid;
          margin: 10px 0;
          padding: 5px;
          height: 75px;
          overflow: auto;
        }
      </style>
    </head>
    <body>
      <h2>QR Code Scanner with Auto-Zoom</h2>
      <label>
        Camera:
        <select id="select-camera"></select>
      </label>
      <label>
        Resolution:
        <select id="select-resolution">
          <option value="640x480">640x480</option>
          <option value="1280x720">1280x720</option>
          <option value="1920x1080" selected>1920x1080</option>
          <option value="3840x2160">3840x2160</option>
        </select>
      </label>
      <label>
        Zoom Factor:
        <span id="zoomFactor">1</span>
      </label>
      <button onclick="startCamera();">Start Camera</button>
      <br/>
      <div class="results">
        <div>Results:</div>
        <ol></ol>
      </div>
      <div id="enhancerUIContainer"></div>
      <script type="text/javascript">
      </script>
    </body>
    </html>
    
  2. Include the SDK in the head. The dynamsoft-barcode-reader-bundle package ships Dynamsoft Barcode Reader, Capture Vision Router, Core, License, Utility, and Camera Enhancer in a single file, so one script tag replaces the six separate packages older samples loaded:

    <script src="https://cdn.jsdelivr.net/npm/dynamsoft-barcode-reader-bundle@11.6.3000/dist/dbr.bundle.js"></script>
    
  3. Initialize the license to use Dynamsoft’s SDKs with the key obtained in the Prerequisites step.

    let license = "LICENSE-KEY";
    await Dynamsoft.License.LicenseManager.initLicense(license);
    
  4. Initialize Dynamsoft Camera Enhancer for camera control.

    let cameraView = await Dynamsoft.DCE.CameraView.createInstance();
    cameraEnhancer = await Dynamsoft.DCE.CameraEnhancer.createInstance(cameraView);
    document.querySelector("#enhancerUIContainer").append(cameraView.getUIElement());
    
  5. Initialize capture vision router to call Dynamsoft Barcode Reader.

    await Dynamsoft.Core.CoreModule.loadWasm(["DBR"]);
    router = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();
    
  6. Set the camera enhancer as the input of the capture vision router. The capture vision router will try to get camera frames from it and read barcodes. A filter is also set so that it will verify the results based on readings of multiple frames and avoid returning duplicate barcodes too quickly.

    router.setInput(cameraEnhancer);
    
    router.addResultReceiver({ onDecodedBarcodesReceived: (result) => {
      displayResults(result);
    }});
    
    let filter = new Dynamsoft.Utility.MultiFrameResultCrossFilter();
    filter.enableResultCrossVerification("barcode", true);
    filter.enableResultDeduplication("barcode", true);
    await router.addResultFilter(filter);
    
  7. Start the selected camera and start capturing barcodes after the camera is opened.

    async function startCamera(){
      let selectedCamera = cameras[document.getElementById("select-camera").selectedIndex];
      let selectedResolution = document.getElementById("select-resolution").selectedOptions[0].value;
      let width = parseInt(selectedResolution.split("x")[0]);
      let height = parseInt(selectedResolution.split("x")[1]);
         
      await cameraEnhancer.selectCamera(selectedCamera);
      await cameraEnhancer.setResolution({width:width, height:height});
      await cameraEnhancer.open();
      await router.startCapturing("ReadSingleBarcode");
    }
    

    The results will be displayed in a container.

    function displayResults(result){
      if (result.barcodeResultItems.length > 0) {   
        let ol = document.querySelector(".results ol");
        ol.innerHTML = "";
        for (let index = 0; index < result.barcodeResultItems.length; index++) {
          const item = result.barcodeResultItems[index];
          const li = document.createElement("li");
          li.innerText = item.formatString+": "+item.text;
          ol.appendChild(li);
        }
      }
    }
    

Step 2: Enable Auto-Zoom

After the web QR code scanner is done, we can enable auto-zoom to improve the scanning of a tiny or distant QR code. If there is a QR code in the camera preview that cannot be read, auto-zoom will be triggered. After zooming, if it cannot read QR codes in several seconds, it will return to the default zoom status.

This feature is included in Dynamsoft Camera Enhancer. We can enable it with the following code:

cameraEnhancer.enableEnhancedFeatures(Dynamsoft.DCE.EnumEnhancedFeatures.EF_AUTO_ZOOM);

Optionally, display the current zoom level on the page so users can confirm auto-zoom is working. Poll getZoomSettings() after the camera starts playing:

cameraEnhancer.on("played", () => {
  setInterval(() => {
    document.getElementById("zoomFactor").innerText = cameraEnhancer.getZoomSettings().factor;
  }, 200);
});

Step 3: How Auto-Zoom Works

So how does auto-zoom work exactly?

If a QR code’s location is detected but is too small and cannot be read, we can trigger the camera zoom to get a better QR code image for reading. Dynamsoft Barcode Reader’s intermediate result feature is used to get the unread QR code’s location.

Here is the code to get the location:

const intermediateResultManager = router.getIntermediateResultManager();
const intermediateResultReceiver = new Dynamsoft.CVR.IntermediateResultReceiver();
intermediateResultReceiver.onLocalizedBarcodesReceived = (result, info) => {
  console.log(result);
};
intermediateResultManager.addResultReceiver(intermediateResultReceiver);

Then, we can calculate the zoom factor to maximize the QR code image in the camera preview.

function calculatedFactor(localizedBarcode){
  let left = localizedBarcode.location.points[0].x;
  let top = localizedBarcode.location.points[0].y;
  let video = document.getElementById("video");
  let width = video.videoWidth;
  if (left < width/2) {
    let croppedWidth = Math.max(0,left - 50);
    if (croppedWidth == 0) {
      return 1.0;
    }
    let maxCroppedWidth = top;
    croppedWidth = Math.min(maxCroppedWidth,croppedWidth);
    return width / (width - (croppedWidth * 2));
  }else{
    return 1.0;
  }
}

With the computed factor, zoom the camera in through the zoom constraint of MediaStreamTrack.applyConstraints() — this is the path taken by the getUserMedia version of the demo, where onLocalizedBarcodesReceived fires a zoomIn() when a high-confidence QR code is localized but no decode result comes back, and falls back with zoomOutIfTimeOut() after five seconds without readings:

async function setZoom(){
  try {
    let expectedZoom = document.getElementById("zoomInput").value;
    const constraints = {advanced: [{zoom: expectedZoom}]};
    await track.applyConstraints(constraints);
  } catch (error) {
    console.log(error);
  }
}

The built-in EF_AUTO_ZOOM feature in Dynamsoft Camera Enhancer performs the same localize-compute-zoom loop internally and additionally simulates the zoom effect on browsers or cameras that do not expose the native zoom constraint.

Common Issues & Edge Cases

  • Zoom has no effect on iOS Safari or Firefox. These browsers do not implement the zoom media constraint. Check support with navigator.mediaDevices.getSupportedConstraints().zoom before relying on it, and use the Camera Enhancer EF_AUTO_ZOOM path, which simulates zooming digitally instead.
  • The specific camera does not support zoom. Browser support alone is not enough: query track.getCapabilities() and only apply zoom if the device reports a zoom range. A webcam without optical zoom simply will not respond to the constraint.
  • The page must be served over HTTPS or localhost. getUserMedia (and therefore the whole scanner) is blocked on insecure origins.
  • Auto-zoom keeps hunting after the code is moved away. The feature is reactive: it zooms in on a localized but unreadable code and returns to the default zoom level after a few seconds without successful reads. If you implement the manual path yourself, remember a timeout — as zoomOutIfTimeOut() does — otherwise the preview stays stuck at a high zoom factor.
  • License dialog covers the page during testing. When a key is invalid or out of session, initLicense() shows an interactive license dialog with a modal mask; dismiss or replace the key before debugging other UI issues.

Source Code

Get the complete sample project source code on GitHub: Vanilla-JS-Barcode-Reader-Demos/autozoom.