Создание QR-кодов на C/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: Сначала я пытался пользоваться библиотекой, но линковщик не прекращал стрелять ошибками о неразрешенных ссылках, конфликтующих функциях и т.п., поэтому я включил исходный код в проект и скомпилировал все вместе.

ссылка на оригинал статьи http://habrahabr.ru/post/182638/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *