Building JavaScript and WebAssembly ZXing on Windows

If you are looking for a barcode SDK for web development, the ideal outcome is to find a pure JavaScript SDK. The pure JavaScript SDK means JavaScript APIs do not rely on any server-side code. However, most of the barcode SDKs are written in C/C++ and Java. They do not have corresponding JavaScript editions. Meanwhile, JavaScript performance is also the bottleneck. Nowadays, with the advent of WebAssembly, all this will change. WebAssembly runs alongside JavaScript, providing with near-native performance in modern web browsers. In this post, let’s see how to build JavaScript and WebAssembly ZXing – the most popular open source barcode SDK – for developing web barcode apps on Windows.

Emscripten Installation

Emscripten is an LLVM-to-JavaScript compiler, which converts C/C++ into JavaScript.

Download and unzip emsdk-portable-64bit.zip.

Fetch the latest registry of available tools:

emsdk update

Download and install the latest SDK tools:

emsdk install latest

Make the “latest” SDK “active” for the current user:

emsdk activate latest

Activate PATH and other environment variables in the current terminal:

emsdk_env

JavaScript ZXing

Clone the source code https://github.com/kig/zxing-cpp-emscripten.git from GitHub. While following the steps to compile ZXing C++ code, I got some errors:

emscripten libzxing fail

Check CMakeLists.txt to find which line caused the failure:

# Add libzxing library.
file(GLOB_RECURSE LIBZXING_FILES
    "./core/src/*.cpp"
    "./core/src/*.h"
    "./core/src/*.cc"
    "./core/src/*.hh"
)
include_directories("./core/src/")
add_library(libzxing STATIC ${LIBZXING_FILES})
set_target_properties(libzxing PROPERTIES PREFIX "")

This part is to compile ZXing source code to a static library libzxing.bc. If I change STATIC to SHARED, the build will succeed.

I didn’t figure out how to fix this issue. My workaround is to skip the step and build the target zxing.js with ZXing source code directly. Here is the changed script:

# Add libzxing library.
file(GLOB_RECURSE LIBZXING_FILES
    "./core/src/*.cpp"
    "./core/src/*.h"
    "./core/src/*.cc"
    "./core/src/*.hh"
)
include_directories("./core/src/")
# add_library(libzxing STATIC ${LIBZXING_FILES})
# set_target_properties(libzxing PROPERTIES PREFIX "")
add_definitions(-DNO_ICONV=1)

# Add cli executable.
file(GLOB_RECURSE ZXING_FILES
    "./emscripten/zxing.js.cpp"
    "./core/src/*.cpp"
    "./core/src/*.cc"
)
add_executable(zxing ${ZXING_FILES})
target_link_libraries(zxing libzxing)

Now I can successfully make zxing.js (1284K).

How to use zxing.js in web and Node.js apps?

There is a web app example test.html located at emscripten\test.

javascript zxing

By studying the code, we can write a simple Node.js app.

To decode images in Node.js, you can use node-canvas. You must install all dependencies beforehand on Windows.
Install node-canvas:

npm install canvas

Code:

const em_module = require('./zxing.js');
const ZXing = em_module();
const Canvas = require('canvas')
  , Image = Canvas.Image;
const fs = require('fs');

fs.readFile(__dirname + '/Qr-10.png', function(err, squid){
    if (err) throw err;
    img = new Image;
    img.src = squid;

    let width = Math.floor(img.width), height = Math.floor(img.height);
    let canvas = new Canvas(width, height);
    let ctx = canvas.getContext('2d');
    ctx.drawImage(img, 0, 0, width, height);
    var imageData = ctx.getImageData(0, 0, width, height);
    var idd = imageData.data;

    var decodeCallback = function (ptr, len, resultIndex, resultCount) {
      var result = new Uint8Array(ZXing.HEAPU8.buffer, ptr, len);
      console.log(String.fromCharCode.apply(null, result));
    };
    var decodePtr = ZXing.Runtime.addFunction(decodeCallback);

    var image = ZXing._resize(width, height);
    console.time("decode QR");
    for (var i = 0, j = 0; i < idd.length; i += 4, j++) {
      ZXing.HEAPU8[image + j] = idd[i];
    }
    var err = ZXing._decode_qr(decodePtr);
    console.timeEnd('decode QR');

    console.log("error code", err);
  });

WebAssembly ZXing

To build WebAssembly, add a compiler parameter ‘-s WASM=1’. In the meantime, delete parameters ‘-s EXPORT_NAME=\”‘ZXing’\” -s MODULARIZE=1’ according to Emscripten compiling-to-JS parameters.

Edit CMakeLists.txt:

set(CMAKE_CXX_FLAGS "-std=c++11 --bind -Oz -s WASM=1 -s RESERVED_FUNCTION_POINTERS=20 -s DISABLE_EXCEPTION_CATCHING=0 --memory-init-file 0 -s EXPORTED_FUNCTIONS=\"['_resize','_decode_qr','_decode_qr_multi','_decode_any','_decode_multi']\"")

After successfully building the project, you can get zxing.js (154K) and zxing.wasm (566K). The two file size is much smaller than the single JavaScript file.

How to deploy WebAssembly to IIS?

Configure MimeType in web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <staticContent>
            <mimeMap fileExtension=".wasm" mimeType="application/wasm" />
        </staticContent>
    </system.webServer>
</configuration>

Is your wasm file loaded?

Check it via developer tools:

WebAssembly ZXing

Performance Comparison: JavaScript ZXing vs. WebAssembly ZXing

Performance: JavaScript vs WebAssembly

WebAssembly is the winner. Good news is that all major browsers now support WebAssembly.

Source Code

https://github.com/yushulx/zxing-cpp-emscripten

  • Charles Okwuagwu

    Hi. Nice Article. Please how do you have a small example of 1D barcode detection? this seems to work only for QR codes