Several years ago I used ZInt in a project and wrote a post on how to generate barcodes from within C++.

Recently, I had a new project where I needed to generate barcodes, and found that things haven't changed much over the last few years. I did come across Project Nayuki's C++ QR code generator which works quite well, and wrote a quick piece on how to combine it with OpenCV.

But, Project Nayuki's C++ QR code generator will only generate QR codes, and I needed support for several types of barcodes. So I'm once again going to use ZInt's C API from within my C++ codebase.


Getting ZInt installed on Ubuntu is almost trivial. The CMake file is misisng just a few lines required to use CPack, which is my only complaint. Mostly because I don't want to run sudo make install, I'd much rather use the standard package manager. So this is what I did:

cd ~/src/ git clone git@github.com:zint/zint.git cd zint mkdir build cd build make -j4 make package sudo dpkg -i zint-package-

I submitted a change to the project to include the lines required for make package to run, but in case it somehow doesn't make it into the project, these are the lines I added to the very bottom of the CMakeLists.txt file:


Of course, if you're using a distro that uses RPM files, change the CPACK_GENERATOR line so it says "RPM" instead of "DEB".

Once you install the package, you'll now have /usr/local/lib/libzint.so and /usr/local/include/zint.h.

Using libzint

The code I have in my previous 2019 post about ZInt still works, but there are a few things I'd change. First, I would use a std::unique_ptr with a custom deleter to ensure the ZInt object cannot leak. And when converting the barcode bitmap to OpenCV, there is no need to traverse the bitmap pixel-by-pixel. OpenCV has cv::Mat constructors that can easily point to existing memory locations. Makes the process much easier, cleaner, and probably faster.

Here is how you can generate a barcode, and then use it in OpenCV:

#include <zint.h> // ... std::unique_ptr<zint_symbol, decltype(&ZBarcode_Delete)> zint(ZBarcode_Create(), ZBarcode_Delete); zint->scale = 5.0f; zint->symbology = BARCODE_QRCODE; zint->output_options |= BARCODE_QUIET_ZONES; std::strcpy(zint->bgcolor, "7799FF"); // mostly blue ZBarcode_Encode_and_Buffer(zint.get(), reinterpret_cast<const unsigned char*>("testing"), 0, 0); // the OpenCV mat will point to this memory location, it does not do a deep copy! cv::Mat mat(zint->bitmap_height, zint->bitmap_width, CV_8UC3, zint->bitmap); // ZInt of course uses RGB, while OpenCV expects BGR. If the barcode // generated is pure black-and-white, then there is nothing that needs // to be fixed. But if there is any colour in the barcode, swapping // the blue and red channels is necessary for it to look correct. cv::cvtColor(mat, mat, cv::COLOR_RGB2BGR);

The code above would generate a barcode that looks like this:

QR code

There are many options, and way too many barcode types to list here. See the ZInt documentation for details.

Last modified: 2023-11-05
Stéphane Charette, stephanecharette@gmail.com