A Simple Web Canvas Region Selection Tool for Barcode Region Detection

The barcode localization algorithm is an essential step for barcode recognition within an image. However, for static images, the bigger size images have, the much more time the algorithm takes. Plus, the success rate of the algorithm may be interfered by the background color and the foreground color. It is tough to guarantee a 100% success rate for locating barcodes. If the auto-detection fails, a viable workaround is to switch to the manual mode, selecting the barcode regions by your eyes, in order to recognize the barcodes you want. In this article, I will demonstrate how to create a simple web canvas region selection tool to do barcode region detection using Dynamsoft JavaScript Barcode SDK.

Canvas Region Selection

The region selection steps include:

  1. Select an image.
  2. Click the mouse and drag the cursor to draw a rectangle.
  3. Clear the previous painting and repeat the second step.

To implement the requirements, you need to create two canvases: one for displaying the image, and the other for drawing overlay:

<style>
        #container {
          position: relative;
        }
    
        #imageCanvas {
          position: relative;
          z-index: 1;
        }
    
        #overlay {
          position: absolute;
          top: 0;
          left: 0;
          z-index: 2
        }
    
      </style>

<div id="container">
        <canvas id="imageCanvas"> </canvas>
        <canvas id="overlay"></canvas>
</div>

First, use FileReader() to load an image file and draw it on the image canvas:

<input type="file" id="barcode-file" onchange="loadfile()" accept=".jpg,.jpeg,.png,.bmp" />

function loadfile() {
            let img = new Image();
            var reader = new FileReader();
            reader.onload = function (evt) {
                img.onload = function () {                    
                    if (img.width > maxLength) {
                        img.height = maxLength * img.height / img.width
                        img.width = maxLength;
                    }
                    else if (img.height > maxLength) {
                        img.width = maxLength * img.width / img.height
                        img.height = maxLength;
                    }
                    canvas.width = img.width;
                    canvas.height = img.height;
                    overlay.width = canvas.width;
                    overlay.height = canvas.height;
                    
                    context.drawImage(img, 0, 0, img.width, img.height);
                };
                img.src = evt.target.result;
            };
            reader.readAsDataURL(name.files[0]);
	
}

You can define a maximum size in case of the image size is too big.

Next, you can add mouse event listeners to the overlay canvas. There are three mouse events required: mousedown, mousemove, and mouseup:

function clearOverlay() {
            overlayCtx.clearRect(0, 0, overlay.width, overlay.height);
            overlayCtx.strokeStyle = '#ff0000';
            overlayCtx.lineWidth = 5;
        }

overlay.addEventListener('mousedown', e => {
                    startX = e.offsetX;
                    startY = e.offsetY;
                    isDrawing = true;
                    clearOverlay();
                    overlay.style.cursor = "crosshair";
                });

                overlay.addEventListener('mousemove', e => {
                    if (isDrawing) {
                        clearOverlay();
                        overlayCtx.beginPath();
                        overlayCtx.rect(startX, startY, e.offsetX - startX, e.offsetY - startY);  
                        overlayCtx.stroke();
                    } 
                    mousePosition.innerHTML = "Cursor: (" + e.offsetX + ", " + e.offsetY + ")";
                });

                overlay.addEventListener('mouseup', e => {
                    if (isDrawing) {
                        isDrawing = false;
                        
                        mousePosition.innerHTML = "Cursor: (" + e.offsetX + ", " + e.offsetY + ")";
                        region.innerHTML = "Decode a region: (" + startX + ", " + startY + ", " + e.offsetX + ", " + e.offsetY + "). ";
                        overlay.style.cursor = "default";
                    }

                });

So far, the canvas region selection function is done. While dragging the cursor, a rectangle will be drawn over the image. In the following paragraph, you will see how to do the barcode region detection with the selected area.

Barcode Region Detection

Here is the online documentation about the region settings:

https://www.dynamsoft.com/barcode-reader/programming/javascript/api-reference/global-interfaces.html#regiondefinition

To make a comparison, you can first decode barcodes from the full image. Dynamsoft JavaScript decoding API supports a variety of data type as the input source, such as file object, Blob, Buffer, ArrayBuffer, Uint8Array, Uint8ClampedArray, HTMLImageElement, HTMLCanvasElement, HTMLVideoElement, and string:

(async () => {
                await barcodereader.resetRuntimeSettings();
                await barcodereader.updateRuntimeSettings('coverage'); // Mode: speed, balance, coverage
                try {
                    await barcodereader.decode(name.files[0]).then((results) => {
                        let txts = [];
                        try {
                            for (let i = 0; i < results.length; ++i) {
                                txts.push(results[i].BarcodeText);
                            }
                            let barcoderesults = txts.join(', ');
                        } catch (e) {
                        }
                    });
                } catch (error) {
                    alert(error);
                }
            })();
  • The resetRuntimeSettings() method changes all settings to default.
  • The updateRuntimeSettings(‘coverage’) maximize recognition accuracy by sacrificing the decoding speed.

The barcode region detection code can be added to the mouseup event function:

overlay.addEventListener('mouseup', e => {
                    if (isDrawing) {
                        isDrawing = false;
                        
                        mousePosition.innerHTML = "Cursor: (" + e.offsetX + ", " + e.offsetY + ")";
                        region.innerHTML = "Decode a region: (" + startX + ", " + startY + ", " + e.offsetX + ", " + e.offsetY + "). ";
                        overlay.style.cursor = "default";

                        // Decode a region of the barcode image
                        (async () => {
                            let settings = await barcodereader.getRuntimeSettings();
                            settings.region.regionLeft = startX * 100 / overlay.width;
                            settings.region.regionTop = startY * 100 / overlay.height;
                            settings.region.regionRight = e.offsetX * 100 / overlay.width;
                            settings.region.regionBottom = e.offsetY * 100 / overlay.height;
                            settings.region.regionMeasuredByPercentage = 1;
                            barcodereader.updateRuntimeSettings(settings);
                            try {
                                let decodingStart = Date.now();
                                await barcodereader.decode(name.files[0]).then((results) => {
                                    let decodingEnd = Date.now();
                                    let txts = [];
                                    try {
                                        for (let i = 0; i < results.length; ++i) {
                                            txts.push(results[i].BarcodeText);
                                        }
                                        let barcoderesults = txts.join(', ');
                                    catch (e) {
                                    }
                                });
                            } catch (error) {
                                alert(error);
                            }
                        })();
                    }

                });

Since you may have scaled the image, you can set a percentage instead of the real coordinate value. The value of regionMeasuredByPercentage must be 1.

Now you can test the barcode region detection app in your web browsers.

barcode region detection

barcode region detection

Source Code

https://gist.github.com/yushulx/b21d0919a1e92e0a320929799a99a5de