1, Foreword
Because the working product equipment needs a function of dynamically generating QR code according to the IP address of the equipment. After scanning the QR code, the user can access the web service running in the device, and then configure the relevant information with the mobile phone.
Because our embedded devices use C language, we need to find a more suitable library for QR code generation of C language if we don't want to build wheels from scratch.
There are many libraries on the Internet. Finally, qrencode written by a Japanese God was determined. The library is libqrencode.
qrencode official website: https://fukuchi.org/works/qrencode/
qrencode open source github address: https://github.com/fukuchi/libqrencode
You can see that there are still a lot of people who pay attention to qrencode.
Also from the Internet search, many people have a good evaluation of it. So we decided to use qrencode as our QR code generation library.
There are still very few materials to use qrencode under Linux, and there will always be some strange problems.
When solving problems, most of them are used in combination with QT under windows. So I spent a lot of time solving the problem of using Linux. This article will describe it in detail.
I wonder why I have to use QT. Almost all articles from Baidu are the same. I just want to write a different one.
2, Prepare the environment and version information used
1. Ubuntu and kernel versions
I also did experiments on the Ubuntu 20 version, no problem
zh@zh:~$ uname -a Linux zh 4.18.0-15-generic #16~18.04.1-Ubuntu SMP Thu Feb 7 14:06:04 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux zh@zh:~$
2. gcc and g + + versions
I have done experiments on Ubuntu 20. gcc and g + + are both 9 X no problem at all.
zh@zh:~$ gcc --version gcc (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. zh@zh:~$ zh@zh:~$ zh@zh:~$ g++ --version g++ (Ubuntu 7.4.0-1ubuntu1~18.04.1) 7.4.0 Copyright (C) 2017 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. zh@zh:~$
3. Cross compile gcc and g + + versions
I won't introduce how to install it. You should be an old hand when you see this article.
Because my own development board is based on ARM architecture, I installed the cross compilation tool of arm architecture.
zh@zh:~$ arm arm2hpdl arm-linux-gnueabihf-gcc-6.2.1 arm-linux-gnueabihf-ld.gold arm-linux-gnueabihf-addr2line arm-linux-gnueabihf-gcc-ar arm-linux-gnueabihf-nm arm-linux-gnueabihf-ar arm-linux-gnueabihf-gcc-nm arm-linux-gnueabihf-objcopy arm-linux-gnueabihf-as arm-linux-gnueabihf-gcc-ranlib arm-linux-gnueabihf-objdump arm-linux-gnueabihf-c++ arm-linux-gnueabihf-gcov arm-linux-gnueabihf-ranlib arm-linux-gnueabihf-c++filt arm-linux-gnueabihf-gcov-tool arm-linux-gnueabihf-readelf arm-linux-gnueabihf-cpp arm-linux-gnueabihf-gdb arm-linux-gnueabihf-size arm-linux-gnueabihf-dwp arm-linux-gnueabihf-gfortran arm-linux-gnueabihf-strings arm-linux-gnueabihf-elfedit arm-linux-gnueabihf-gprof arm-linux-gnueabihf-strip arm-linux-gnueabihf-g++ arm-linux-gnueabihf-ld arm-linux-gnueabihf-gcc arm-linux-gnueabihf-ld.bfd zh@zh:~$ zh@zh:~$ zh@zh:~$ arm-linux-gnueabihf-gcc --version arm-linux-gnueabihf-gcc (Linaro GCC 6.2-2016.11) 6.2.1 20161016 Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. zh@zh:~$ zh@zh:~$ arm-linux-gnueabihf-g++ --version arm-linux-gnueabihf-g++ (Linaro GCC 6.2-2016.11) 6.2.1 20161016 Copyright (C) 2016 Free Software Foundation, Inc. This is free software; see the source for copying conditions. There is NO warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. zh@zh:~$ zh@zh:~$
4. Development board information
I bought 100ask from Mr. Wei Dongshan's Taobao store some time ago_ Imx6ull Pro development board.
It looks like this: it is based on arm architecture.
The kernel version of the development board is as follows:
[root@100ask:~]# uname -a Linux 100ask 4.9.88 #1 SMP PREEMPT Sat Jul 24 07:41:11 EDT 2021 armv7l GNU/Linux [root@100ask:~]#
3, Compiling & installing qrencode in development environment
1. Download qrencode source code
Open: https://fukuchi.org/works/qrencode/
Now the latest is 4.1 1 version:
After downloading:
2. Upload to Linux
You can use the FileZilla tool and any tool that can be uploaded to Linux.
After uploading:
zh@zh:~$ ls -al qrencode-4.1.1.tar.gz -rw-rw-r-- 1 zh zh 543245 Aug 7 10:36 qrencode-4.1.1.tar.gz zh@zh:~$
Extract:
zh@zh:~$ tar zxvf qrencode-4.1.1.tar.gz
3. Compilation and installation
Because we are now compiling and installing in the development environment, we can ignore some configuration information and directly default.
to configure:
zh@zh:~/qrencode-4.1.1$ ./configure
compile:
zh@zh:~/qrencode-4.1.1$ make
Installation:
zh@zh:~/qrencode-4.1.1$ sudo make install
You can see some directories to install to:
---------------------------------------------------------------------- /bin/mkdir -p '/usr/local/bin' /bin/bash ./libtool --mode=install /usr/bin/install -c qrencode '/usr/local/bin' libtool: install: /usr/bin/install -c .libs/qrencode /usr/local/bin/qrencode /bin/mkdir -p '/usr/local/include' /usr/bin/install -c -m 644 qrencode.h '/usr/local/include' /bin/mkdir -p '/usr/local/share/man/man1' /usr/bin/install -c -m 644 qrencode.1 '/usr/local/share/man/man1' /bin/mkdir -p '/usr/local/lib/pkgconfig' /usr/bin/install -c -m 644 libqrencode.pc '/usr/local/lib/pkgconfig' make[2]: Leaving directory '/home/zh/qrencode-4.1.1' make[1]: Leaving directory '/home/zh/qrencode-4.1.1' zh@zh:~/qrencode-4.1.1$
After installation, you can see:
zh@zh:~/qrencode-4.1.1$ zh@zh:~/qrencode-4.1.1$ ls /usr/local/include/ qrencode.h zh@zh:~/qrencode-4.1.1$ zh@zh:~/qrencode-4.1.1$ zh@zh:~/qrencode-4.1.1$ ls /usr/local/bin/ qrencode zh@zh:~/qrencode-4.1.1$ zh@zh:~/qrencode-4.1.1$ ls /usr/local/lib/ libqrencode.la libqrencode.so libqrencode.so.4 libqrencode.so.4.1.1 pkgconfig python2.7 python3.6 zh@zh:~/qrencode-4.1.1$
I have compiled and installed Ubuntu 18 (GCC v7. X) and Ubuntu 20 (GCC V9. X) without any problems. If you have any questions, you can also discuss them together.
4. Write qrencode test program
Here is a very complete test program that has been tested by me.
Core code: there is only one QRcode_encodeString method
//main.cpp #include <cstdio> #include <cstring> #include <iostream> #include <cmath> #include <cstdlib> #include <qrencode.h> using namespace std; typedef unsigned char BYTE; typedef unsigned short WORD; typedef unsigned int DWORD; //Bitmap file header definition; typedef struct tagBITMAPFILEHEADER { //WORD bfType;// If it is read separately, it is not defined in the structure DWORD bfSize; //file size WORD bfReserved1; //Reserved word WORD bfReserved2; //Reserved word DWORD bfOffBits; //The number of bytes offset from the file header to the actual bitmap data } BITMAPFILEHEADER; typedef struct tagBITMAPINFOHEADER { DWORD biSize; //Header size DWORD biWidth; //Image width DWORD biHeight; //Image height WORD biPlanes; //Number of bit planes, must be 1 WORD biBitCount; //bits per pixel DWORD biCompression; //Compression type DWORD biSizeImage; //Compressed image size bytes DWORD biXPelsPerMeter; //Horizontal resolution DWORD biYPelsPerMeter; //Vertical resolution DWORD biClrUsed; //The number of colors actually used by the bitmap DWORD biClrImportant; //The number of important colors in the standard map } BITMAPINFOHEADER; //Bitmap header definition //Pixel information typedef struct tagIMAGEDATA { BYTE blue; BYTE green; BYTE red; } DATA; int main() { //You can replace it with what you want to set //const char *QRTEXT = "haha,"; //You can also place links to jump const char *QRTEXT = "https://blog.csdn.net/qq_17623363"; QRcode *qrCode; int version = 5; //Set the version number, which is set to 5 here, and the corresponding size is 37 * 37 QRecLevel level = QR_ECLEVEL_H; QRencodeMode hint = QR_MODE_8; int casesensitive = 1; qrCode = QRcode_encodeString(QRTEXT, version, level, hint, casesensitive); if (NULL == qrCode) { printf("QRcode create fail\n"); return -1; } //Save the QR code to be generated as a BMP true color picture file FILE *pf = fopen("qrcode.bmp", "wb"); if (NULL == pf) { printf("file open fail.\n"); fclose(pf); return -1; } int width = qrCode->width; int height = qrCode->width; int biCount = 24; //True color int lineByte = (width * biCount / 8 + 3) / 4 * 4; //Bytes per line must be a multiple of 4 //bitmap-file header BITMAPFILEHEADER bitMapFileHeader; //bitMapFileHeader.bfType = 0x4D42; bitMapFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + lineByte * height; bitMapFileHeader.bfReserved1 = 0; bitMapFileHeader.bfReserved2 = 0; bitMapFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER); //Bitmap header BITMAPINFOHEADER bitMapInfoHeader; bitMapInfoHeader.biBitCount = biCount; bitMapInfoHeader.biClrImportant = 0; bitMapInfoHeader.biClrUsed = 0; bitMapInfoHeader.biCompression = 0; bitMapInfoHeader.biHeight = height; bitMapInfoHeader.biPlanes = 1; bitMapInfoHeader.biSize = 40; bitMapInfoHeader.biSizeImage = lineByte * (height); bitMapInfoHeader.biWidth = width; bitMapInfoHeader.biXPelsPerMeter = 0; bitMapInfoHeader.biYPelsPerMeter = 0; WORD bfType = 0x4D42; //BM type fwrite(&bfType, sizeof(WORD), 1, pf); //Write file header into file fwrite(&bitMapFileHeader, sizeof(BITMAPFILEHEADER), 1, pf); //Write bitmap header into file fwrite(&bitMapInfoHeader, sizeof(BITMAPINFOHEADER), 1, pf); unsigned char *pBMPData = new unsigned char[lineByte * height]; memset(pBMPData, 255, lineByte * height); unsigned char *qrData = qrCode->data; for (int i = 0; i < height; i++) { for (int j = 0; j < lineByte / 3; j++) { if (*(qrData)&1) { //Set rgb color, which can be customized. It is set to black here. *(pBMPData + lineByte * i + 3 * j) = 0; *(pBMPData + lineByte * i + 3 * j + 1) = 0; *(pBMPData + lineByte * i + 3 * j + 2) = 0; } qrData++; } } //Write data into file fwrite(pBMPData, sizeof(unsigned char), lineByte * height, pf); fclose(pf); delete[] pBMPData; pBMPData = NULL; QRcode_free(qrCode); return 0; }
5. Upload the c + + file to Ubuntu
After uploading:
zh@zh:~/qrcode$ ls main.cpp zh@zh:~/qrcode$
compile:
zh@zh:~/qrcode$ g++ main.cpp -o QRTest -I/usr/local/include -L/usr/local/lib -lqrencode zh@zh:~/qrcode$ zh@zh:~/qrcode$ ll -rw-rw-r-- 1 zh zh 4254 Aug 8 03:22 main.cpp -rwxrwxr-x 1 zh zh 13168 Aug 8 03:27 QRTest* zh@zh:~/qrcode$
Execute executable program to generate QR Code:
zh@zh:~/qrcode$ ./QRTest zh@zh:~/qrcode$ zh@zh:~/qrcode$ ll -rw-rw-r-- 1 zh zh 4254 Aug 8 03:22 main.cpp -rw-rw-r-- 1 zh zh 4198 Aug 8 03:27 qrcode.bmp -rwxrwxr-x 1 zh zh 13168 Aug 8 03:27 QRTest* zh@zh:~/qrcode$
qrcode.bmp is the QR code image generated by us. We can download this image to windows and view it; If you are the graphical interface of ubuntu, you can also view it directly.
The following is the QR code image we want:
You can scan and try.
In this way, the development environment is successfully configured!
4, ARM development board porting and testing qrencode
When compiling, we can choose to compile into static library or dynamic library.
The basic knowledge of static library and dynamic library is not discussed in this article, so you need to understand it yourself.
As for the version information of my cross compilation tool, I have already mentioned it, so I won't repeat it here.
1. Compile into dynamic library
#Create a directory to store the path of dynamic library installation, which is convenient for us to find and migrate mkdir /home/zh/libqrencode-arm-so #Unzip the source code tar xvzf qrencode-4.1.1.tar.gz # Enter the extracted qrencode-4.1 1 catalog cd qrencode-4.1.1 # Configure the prefix path and the prefix of the cross compilation tool chain ./configure --prefix=/home/zh/libqrencode-arm-so --host= arm-linux-gnueabihf --without-tools #compile make #install make install
If you don't make mistakes, you will succeed.
If we transplant, we need the following things
zh@zh:~$ ls /home/zh/libqrencode-arm-so/ include lib zh@zh:~$ zh@zh:~$ zh@zh:~$ tree /home/zh/libqrencode-arm-so /home/zh/libqrencode-arm-so ├── include │ └── qrencode.h └── lib ├── libqrencode.la ├── libqrencode.so -> libqrencode.so.4.1.1 ├── libqrencode.so.4 -> libqrencode.so.4.1.1 ├── libqrencode.so.4.1.1 └── pkgconfig └── libqrencode.pc 3 directories, 6 files zh@zh:~$ zh@zh:~$
2. Compile into static library
#Create a directory to store the path of dynamic library installation, which is convenient for us to find and migrate mkdir /home/zh/libqrencode-arm-static #Unzip the source code tar xvzf qrencode-4.1.1.tar.gz # Enter the extracted qrencode-4.1 1 catalog cd qrencode-4.1.1 # Configure the prefix path and the prefix of the cross compilation tool chain ./configure --prefix=/home/zh/libqrencode-arm-static --host=arm-linux-gnueabihf --without-tools --enable-static --disable-shared #compile make #install make install
After successful installation:
zh@zh:~$ ls /home/zh/libqrencode-arm-static/ include lib zh@zh:~$ zh@zh:~$ tree /home/zh/libqrencode-arm-static/ /home/zh/libqrencode-arm-static/ ├── include │ └── qrencode.h └── lib ├── libqrencode.a ├── libqrencode.la └── pkgconfig └── libqrencode.pc 3 directories, 4 files zh@zh:~$
3. Compiling and installing Linux x86
#Configuration, self configurable ./configure #compile make #install make install
4. Cross compile test program
For simplicity and understanding, the Makefile form is not used
zh@zh:~/qrcode$ arm-linux-gnueabihf-g++ -I/home/zh/libqrencode-arm-so/include -c -o main.o main.cpp zh@zh:~/qrcode$ zh@zh:~/qrcode$ zh@zh:~/qrcode$ arm-linux-gnueabihf-g++ -o Qrcode -g main.o -I/home/zh/libqrencode-arm-so/include -L/home/zh/libqrencode-arm-so/lib -lqrencode
After cross compilation, we cannot execute normally on Ubuntu development environment:
zh@zh:~/qrcode$ ls main.cpp Qrcode qrcode.bmp QRTest zh@zh:~/qrcode$ #Cross compiled is not executable zh@zh:~/qrcode$ ./Qrcode -bash: ./Qrcode: cannot execute binary file: Exec format error zh@zh:~/qrcode$ #The original can be executed zh@zh:~/qrcode$ ./QRTest zh@zh:~/qrcode$
You can view the version information:
You can see that QRTest is on x86-64 platform;
Qrcode is the of ARM platform.
zh@zh:~/qrcode$ file QRTest QRTest: ELF 64-bit LSB shared object, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/l, for GNU/Linux 3.2.0, BuildID[sha1]=65e6c48fca725e09171b5cb79924671810e5e7ad, not stripped zh@zh:~/qrcode$ zh@zh:~/qrcode$ zh@zh:~/qrcode$ file Qrcode Qrcode: ELF 32-bit LSB executable, ARM, EABI5 version 1 (SYSV), dynamically linked, interpreter /lib/ld-, for GNU/Linux 2.6.32, BuildID[sha1]=942712d2411951cb747b0dcfed3302993acc8de8, with debug_info, not stripped zh@zh:~/qrcode$ zh@zh:~/qrcode$
4. Taking dynamic library as an example
(1) Copy all files of test code and dynamic library to the development board
I mount an nfs, which is convenient for debugging.
[root@100ask:/mnt]# df Filesystem 1K-blocks Used Available Use% Mounted on /dev/root 1497056 605844 809008 43% / devtmpfs 87344 0 87344 0% /dev tmpfs 251696 0 251696 0% /dev/shm tmpfs 251696 304 251392 1% /tmp tmpfs 251696 512 251184 1% /run 192.168.1.200:/home/zh/nfs_rootfs 277709056 23534592 239997952 9% /mnt [root@100ask:/mnt]# [root@100ask:/mnt]# [root@100ask:/mnt]# pwd /mnt [root@100ask:/mnt]#
Copy the necessary files to the directory of the nfs share:
zh@zh:~$ cp -arf /home/zh/libqrencode-arm-so /home/zh/nfs_rootfs/ zh@zh:~$ zh@zh:~$ cp -arf /home/zh/qrcode /home/zh/nfs_rootfs/ zh@zh:~$
Then we can see on the development board:
[root@100ask:/mnt/qrcode]# ls QRTest Qrcode main.cpp qrcode.bmp [root@100ask:/mnt/qrcode]# [root@100ask:/mnt/qrcode]# ls /mnt/libqrencode-arm-so/ include lib
In order to better test whether it is successful, we delete the original QR code image
[root@100ask:/mnt/qrcode]# rm qrcode.bmp [root@100ask:/mnt/qrcode]# [root@100ask:/mnt/qrcode]# ls Makefile Makefile2 QRTest Qrcode main.cpp [root@100ask:/mnt/qrcode]#
Test successful:
It can be seen that it cannot succeed, and libqrencode is missing so. 4 documents
[root@100ask:/mnt/qrcode]# ./Qrcode ./Qrcode: error while loading shared libraries: libqrencode.so.4: cannot open shared object file: No such file or directory [root@100ask:/mnt/qrcode]#
We copy the cross compiled dynamic library file to the / usr/lib directory on the arm development board:
[root@100ask:/mnt/qrcode]# cp -p /mnt/libqrencode-arm-so/ include/ lib/ [root@100ask:/mnt/qrcode]# cp -p /mnt/libqrencode-arm-so/lib/ libqrencode.la libqrencode.so.4 pkgconfig/ libqrencode.so libqrencode.so.4.1.1 [root@100ask:/mnt/qrcode]# cp -p /mnt/libqrencode-arm-so/lib/libqrencode.so.4 /usr/lib/ [root@100ask:/mnt/qrcode]#
Execute again:
[root@100ask:/mnt/qrcode]# [root@100ask:/mnt/qrcode]# ./Qrcode [root@100ask:/mnt/qrcode]# [root@100ask:/mnt/qrcode]# [root@100ask:/mnt/qrcode]# ls Makefile Makefile2 QRTest Qrcode main.cpp qrcode.bmp [root@100ask:/mnt/qrcode]# [root@100ask:/mnt/qrcode]#
Copy the pictures in the development board to see if they are successful:
Download succeeded
It can be seen that it can be successful:
5, Existing problems
The generated image is too small to find a solution.
It is understood that ffmpeg can be used to solve the problem of image size.
6, References
Installation test related:
https://blog.csdn.net/zb774095236/article/details/107938644/
Migration related:
https://www.cnblogs.com/kuang17/p/7825323.html
Compilation related:
https://blog.csdn.net/u014213012/article/details/51833299