Создание QR-кодов на C/C++

в 20:47, , рубрики: c++, код, Программирование, метки: ,

image
Это простой пример использования библиотеки 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

Источник

Поделиться

* - обязательные к заполнению поля