Logo

dev-resources.site

for different kinds of informations.

Decoding 1D/2D Barcodes from Multi-Page PDFs Using C++ and Node.js

Published at
11/4/2024
Categories
cpp
node
pdf
barcode
Author
yushulx
Categories
4 categories in total
cpp
open
node
open
pdf
open
barcode
open
Author
7 person written this
yushulx
open
Decoding 1D/2D Barcodes from Multi-Page PDFs Using C++ and Node.js

While many barcode SDKs can decode barcodes from images, only a few excel at extracting 1D and 2D barcodes from multi-page PDF files. This is where the Dynamsoft Barcode Reader SDK stands out, offering robust capabilities to accurately scan and decode barcodes across multiple pages within PDFs. In this tutorial, we will start by using Dynamsoft C++ Barcode SDK v10.x to tackle the challenges of PDF barcode decoding and then integrate the functionality into a Node.js addon, helping developers streamline barcode extraction from complex PDF documents.

Node.js Barcode Reader Demo Video

Prerequisites

A Simple C++ Program to Decode Barcodes from Images

To get started with the C++ API of the Dynamsoft Barcode Reader SDK, you can refer to the ReadAnImage.cpp file provided in the official repository.

#include <iostream>
#include <string>

#include "../../../Include/DynamsoftCaptureVisionRouter.h"

using namespace std;
using namespace dynamsoft::license;
using namespace dynamsoft::cvr;
using namespace dynamsoft::dbr;
using namespace dynamsoft::basic_structures;
#if defined(_WIN64) || defined(_WIN32)
#ifdef _WIN64
#pragma comment(lib, "../../../Distributables/Lib/Windows/x64/DynamsoftLicensex64.lib")
#pragma comment(lib, "../../../Distributables/Lib/Windows/x64/DynamsoftCaptureVisionRouterx64.lib")
#else
#pragma comment(lib, "../../../Distributables/Lib/Windows/x86/DynamsoftLicensex86.lib")
#pragma comment(lib, "../../../Distributables/Lib/Windows/x86/DynamsoftCaptureVisionRouterx86.lib")
#endif
#endif

int main()
{
    int errorCode = 1;
    char errorMsg[512];

    errorCode = CLicenseManager::InitLicense("LICENSE-KEY", errorMsg, 512);

    if (errorCode != ErrorCode::EC_OK && errorCode != ErrorCode::EC_LICENSE_CACHE_USED)
    {
        cout << "License initialization failed: ErrorCode: " << errorCode << ", ErrorString: " << errorMsg << endl;
    }
    else
    {
        CCaptureVisionRouter *cvr = new CCaptureVisionRouter;

        string imageFile = "../../../Images/GeneralBarcodes.png";
        CCapturedResult *result = cvr->Capture(imageFile.c_str(), CPresetTemplate::PT_READ_BARCODES);

        if (result->GetErrorCode() != 0)
        {
            cout << "Error: " << result->GetErrorCode() << "," << result->GetErrorString() << endl;
        }
        CDecodedBarcodesResult *barcodeResult = result->GetDecodedBarcodesResult();
        if (barcodeResult == nullptr || barcodeResult->GetItemsCount() == 0)
        {
            cout << "No barcode found." << endl;
        }
        else
        {
            int barcodeResultItemCount = barcodeResult->GetItemsCount();
            cout << "Decoded " << barcodeResultItemCount << " barcodes" << endl;

            for (int j = 0; j < barcodeResultItemCount; j++)
            {
                const CBarcodeResultItem *barcodeResultItem = barcodeResult->GetItem(j);
                cout << "Result " << j + 1 << endl;
                cout << "Barcode Format: " << barcodeResultItem->GetFormatString() << endl;
                cout << "Barcode Text: " << barcodeResultItem->GetText() << endl;
            }
        }
        if (barcodeResult)
            barcodeResult->Release();
        if (result)
            result->Release();
        delete cvr, cvr = NULL;
    }
    cout << "Press any key to quit..." << endl;
    cin.ignore();
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

The primary methods used in the code snippet above are InitLicense() and Capture():

  • InitLicense() initializes the SDK with your license key.
  • Capture() processes the specified image file to decode barcodes and returns the results.

Note: Supported image formats include BMP, JPEG, PNG, single-page TIFF and single-page PDF. For multi-page TIFF/PDF files, use the CFileFetcher class to handle page-by-page processing.

Reading Barcodes from Multi-Page PDFs

Let's modify the implementation to read barcodes from multi-page PDF files.

  1. Create a MyImageSourceStateListener class that inherits from CImageSourceStateListener. This class listens for image source states and stops capturing when the image source is exhausted.

    class MyImageSourceStateListener : public CImageSourceStateListener
    {
    private:
        CCaptureVisionRouter *m_router;
    
    public:
        MyImageSourceStateListener(CCaptureVisionRouter *router)
        {
            m_router = router;
        }
    
        virtual void OnImageSourceStateReceived(ImageSourceState state)
        {
            if (state == ISS_EXHAUSTED)
                m_router->StopCapturing();
        }
    };
    
  2. Create a MyCapturedResultReceiver class that inherits from CCapturedResultReceiver. This class receives decoded barcode results from any image source. The fileTag->GetPageNumber() method retrieves the page number of the image in the PDF or TIFF file.

    class MyCapturedResultReceiver : public CCapturedResultReceiver
    {
    
        virtual void OnDecodedBarcodesReceived(CDecodedBarcodesResult *pResult) override
        {
            if (pResult->GetErrorCode() != EC_OK)
            {
                cout << "Error: " << pResult->GetErrorString() << endl;
            }
            else
            {
                auto tag = pResult->GetOriginalImageTag();
                if (tag)
                {
                    cout << "ImageID:" << tag->GetImageId() << endl;
                    CFileImageTag *fileTag = (CFileImageTag *)tag;
                    cout << "Page number:" << fileTag->GetPageNumber() << endl;
                }
                int count = pResult->GetItemsCount();
                cout << "Decoded " << count << " barcodes" << endl;
                for (int i = 0; i < count; i++)
                {
                    const CBarcodeResultItem *barcodeResultItem = pResult->GetItem(i);
                    if (barcodeResultItem != NULL)
                    {
                        cout << "Result " << i + 1 << endl;
                        cout << "Barcode Format: " << barcodeResultItem->GetFormatString() << endl;
                        cout << "Barcode Text: " << barcodeResultItem->GetText() << endl;
                    }
                }
            }
    
            cout << endl;
        }
    };
    
  3. Instantiate the CFileFetcher class and set the PDF file path.

    CFileFetcher *fileFetcher = new CFileFetcher();
    cvr->SetInput(fileFetcher);
    
  4. Read barcodes from the PDF file. Setting the second parameter of StartCapturing() to true blocks the main thread until the capturing process is complete.

    cvr->SetInput(fileFetcher);
    cvr->AddResultReceiver(capturedReceiver);
    cvr->AddImageSourceStateListener(listener);
    
    char errorMsg[512] = {0};
    int errorCode = cvr->StartCapturing(CPresetTemplate::PT_READ_BARCODES, true, errorMsg, 512);
    

The Complete C++ Program

#include <stdio.h>
#include <string>
#include <vector>
#if defined(_WIN32) || defined(_WIN64)
#include <windows.h>
#include <conio.h>
#include <io.h>
#else
#include <cstring>
#include <dirent.h>
#include <sys/time.h>
#endif

#include <fstream>
#include <streambuf>
#include <iostream>
#include <sstream>

#include "DynamsoftCaptureVisionRouter.h"
#include "DynamsoftUtility.h"
#include "template.h"

using namespace std;
using namespace dynamsoft::license;
using namespace dynamsoft::cvr;
using namespace dynamsoft::dbr;
using namespace dynamsoft::utility;
using namespace dynamsoft::basic_structures;

class MyCapturedResultReceiver : public CCapturedResultReceiver
{

    virtual void OnDecodedBarcodesReceived(CDecodedBarcodesResult *pResult) override
    {
        if (pResult->GetErrorCode() != EC_OK)
        {
            cout << "Error: " << pResult->GetErrorString() << endl;
        }
        else
        {
            auto tag = pResult->GetOriginalImageTag();
            if (tag)
            {
                cout << "ImageID:" << tag->GetImageId() << endl;
                CFileImageTag *fileTag = (CFileImageTag *)tag;
                cout << "Page number:" << fileTag->GetPageNumber() << endl;
            }
            int count = pResult->GetItemsCount();
            cout << "Decoded " << count << " barcodes" << endl;
            for (int i = 0; i < count; i++)
            {
                const CBarcodeResultItem *barcodeResultItem = pResult->GetItem(i);
                if (barcodeResultItem != NULL)
                {
                    cout << "Result " << i + 1 << endl;
                    cout << "Barcode Format: " << barcodeResultItem->GetFormatString() << endl;
                    cout << "Barcode Text: " << barcodeResultItem->GetText() << endl;
                }
            }
        }

        cout << endl;
    }
};

class MyImageSourceStateListener : public CImageSourceStateListener
{
private:
    CCaptureVisionRouter *m_router;

public:
    MyImageSourceStateListener(CCaptureVisionRouter *router)
    {
        m_router = router;
    }

    virtual void OnImageSourceStateReceived(ImageSourceState state)
    {
        if (state == ISS_EXHAUSTED)
            m_router->StopCapturing();
    }
};

bool GetImagePath(char *pImagePath)
{
    std::string input;
    while (true)
    {
        std::cout << "\n>> Step 1: Input your image file's full path:\n";
        std::getline(std::cin, input);

        input.erase(0, input.find_first_not_of(" \t\n\r\"\'")); // Trim leading
        input.erase(input.find_last_not_of(" \t\n\r\"\'") + 1); // Trim trailing

        if (input == "q" || input == "Q")
        {
            return true; 
        }

        std::strncpy(pImagePath, input.c_str(), 511);
        pImagePath[511] = '\0'; 

        std::ifstream file(pImagePath);
        if (file.good())
        {
            file.close();
            return false; 
        }

        std::cout << "Please input a valid path.\n";
    }
}

int main(int argc, char *argv[])
{
    printf("*************************************************\r\n");
    printf("Welcome to Dynamsoft Barcode Demo\r\n");
    printf("*************************************************\r\n");
    printf("Hints: Please input 'Q' or 'q' to quit the application.\r\n");

    int iRet = -1;
    char szErrorMsg[256];
    iRet = CLicenseManager::InitLicense(LICENSE-KEY, szErrorMsg, 256);
    if (iRet != EC_OK)
    {
        cout << szErrorMsg << endl;
    }
    int errorCode = 1;
    char errorMsg[512] = {0};

    CCaptureVisionRouter *cvr = new CCaptureVisionRouter;
    errorCode = cvr->InitSettings(jsonString.c_str(), errorMsg, 512);
    if (errorCode != EC_OK)
    {
        cout << "error:" << errorMsg << endl;
        return -1;
    }

    char pszImageFile[512] = {0};
    bool bExit = false;
    CImageSourceStateListener *listener = new MyImageSourceStateListener(cvr);
    CFileFetcher *fileFetcher = new CFileFetcher();
    CCapturedResultReceiver *capturedReceiver = new MyCapturedResultReceiver;

    cvr->SetInput(fileFetcher);
    cvr->AddResultReceiver(capturedReceiver);
    cvr->AddImageSourceStateListener(listener);

    while (1)
    {
        bExit = GetImagePath(pszImageFile);
        if (bExit)
            break;
        float costTime = 0.0;
        int errorCode = 0;

        string path = string(pszImageFile);
        fileFetcher->SetFile(pszImageFile);
        errorCode = cvr->StartCapturing(CPresetTemplate::PT_READ_BARCODES, true, errorMsg, 512);
    }

    delete cvr, cvr = NULL, listener, capturedReceiver, fileFetcher;
    return 0;
}
Enter fullscreen mode Exit fullscreen mode

Integrating C++ Barcode Decoding Functionality into a Node.js Addon

We have an existing Node.js barcode SDK project, barcode4nodejs, built with Dynamsoft C++ Barcode SDK v9.x. The following steps outline how to upgrade the underlying C++ barcode decoding functionality to v10.x with minimal changes: no modifications are needed for the JavaScript code, while only a few adjustments are required for the C++ part.

  1. Update the shared libraries in the platforms folder for Windows, Linux and macOS.
  2. Modify the binding.gyp to link the new shared libraries.

    {
        ...
        "targets": [
            {
                ...
                "conditions": [
                    ["OS=='linux'", {
                        "defines": ["LINUX_DBR"],
                        "cflags": ["-std=c++11", "-DNAPI_CPP_EXCEPTIONS", "-fexceptions"],
                        "cflags_cc": ["-std=c++11", "-DNAPI_CPP_EXCEPTIONS", "-fexceptions"],
                        "ldflags": ["-Wl,-rpath,'$$ORIGIN'"],
                        "libraries": [
                            "-lDynamsoftCore", "-lDynamsoftLicense", "-lDynamsoftCaptureVisionRouter", "-lDynamsoftUtility", "-L../platforms/linux/<(arch)"
                        ],
                        "copies": [
                            {
                                "destination": "build/Release/",
                                "files": [
                                    "./platforms/linux/<(arch)/libDynamicImage.so",
                                    "./platforms/linux/<(arch)/libDynamicPdf.so",
                                    "./platforms/linux/<(arch)/libDynamicPdfCore.so",
                                    "./platforms/linux/<(arch)/libDynamsoftBarcodeReader.so",
                                    "./platforms/linux/<(arch)/libDynamsoftCaptureVisionRouter.so",
                                    "./platforms/linux/<(arch)/libDynamsoftCore.so",
                                    "./platforms/linux/<(arch)/libDynamsoftImageProcessing.so",
                                    "./platforms/linux/<(arch)/libDynamsoftLicense.so",
                                    "./platforms/linux/<(arch)/libDynamsoftUtility.so",
                                ]
                            }
                        ]
                    }],
                    ["OS=='win'", {
                        "defines": ["WINDOWS_DBR", "NAPI_CPP_EXCEPTIONS"],
                        "libraries": [
                            "-l../platforms/windows/DynamsoftCorex64.lib", "-l../platforms/windows/DynamsoftLicensex64.lib", "-l../platforms/windows/DynamsoftCaptureVisionRouterx64.lib", "-l../platforms/windows/DynamsoftUtilityx64.lib"
                        ],
                        "copies": [
                            {
                                "destination": "build/Release/",
                                "files": [
                                    "./platforms/windows/DynamicImagex64.dll",
                                    "./platforms/windows/DynamicPdfCorex64.dll",
                                    "./platforms/windows/DynamicPdfx64.dll",
                                    "./platforms/windows/DynamsoftBarcodeReaderx64.dll",
                                    "./platforms/windows/DynamsoftCaptureVisionRouterx64.dll",
                                    "./platforms/windows/DynamsoftCorex64.dll",
                                    "./platforms/windows/DynamsoftImageProcessingx64.dll",
                                    "./platforms/windows/DynamsoftLicensex64.dll",
                                    "./platforms/windows/DynamsoftUtilityx64.dll",
                                    "./platforms/windows/vcomp140.dll"
                                ]
                            }
                        ]
    
                    }],
                    ["OS=='mac'", {
                        "defines": ["MAC_DBR"],
                        "cflags": ["-std=c++11", "-DNAPI_CPP_EXCEPTIONS"],
                        "cflags_cc": ["-std=c++11", "-DNAPI_CPP_EXCEPTIONS"],
                        "ldflags": ["-Wl,-rpath,@loader_path"],
                        "libraries": [
                            "-lDynamsoftCore", "-lDynamsoftLicense", "-lDynamsoftCaptureVisionRouter", "-lDynamsoftUtility", "-L../platforms/macos"
                        ],
                        "copies": [
                            {
                                "destination": "build/Release/",
                                "files": [
                                    "./platforms/macos/libDynamicImagex64.dylib",
                                    "./platforms/macos/libDynamicPdf.dylib",
                                    "./platforms/macos/libDynamicPdfCore.dylib",
                                    "./platforms/macos/libDynamsoftBarcodeReader.dylib",
                                    "./platforms/macos/libDynamsoftCaptureVisionRouter.dylib",
                                    "./platforms/macos/libDynamsoftCore.dylib",
                                    "./platforms/macos/libDynamsoftImageProcessing.dylib",
                                    "./platforms/macos/libDynamsoftLicense.dylib",
                                    "./platforms/macos/libDynamsoftUtility.dylib",
                                ]
                            }
                        ]
                    }]
                ]
            }
        ]
    }
    
  3. Copy the necessary header files to the src folder.

    DynamsoftBarcodeReader.h
    DynamsoftCaptureVisionRouter.h
    DynamsoftCodeParser.h
    DynamsoftCore.h
    DynamsoftDocumentNormalizer.h
    DynamsoftImageProcessing.h
    DynamsoftLabelRecognizer.h
    DynamsoftLicense.h
    DynamsoftUtility.h
    template.h
    
  4. Add CCaptureVisionRouter *, CFileFetcher *, CImageSourceStateListener *, and MyCapturedResultReceiver * pointers as members of the BarcodeReader class in dbr.h.

    #ifndef DBR_H
    #define DBR_H
    
    #include <napi.h>
    #include <string>
    #include <uv.h>
    #include <vector>
    #include "DynamsoftCaptureVisionRouter.h"
    #include "DynamsoftUtility.h"
    
    using namespace std;
    using namespace dynamsoft::license;
    using namespace dynamsoft::cvr;
    using namespace dynamsoft::dbr;
    using namespace dynamsoft::utility;
    using namespace dynamsoft::basic_structures;
    
    class MyCapturedResultReceiver : public CCapturedResultReceiver
    {
    public:
        vector<CDecodedBarcodesResult *> results;
    
    public:
        virtual void OnDecodedBarcodesReceived(CDecodedBarcodesResult *pResult) override;
    };
    
    typedef enum
    {
        NO_BUFFER,
        FILE_STREAM,
        YUYV_BUFFER,
        BASE64,
        RGB_BUFFER,
    } BufferType;
    
    struct BarcodeWorker
    {
        uv_work_t request;                         
        Napi::FunctionReference callback;          
        int iFormat;                               
        std::string filename;                      
        vector<CDecodedBarcodesResult *> pResults; 
        unsigned char *buffer;
        int size;              
        int errorCode;         
        int width;             
        int height;            
        BufferType bufferType; 
        bool useTemplate;
        int stride;               
        std::string base64string; 
        std::string templateContent;
        int elapsedTime;
        CCaptureVisionRouter *handler;
        MyCapturedResultReceiver *capturedReceiver;
        CFileFetcher *fileFetcher;
    };
    
    class MyImageSourceStateListener : public CImageSourceStateListener
    {
    private:
        CCaptureVisionRouter *m_router;
        BarcodeWorker *m_worker;
    
    public:
        MyImageSourceStateListener(CCaptureVisionRouter *router);
        virtual void OnImageSourceStateReceived(ImageSourceState state) override;
    };
    
    class BarcodeReader : public Napi::ObjectWrap<BarcodeReader>
    {
    ...
    
    private:
        CCaptureVisionRouter *handler;
        CFileFetcher *fileFetcher;
        CImageSourceStateListener *listener;
        MyCapturedResultReceiver *capturedReceiver;
    
        static Napi::FunctionReference constructor;
    
        ...
    };
    
    #endif // DBR_H
    
  5. Update C++ implementation in dbr.cc:

    • Instantiate CCaptureVisionRouter, MyImageSourceStateListener, CFileFetcher, and MyCapturedResultReceiver in the BarcodeReader constructor.

      BarcodeReader::BarcodeReader(const Napi::CallbackInfo &info) : Napi::ObjectWrap<BarcodeReader>(info)
      {
          Napi::Env env = info.Env();
          handler = new CCaptureVisionRouter;
          char errorMsgBuffer[256];
          int ret = handler->InitSettings(jsonString.c_str(), errorMsgBuffer, 256);
          if (ret)
          {
              printf("InitSettings: %s\n", errorMsgBuffer);
          }
      
          listener = new MyImageSourceStateListener(handler);
          fileFetcher = new CFileFetcher();
          handler->SetInput(fileFetcher);
      
          capturedReceiver = new MyCapturedResultReceiver;
          handler->AddResultReceiver(capturedReceiver);
          handler->AddImageSourceStateListener(listener);
      }
      
    • Implement the callback functions to track the image processing lifecycle and store barcode results for later use. Use Retain() to prevent auto-release of results.

      void MyCapturedResultReceiver::OnDecodedBarcodesReceived(CDecodedBarcodesResult *pResult)
      {
          pResult->Retain();
          results.push_back(pResult);
      }
      
      MyImageSourceStateListener::MyImageSourceStateListener(CCaptureVisionRouter *router)
      {
          m_router = router;
      }
      
      void MyImageSourceStateListener::OnImageSourceStateReceived(ImageSourceState state)
      {
          if (state == ISS_EXHAUSTED)
          {
              m_router->StopCapturing();
          }
      }
      
    • Call StartCapturing() in the ProcessImage() function to initiate barcode detection on the built-in thread pool. The main thread will remain blocked until all barcode decoding tasks are complete.

      void BarcodeReader::ProcessImage(BarcodeWorker *worker)
      {
          CCaptureVisionRouter *handler = worker->handler;
          CCapturedResult *result = NULL;
          if (!worker->useTemplate)
          {
              SimplifiedCaptureVisionSettings pSettings = {};
              handler->GetSimplifiedSettings("", &pSettings);
              pSettings.barcodeSettings.barcodeFormatIds = worker->iFormat <= 0 ? BF_ALL : worker->iFormat;
      
              char szErrorMsgBuffer[256];
              handler->UpdateSettings("", &pSettings, szErrorMsgBuffer, 256);
          }
          else
          {
              char errorMessage[256];
              int ret = handler->InitSettings(worker->templateContent.c_str(), errorMessage, 256);
              if (ret)
              {
                  printf("Returned value: %d, error message: %s\n", ret, errorMessage);
              }
          }
      
          int starttime = gettime();
          int ret = 0;
          switch (worker->bufferType)
          {
          case FILE_STREAM:
              if (worker->buffer)
              {
                  worker->fileFetcher->SetFile(worker->buffer, worker->size);
              }
              break;
          case YUYV_BUFFER:
              if (worker->buffer)
              {
                  int width = worker->width, height = worker->height;
                  int size = width * height;
                  int index = 0;
                  unsigned char *data = new unsigned char[size];
                  for (int i = 0; i < size; i++)
                  {
                      data[i] = worker->buffer[index];
                      index += 2;
                  }
                  CImageData *imageData = new CImageData(size, data, width, height, width, IPF_GRAYSCALED);
                  worker->fileFetcher->SetFile(imageData);
                  delete imageData, imageData = NULL;
                  delete[] data, data = NULL;
              }
              break;
          case BASE64:
              if (worker->base64string != "")
              {
                  worker->fileFetcher->SetFile(worker->buffer, worker->size);
              }
              break;
          case RGB_BUFFER:
              if (worker->buffer)
              {
                  int width = worker->width, height = worker->height, stride = worker->stride;
                  ImagePixelFormat format = IPF_RGB_888;
                  if (width == stride)
                  {
                      format = IPF_GRAYSCALED;
                  }
                  else if (width * 3 == stride)
                  {
                      format = IPF_RGB_888;
                  }
                  else if (width * 4 == stride)
                  {
                      format = IPF_ARGB_8888;
                  }
                  CImageData *imageData = new CImageData(stride * height, worker->buffer, width, height, stride, format);
                  worker->fileFetcher->SetFile(imageData);
                  delete imageData, imageData = NULL;
              }
              break;
          default:
              worker->fileFetcher->SetFile(worker->filename.c_str());
          }
      
          char errorMsg[512] = {0};
          int errorCode = worker->handler->StartCapturing("", true, errorMsg, 512);
          if (errorCode != 0)
          {
              printf("StartCapturing: %s\n", errorMsg);
          }
      
          int endtime = gettime();
          int elapsedTime = endtime - starttime;
      
          worker->pResults = worker->capturedReceiver->results;
          worker->errorCode = ret;
          worker->elapsedTime = elapsedTime;
      }
      
    • Use Napi::Object to encapsulate barcode results, making them accessible in the JavaScript layer.

      void BarcodeReader::WrapResults(BarcodeWorker *worker, Napi::Env env, Napi::Object &result)
      {
          vector<CDecodedBarcodesResult *> pResults = worker->pResults;
          Napi::Array barcodeResults = Napi::Array::New(env);
          for (int j = 0; j < pResults.size(); j++)
          {
              CDecodedBarcodesResult *barcodeResult = pResults[j];
      
              if (barcodeResult)
              {
                  CFileImageTag *fileTag = (CFileImageTag *)barcodeResult->GetOriginalImageTag();
                  int count = barcodeResult->GetItemsCount();
      
                  for (int i = 0; i < count; i++)
                  {
                      const CBarcodeResultItem *barcodeResultItem = barcodeResult->GetItem(i);
                      CPoint *points = barcodeResultItem->GetLocation().points;
      
                      Napi::Object res = Napi::Object::New(env);
                      res.Set("format", barcodeResultItem->GetFormatString());
                      res.Set("value", barcodeResultItem->GetText());
                      res.Set("x1", Napi::Number::New(env, points[0][0]));
                      res.Set("y1", Napi::Number::New(env, points[0][1]));
                      res.Set("x2", Napi::Number::New(env, points[1][0]));
                      res.Set("y2", Napi::Number::New(env, points[1][1]));
                      res.Set("x3", Napi::Number::New(env, points[2][0]));
                      res.Set("y3", Napi::Number::New(env, points[2][1]));
                      res.Set("x4", Napi::Number::New(env, points[3][0]));
                      res.Set("y4", Napi::Number::New(env, points[3][1]));
                      res.Set("page", Napi::Number::New(env, fileTag->GetPageNumber()));
                      res.Set("time", Napi::Number::New(env, worker->elapsedTime));
                      res.Set("angle", Napi::Number::New(env, barcodeResultItem->GetAngle()));
                      res.Set("isMirrored", Napi::Number::New(env, barcodeResultItem->IsMirrored()));
                      barcodeResults.Set(i + j * count, res);
                  }
      
                  barcodeResult->Release();
              }
          }
      
          result = barcodeResults;
          worker->pResults.clear();
      }
      

Build the Node.js Addon

Use node-gyp to build the Node.js barcode SDK module.

node-gyp configure
node-gyp build
Enter fullscreen mode Exit fullscreen mode

On macOS, you'll need to run the following commands to ensure the .dylib files are accessible:

    install_name_tool -change @rpath/libDynamsoftCore.dylib @loader_path/libDynamsoftCore.dylib build/Release/dbr.node
    install_name_tool -change @rpath/libDynamsoftLicense.dylib @loader_path/libDynamsoftLicense.dylib build/Release/dbr.node
    install_name_tool -change @rpath/libDynamsoftCaptureVisionRouter.dylib @loader_path/libDynamsoftCaptureVisionRouter.dylib build/Release/dbr.node
    install_name_tool -change @rpath/libDynamsoftUtility.dylib @loader_path/libDynamsoftUtility.dylib build/Release/dbr.node
    install_name_tool -change @rpath/libDynamsoftImageProcessing.dylib @loader_path/libDynamsoftImageProcessing.dylib build/Release/libDynamsoftUtility.dylib
Enter fullscreen mode Exit fullscreen mode

Reading Barcodes from Multi-Page PDFs in Node.js

  1. Create a test.js file with the following code:

    var dbr = require('barcode4nodejs');
    var barcodeTypes = dbr.barcodeTypes;
    var readline = require('readline');
    var fs = require('fs');
    
    dbr.initLicense("LICENSE-KEY");
    
    function decodeFileStreamAsync(fileName) {
      let stats = fs.statSync(fileName);
      let fileSize = stats['size'];
    
      fs.open(fileName, 'r', function (status, fd) {
        if (status) {
          console.log(status.message);
          return;
        }
        let buffer = Buffer.alloc(fileSize);
        fs.read(fd, buffer, 0, fileSize, 0, function (err, bytesRead, data) {
          (async function () {
            try {
              var result = await dbr.decodeFileStreamAsync(buffer, fileSize, barcodeTypes, "");
              console.log(result);
              setTimeout(() => {
                console.log('terminated');
              }, 1000);
            } catch (error) {
              console.log(error);
            }
          })();
        });
      });
    }
    
    let args = process.argv;
    if (args.includes('-f')) {
      let fIndex = args.indexOf('-f');
      if (args[fIndex + 1]) {
        decodeFileStreamAsync(args[fIndex + 1]);
      } else {
        console.log('Please add a file.');
      }
    
    }
    

    You need to replace LICENSE-KEY with your own.

  2. Run the script with the PDF file created earlier.

    node test.js -f multipage.pdf
    

    read barcodes from multipage PDF in Node.js

Source Code

pdf Article's
30 articles in total
Favicon
Transforming Starlight into PDF: experience and insights
Favicon
Intelligent PDF Data Extraction and database creation
Favicon
The Struggle of Finding a Free Excel to PDF Converter: My Journey and Solution
Favicon
Guess what? You can make a game inside a PDF!
Favicon
What is Instafill.ai and why it works?
Favicon
How to Save and Open PDFs in Files App with Shortcuts: Specify Path and Filename for Better Access
Favicon
23 Free Online Tools for PDF/Image Conversion & Data Extraction
Favicon
How to Insert Signatures into PDF Documents with HTML5 and JavaScript
Favicon
Easily Manage Multiple PDFs Simultaneously Using Flutter PDF Viewer
Favicon
How to Generate Invoice PDF in Laravel?
Favicon
Using LangChain to Search Your Own PDF Documents
Favicon
Add hyperlink to any Text to another field of same PDF in Angular
Favicon
๐Ÿš€ Generate Dynamic PDFs in Laravel with DomPDF
Favicon
๐Ÿ›  Build a Professional CV in PDF with Markdown and Hugo
Favicon
Printer Scanners VS Mobile Scanner - Do Printers Still Have a Role?
Favicon
Merge PDFs Recursively - Python
Favicon
Replace Text in PDFs Using Python
Favicon
Top 9 PDF Generator APIs in 2024
Favicon
HTML2PDF.Lib: A melhor forma de converter HTML para PDF com .Net
Favicon
How to Sign PDFs Online for Free with BoldSign
Favicon
How to Detect and Save Documents to PDF with HTML5 and JavaScript
Favicon
uniapp ๅ…ฅ้—จๅฎžๆˆ˜ 19๏ผšๅฐ†ๅ‰็ซฏ้กต้ขๅฏผๅ‡บๆˆpdf
Favicon
Identify and Highlight Spelling Errors in PDFs Using Flutter PDF Viewer
Favicon
Combine PDF Files with PDF API
Favicon
6 Effective Ways to Merge PDF Files Using C#
Favicon
Decoding 1D/2D Barcodes from Multi-Page PDFs Using C++ and Node.js
Favicon
How to add image to PDF in C# (Developer Tutorial)
Favicon
How to Read DataMatrix and Other 1D/2D Barcodes from PDF Files in HTML5 and JavaScript
Favicon
Ferrum Doesnโ€™t Work on Heroku?
Favicon
Unlocking Text from Embedded-Font PDFs: A pytesseract OCR Tutorial

Featured ones: