Это простой пример использования библиотеки libqrencode от FUKUCHI Kentaro для генерации bmp-файла с QR-кодом для какого-то текста. В интернете полно ссылок на эту библиотеку, но ни одного примера ее использования. libqrencode
поддерживает QR Code model 2, описанный в JIS (Japanese Industrial Standards) X0510:2004 или ISO/IEC 18004. В настоящее время не поддерживаются режимы ECI и FNC1 QR Code model 1.
Предисловие
QR-код — это двухмерный код, который может быть считан различными устройствами. Сегодня, практически в каждом смартфоне есть QRCode reader. Этот формат поддерживает разные типы данных: url, контакты и т.д. В примере этой статьи закодирован url, который приведет вас в статью в википедии о QR-кодах. Наиболее используемая библиотека для генерации кодов — libqrencode
, но простых примеров ее использования, особенно на С/С++ в сети мало нет. Документация представляет собой просто комментарии в исходном коде. Было написано простое приложение, которое преобразует url в QR-код и сохраняет его в обычном bmp-файле.
Использование кода
Для использования кода, приведенного выше, необходимо скачать библиотеку libqrencode
, ссылка на которую есть в самом начале поста и поместить ее исходники (можно в отдельной папке) в папку с проектом. Итак, простое Win32-приложения для конвертации url в QR-код, которое можно использовать в своих проектах:
#include <stdio.h>
#include <tchar.h>
#include <string.h>
#include <errno.h>
#include <conio.h>
#include <ctype.h>
#include <stddef.h>
#include <stdlib.h>
#include <wchar.h>
#include "qrencode.h" //by libqrencode
#define QRCODE_TEXT "http://ru.wikipedia.org/wiki/QR-%EA%EE%E4" // Text to encode into QRCode
#define OUT_FILE "C:/test.bmp" // Output file name
#define OUT_FILE_PIXEL_PRESCALER 8 // Number of pixels in bmp file for each QRCode pixel, on each dimension
#define PIXEL_COLOR_R 0 // Color of bmp pixels
#define PIXEL_COLOR_G 0
#define PIXEL_COLOR_B 0xff
typedef unsigned short WORD;
typedef unsigned long DWORD;
typedef signed long LONG;
#define BI_RGB 0L
#pragma pack(push, 2)
typedef struct
{
WORD bfType;
DWORD bfSize;
WORD bfReserved1;
WORD bfReserved2;
DWORD bfOffBits;
} BITMAPFILEHEADER;
typedef struct
{
DWORD biSize;
LONG biWidth;
LONG biHeight;
WORD biPlanes;
WORD biBitCount;
DWORD biCompression;
DWORD biSizeImage;
LONG biXPelsPerMeter;
LONG biYPelsPerMeter;
DWORD biClrUsed;
DWORD biClrImportant;
} BITMAPINFOHEADER;
#pragma pack(pop)
int _tmain(int argc, _TCHAR** argv)
{
char* szSourceSring = QRCODE_TEXT;
unsigned int unWidth, x, y, l, n, unWidthAdjusted, unDataBytes;
unsigned char* pRGBData, *pSourceData, *pDestData;
QRcode* pQRC;
FILE* f;
/*
* Создание символа из строки. Библиотека автоматически
* парсит входную строку и кодирует ее в символ QR-кода.
* WARNING: Эта функция THREAD-UNSAFE, когда pthread отключен.
* Параметры:
* string: входная строка; должна завершаться нулем
* version: версия символа; если 0, библиотека выбирает минимальную версию входных данных
* level: уровень коррекции ошибок
* hint: указывает библиотеке на то, как должны кодироваться не алфавитные символы
* QR_MODE_KANJI - иероглифы будут кодироваться как Shif-JIS
* QR_MODE_8 - все не алфавитные символы будут кодироваться как есть. Для UTF-8, выбирайте этот режим
* casesensitive: case-sensitive(1) или нет(0).
* return: экземпляр класса QRcode; при ошибке возвращается NULL и errno устанавливает ошибку
* EINVAL: некорректный входной объект
* ENOMEM: не удается выделить память для входных объектов
* ERANGE: входные данные слишком большие
*/
// Вычисление QRcode
if (pQRC = QRcode_encodeString(szSourceSring, 0, QR_ECLEVEL_H, QR_MODE_8, 1))
{
unWidth = pQRC->width;
unWidthAdjusted = unWidth * OUT_FILE_PIXEL_PRESCALER * 3;
if (unWidthAdjusted % 4)
unWidthAdjusted = (unWidthAdjusted / 4 + 1) * 4;
unDataBytes = unWidthAdjusted * unWidth * OUT_FILE_PIXEL_PRESCALER;
if (!(pRGBData = (unsigned char*)malloc(unDataBytes)))
{
printf("Out of memory");
exit(1);
}
memset(pRGBData, 0xff, unDataBytes);
// Подготовка заголовков bmp
BITMAPFILEHEADER kFileHeader;
kFileHeader.bfType = 0x4d42; // "BM"
kFileHeader.bfSize = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + nDataBytes;
kFileHeader.bfReserved1 = 0;
kFileHeader.bfReserved2 = 0;
kFileHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER);
BITMAPINFOHEADER kInfoHeader;
kInfoHeader.biSize = sizeof(BITMAPINFOHEADER);
kInfoHeader.biWidth = unWidth * OUT_FILE_PIXEL_PRESCALER;
kInfoHeader.biHeight = -((int)unWidth * OUT_FILE_PIXEL_PRESCALER);
kInfoHeader.biPlanes = 1;
kInfoHeader.biBitCount = 24;
kInfoHeader.biCompression = BI_RGB;
kInfoHeader.biSizeImage = 0;
kInfoHeader.biXPelsPerMeter = 0;
kInfoHeader.biYPelsPerMeter = 0;
kInfoHeader.biClrUsed = 0;
kInfoHeader.biClrImportant = 0;
// Конвертирование битов QrCode в bmp пиксели
pSourceData = pQRC->data;
for(y = 0; y < unWidth; y++)
{
pDestData = pRGBData + unWidthAdjusted * y * OUT_FILE_PIXEL_PRESCALER;
for(x = 0; x < unWidth; x++)
{
if (*pSourceData & 1)
for(l = 0; l < OUT_FILE_PIXEL_PRESCALER; l++)
for(n = 0; n < OUT_FILE_PIXEL_PRESCALER; n++)
{
*(pDestData + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_B;
*(pDestData + 1 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_G;
*(pDestData + 2 + n * 3 + unWidthAdjusted * l) = PIXEL_COLOR_R;
}
pDestData += 3 * OUT_FILE_PIXEL_PRESCALER;
pSourceData++;
}
}
if (!(fopen_s(&f, OUT_FILE, "wb")))
{
fwrite(&kFileHeader, sizeof(BITMAPFILEHEADER), 1, f);
fwrite(&kInfoHeader, sizeof(BITMAPINFOHEADER), 1, f);
fwrite(pRGBData, sizeof(unsigned char), unDataBytes, f);
fclose(f);
}
else
{
printf("Unable to open file");
exit(1);
}
free(pRGBData);
QRcode_free(pQRC);
}
else
{
printf("NULL returned");
exit(1);
}
return 0;
}
Изменяя дефайны, можно перекомпилировать программу, для генерации разных url / выходных файлов / размеров пикселей / цветов пикселей.
P.S: Сначала я пытался пользоваться библиотекой, но линковщик не прекращал стрелять ошибками о неразрешенных ссылках, конфликтующих функциях и т.п., поэтому я включил исходный код в проект и скомпилировал все вместе.
Автор: Renzo