Web Parcel Management: Scan 1D Barcodes and Recognize Surrounding Text in Any Orientation
Tags: webdev, javascript, ocr, barcode
Published: 2024-05-16 08:41:08

In today's fast-paced world, efficiently managing and tracking parcels is crucial for businesses. The use of 1D and 2D **barcodes** has revolutionized the way parcels are labeled, scanned, and processed. Additionally, **Optical Character Recognition (OCR)** technology has enabled the digitization of text on parcels, facilitating automated data extraction and processing. Most OCR technologies can only recognize text in a horizontal orientation. However, in real-world scenarios, a barcode and its surrounding text label can appear in **any orientation** on a parcel. This article aims to address this challenge using Dynamsoft Capture Vision SDKs.

![parcel management with barcode and OCR](https://www.dynamsoft.com/codepool/img/2024/05/ups-parcel-barcode-text.jpg)

## Online Demo
[https://yushulx.me/javascript-barcode-qr-code-scanner/examples/10.x/barcode_ocr_text](https://yushulx.me/javascript-barcode-qr-code-scanner/examples/10.x/barcode_ocr_text)

## Prerequisites
- Obtain a [30-Day trial license key](https://www.dynamsoft.com/customer/license/trialLicense/) for multiple Dynamsoft SDK modules.
    
    ![Dynamsoft Capture Vision trial license](https://www.dynamsoft.com/codepool/img/2024/05/capture-vision-trial-license.png)

- Generate a combo of Dynamsoft SDK modules for barcode and OCR. 
    1. Open the [generator page](https://www.dynamsoft.com/generate-compatible-modules-dependency/).
    2. Select "NPM for JavaScript Edition".
    3. Check **Dynamsoft Barcode Reader**, **Dynamsoft Label Recognizer**, and **Dynamsoft Camera Enhancer**.
        
        ![Generate Dynamsoft SDK modules](https://www.dynamsoft.com/codepool/img/2024/05/dynamsoft-capture-vision-module.jpg)

    4. Click the `Generate` button to get the combo URLs.
        
        ```bash
        <script src="https://cdn.jsdelivr.net/npm/dynamsoft-core@3.0.33/dist/core.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/dynamsoft-barcode-reader@10.0.21/dist/dbr.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/dynamsoft-camera-enhancer@4.0.1/dist/dce.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-router@2.0.32/dist/cvr.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/dynamsoft-label-recognizer@3.0.30/dist/dlr.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/dynamsoft-license@3.0.40/dist/license.js"></script>
        <script src="https://cdn.jsdelivr.net/npm/dynamsoft-utility@1.0.21/dist/utility.js"></script>
        ```
        
        Copy the above script tags to your HTML file. Do not disrupt the order, or you will encounter errors.

## The Architecture of Dynamsoft Capture Vision
If this is your first time hearing about [Dynamsoft Capture Vision](https://www.dynamsoft.com/capture-vision/docs/core/architecture/), you may wonder how it works. The following diagram illustrates the architecture of Dynamsoft Capture Vision:

![Dynamsoft Capture Vision Architecture](https://www.dynamsoft.com/capture-vision/docs/core/architecture/assets/dcv-architecture.png)

Dynamsoft Capture Vision consists of several key modules: **Dynamsoft Barcode Reader**, **Dynamsoft Label Recognizer**, **Dynamsoft Document Normalizer**, **Dynamsoft Code Parser**, and **Dynamsoft Camera Enhancer**. These modules can function independently or collaboratively, providing a comprehensive solution for barcode scanning, OCR, document processing, and image enhancement.

In the parcel management scenario discussed in this article, we focus on **Dynamsoft Barcode Reader** and **Dynamsoft Label Recognizer**. The former is used to scan 1D barcodes, while the latter is used to recognize text on parcels. In the subsequent sections, you will learn how to integrate these two modules into a web application.

## How to Scan 1D Barcodes and OCR Text Simultaneously

### Step 1. Include the Dynamsoft SDK Modules
Create an HTML file and include the script tags generated in the prerequisites section.

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <script src="https://cdn.jsdelivr.net/npm/dynamsoft-core@3.2.30/dist/core.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/dynamsoft-license@3.2.20/dist/license.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/dynamsoft-utility@1.2.20/dist/utility.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/dynamsoft-label-recognizer@3.2.30/dist/dlr.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/dynamsoft-barcode-reader@10.2.10/dist/dbr.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/dynamsoft-capture-vision-router@2.2.30/dist/cvr.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/dynamsoft-camera-enhancer@4.0.2/dist/dce.js"></script>

    <title>Dynamsoft Capture Vision Example</title>
    <link rel="stylesheet" href="main.css">
</head>

<body>
</body>

</html>
```
    
### Step 2.Initialize Dynamsoft Barcode Reader and Dynamsoft Label Recognizer
1. Set the license key:
    
    ```js
    Dynamsoft.License.LicenseManager.initLicense(license);
    ```
    
2. Load the wasm files actively:
    
    ```js
    Dynamsoft.Core.CoreModule.loadWasm(["cvr", "dbr", "dlr",]);
    ```
    
    Downloading WASM files may take some time. Without calling this method, the SDK will load the WASM files automatically when needed. However, this may cause a delay when scanning barcodes or recognizing text.

3. Pick a suitable OCR model for the label recognizer:
    
    ```js
    await Dynamsoft.DLR.LabelRecognizerModule.loadRecognitionData("Letter");
    ```
    
    All available OCR models are listed in the [documentation](https://www.dynamsoft.com/label-recognition/docs/web/programming/javascript/api-reference/label-recognizer-module-class.html?lang=js#loadrecognitiondata). You can choose the one that best fits your scenario.

    ```bash
    Letter.data
    MRZ.data
    Number.data
    NumberLetter.data
    NumberUppercase.data
    Uppercase.data
    VIN.data
    ```
    
4. Create instances of `CaptureVisionRouter`, `CameraView`, `CameraEnhancer` and `CapturedResultReceiver`. The `CapturedResultReceiver` provides callbacks for handling different types of results, such as barcode results and text results.
    
    ```javascript
    let router = await Dynamsoft.CVR.CaptureVisionRouter.createInstance();

    let view = await Dynamsoft.DCE.CameraView.createInstance();
    let cameraEnhancer = await Dynamsoft.DCE.CameraEnhancer.createInstance(view);

    document.querySelector("#cameraViewContainer").append(view.getUIElement());
    router.setInput(cameraEnhancer);

    const resultsContainer = document.querySelector("#results");
    const resultReceiver = new Dynamsoft.CVR.CapturedResultReceiver();

    let lastResult = {};

    resultReceiver.onCapturedResultReceived = (result) => {
        if (result.items.length == 0) {
            resultsContainer.textContent = '';
        }
    }

    resultReceiver.onDecodedBarcodesReceived = (result) => {
        if (!lastResult["id"]) {
            lastResult["id"] = result.originalImageTag.imageId;
        }
        else {
            if (lastResult["id"] !== result.originalImageTag.imageId) {
                resultsContainer.textContent = '';
                lastResult["id"] = result.originalImageTag.imageId;
            }
        }

        if (result.barcodeResultItems.length > 0) {
            for (let item of result.barcodeResultItems) {
                resultsContainer.textContent += `Barcode Type: ${item.formatString}, Value: ${item.text}\n\n`;
            }
        }
    }

    resultReceiver.onRecognizedTextLinesReceived = (result) => {
        if (!lastResult["id"]) {
            lastResult["id"] = result.originalImageTag.imageId;
        }
        else {
            if (lastResult["id"] !== result.originalImageTag.imageId) {
                resultsContainer.textContent = '';
                lastResult["id"] = result.originalImageTag.imageId;
            }
        }

        if (result.textLineResultItems.length > 0) {
            for (let item of result.textLineResultItems) {
                resultsContainer.textContent += `Text: ${item.text}\n`;
            }
        }
    };
    router.addResultReceiver(resultReceiver);
    ```
        
5. Define a custom template for image processing logics and set it to the router:
    
    ```js
    let settings = {
        "CaptureVisionTemplates": [
            {
                "Name": "ReadBarcode&AccompanyText",
                "ImageROIProcessingNameArray": [
                    "roi-read-barcodes-only", "roi-read-text"
                ]
            }
        ],
        "TargetROIDefOptions": [
            {
                "Name": "roi-read-barcodes-only",
                "TaskSettingNameArray": ["task-read-barcodes"]
            },
            {
                "Name": "roi-read-text",
                "TaskSettingNameArray": ["task-read-text"],
                "Location":
                {
                    "ReferenceObjectFilter": {
                        "ReferenceTargetROIDefNameArray": ["roi-read-barcodes-only"]
                    },
                    "Offset": {
                        "MeasuredByPercentage": 1,
                        "FirstPoint": [-20, -50],
                        "SecondPoint": [150, -50],
                        "ThirdPoint": [150, -5],
                        "FourthPoint": [-20, -5]
                    }
                }
            }
        ],
        "CharacterModelOptions": [
            {
                "Name": "Letter"
            }
        ],
        "ImageParameterOptions": [
            {
                "Name": "ip-read-text",
                "TextureDetectionModes": [
                    {
                        "Mode": "TDM_GENERAL_WIDTH_CONCENTRATION",
                        "Sensitivity": 8
                    }
                ],
                "TextDetectionMode": {
                    "Mode": "TTDM_LINE",
                    "CharHeightRange": [
                        20,
                        1000,
                        1
                    ],
                    "Direction": "HORIZONTAL",
                    "Sensitivity": 7
                }
            }
        ],
        "TextLineSpecificationOptions": [
            {
                "Name": "tls-11007",
                "CharacterModelName": "Letter",
                "CharHeightRange": [5, 1000, 1],
                "BinarizationModes": [
                    {
                        "BlockSizeX": 30,
                        "BlockSizeY": 30,
                        "Mode": "BM_LOCAL_BLOCK",
                        "MorphOperation": "Close"
                    }
                ]
            }
        ],
        "BarcodeReaderTaskSettingOptions": [
            {
                "Name": "task-read-barcodes",
                "BarcodeFormatIds": ["BF_ONED"]
            }
        ],
        "LabelRecognizerTaskSettingOptions": [
            {
                "Name": "task-read-text",
                "TextLineSpecificationNameArray": [
                    "tls-11007"
                ],
                "SectionImageParameterArray": [
                    {
                        "Section": "ST_REGION_PREDETECTION",
                        "ImageParameterName": "ip-read-text"
                    },
                    {
                        "Section": "ST_TEXT_LINE_LOCALIZATION",
                        "ImageParameterName": "ip-read-text"
                    },
                    {
                        "Section": "ST_TEXT_LINE_RECOGNITION",
                        "ImageParameterName": "ip-read-text"
                    }
                ]
            }
        ]
    }
    await router.initSettings(settings);
    ```
    
    There are several [preset templates](https://www.dynamsoft.com/capture-vision/docs/web/programming/javascript/api-reference/capture-vision-router/preset-templates.html?product=dlr&lang=js) defined in the SDK. If none of them fits your scenario, you can create a custom template like the one above.

6. Start the camera and the router:
    
    ```js
    await cameraEnhancer.open();
    await router.startCapturing("ReadBarcode&AccompanyText");
    ```

    The `ReadBarcode&AccompanyText` string is the name of the custom template defined in the previous step.

7. Run the application in a browser. Point the camera at a parcel with a 1D barcode and text label. The application will scan the barcode and recognize the text simultaneously.
    
    ![scan barcode and OCR text in web](https://www.dynamsoft.com/codepool/img/2024/05/barcode-ocr-text-90-degree.jpg)

## Troubleshooting

If you encounter issues with text recognition, check the developer console to verify whether the OCR model has been loaded successfully. 

![check OCR model in the developer console](https://www.dynamsoft.com/codepool/img/2024/05/ocr-model-file.jpg)

## Source Code
[https://github.com/yushulx/javascript-barcode-qr-code-scanner/tree/main/examples/10.x/barcode_ocr_text](https://github.com/yushulx/javascript-barcode-qr-code-scanner/tree/main/examples/10.x/barcode_ocr_text)