Generate QR code and write it to a PNG, scaled, in C++
Published: 07-06-2020 | Author: Remy van Elst | Text only version of this article
The QR-Code-Generator library by Project Nayuki for C++ gives you an easy, fast and correct way to generate QR codes. However, you get just a data structure, showing that data is up to you. An example is provided to print the code to a terminal, but not to create and actual image file. For Java, there is an example provided which writes a PNG file, but not for C++.
The author of the library also has another C++ library, Tiny-PNG-Out. It is correct up until 700 megapixel PNG files, which I hope your QR code never hits.
I've written a class which bridges the two together, allowing you to both generate the QR code and write it to a PNG file, scaled up to be as readable as possible.
The code is simple and has comments explaining why things happen. It's easy
to adapt and integrate into your own project, since it does not require any
external dependencies (like
libpng), which, in my case, is
useful due to size limitations on an embedded platform.
Credit where credit is due, all the heavy lifting is done by the two libraries, my class is just a convinience you could write yourself in an hour or so.
Size, scaled up?
A QR code consists out of modules, otherwise known as the black and white dots. The library gives you a data structure where each dot is either a 1 or 0, (black/white). The size of the total QR code is also provided.
It is up to you to scale those up to bigger pixels if required. Since we're writing it to a PNG file using the Tiny PNG Out library, we could just pass the qr data and size, (width/height) and be done with it. That would result in a small, probably unscanable image:
The PNG library needs a
vector of RGB 8.8.8 pixels. That's just the HTML colour scheme
you already know (#FF0000 for red) but in a vector. If we wanted a brown code, we'd make
the black dots
0x8B, 0x45, 0x14 instead of
0x00, 0x00, 0x00:
To make sure the code is readable, I calculate how many times the code fits inside the requested image size. If the QR code reports that it's size is 23, that means, in the context of our png library, we must write 23 modules as one row of pixels, then start a new row. But if you've requested a 600x600px image, that would be way too small.
Therefore the modules are scaled up to the size of the image. So if you've requested a 90x90px image and the qr code reports a size of 29, it will fit inside 90px three times. The resulting image will be 87x87px with a qr module size of 3 (each black/white dot being 3 pixels tall/wide).
You can provide a minimal module pixel size. If you want to encode a small code but want the pixels to be, lets say, at least 2 pixels wide for better scanability, you can ask the class. If it is able to scale up, it will write the file, otherwise it will return false.
The QR code is written row by row, to avoid first constructing a large
vector. This causes
I/O. If you want to change it, it's quite easy. When constructing a
20148x20148 qr code,
RAM usage was around 2 GB when constructing the whole image first and then writing it, but it's
at max 5MB when writing row by row.
Clone this git repository. You get both projects included.
git clone https://github.com/RaymiiOrg/cpp-qr-to-png cd https://github.com/RaymiiOrg/cpp-qr-to-png
Create a build folder:
mkdir build cd build
The binary which writes example files is located in the
Running it should generate 3 example QR codes:
/home/remy/Repo/cpp-qr-to-png/cmake-build-debug/src/qr-to-png Writing Example QR code 1 (normal) to example1.png with text: 'https://raymii.org', size: 300x300, qr module pixel size: 3. Success! Writing Example QR code 2 (tiny) to example2.png with text: 'https://raymii.org', size: 40x40, qr module pixel size: 1. Success! Writing Example QR code 3 (huge) to example3.png with text: 'https://raymii.org', size: 1080x1080, qr module pixel size: 20. Success!
However, the built version of this program is not very usefull, it's about the code itself.
src/main.cpp you will find 4 examples on how to use the class. Here is
auto exampleQrPng1 = QrToPng("example1.png", 300, 3, "https://raymii.org", true, qrcodegen::QrCode::Ecc::MEDIUM); exampleQrPng1.writeToPNG()
Which results in the below image as
Copyright (c) 2020 Remy van Elst (https://raymii.org) License: GNU GPLv3
QR Code generator:
https://github.com/nayuki/QR-Code-generator Copyright (c) 2020 Project Nayuki. (MIT License) https://www.nayuki.io/page/qr-code-generator-library
Tiny PNG Out:
https://www.nayuki.io/page/tiny-png-output GPL v3 or LGPL v3
Licenses are also includes in the