QR码:
QR码是一种高密度矩阵条形码,而quirc是一个用于从图像中提取和解码它们的库。
它具有多种功能,因此非常适合此目的:
1、它足够快,可以用于实时视频:在现代x86内核上,从VGA帧提取和解码大约需要50毫秒
2、它具有鲁棒且宽容的识别算法。它可以正确识别和解码相机旋转和/或倾斜的QR码。它还可以区分和解码同一图像中的多个代码。
3、它易于使用,并且在单个带注释的头文件中描述了一个简单的API(有关概述,请参见下文)。
4、它很小,易于嵌入,除了标准C函数外没有任何依赖关系。
5、它的内存占用非常小:每个图像像素一个字节,每个解码器对象几个kB。
6、它不使用全局可变状态,并且可以在多线程应用程序中安全使用。
7、BSD许可,几乎没有关于使用和/或修改的限制。

库的使用:
	该库的所有功能都通过单个头文件公开,其中应包括:#include <quirc.h>
	
	要解码图像,您需要实例化一个struct quirc对象,这是通过quirc_new函数完成的。以后,当您不再需要解码任何内容时,应使用以下命令释放分配的内存quirc_destroy:
		struct quirc *qr;

		qr = quirc_new();
		if (!qr) {
				perror("Failed to allocate memory");
				abort();
		}

		/* ... */

		quirc_destroy(qr);
		
	获取解码器对象后,您需要设置将要使用的图像大小,可使用quirc_resize以下方法完成:
		if (quirc_resize(qr, 640, 480) < 0) {
			perror("Failed to allocate video memory");
			abort();
		}
	quirc_resize并且quirc_new是唯一的库函数,其分配内存。如果您打算处理一系列帧(或视频流),则可能要分配单个解码器并确定其大小,并保留该解码器以处理每个帧。
		
	处理框架分为两个阶段。第一阶段是称为识别的图像识别阶段,该阶段会拍摄灰度图像并搜索QR码。使用quirc_begin和quirc_end,您可以将灰度图像直接送入quirc用于图像处理的缓冲区中:
		uint8_t *image;
		int w, h;

		image = quirc_begin(qr, &w, &h);

		/* Fill out the image buffer here.
		 * image is a pointer to a w*h bytes.
		 * One byte per pixel, w pixels per line, h lines in the buffer.
		 */

		quirc_end(qr);
		
	注意,quirc_begin仅返回指向先前分配的缓冲区的指针。缓冲区将包含未初始化的数据。呼叫至后quirc_end,解码器会保存一个可通过quirc_count和查询的QR码列表quirc_extract。
		
	此时,处理的第二阶段发生-解码。这是通过调用来完成的,该调用quirc_decode与解码器对象无关。

		int num_codes;
		int i;

		/* We've previously fed an image to the decoder via
		 * quirc_begin/quirc_end.
		 */

		num_codes = quirc_count(qr);
		for (i = 0; i < num_codes; i++) {
				struct quirc_code code;
				struct quirc_data data;
				quirc_decode_error_t err;

				quirc_extract(qr, i, &code);

				/* Decoding stage */
				err = quirc_decode(&code, &data);
				if (err)
						printf("DECODE FAILED: %s\n", quirc_strerror(err));
				else
						printf("Data: %s\n", data.payload);
		}
	quirc_code并且quirc_data是扁平结构,使用后无需初始化或释放。		
	版权所有(C)2010-2012 Daniel Beer < dlbeer@gmail.com >

quirc.文件

#ifndef QUIRC_H_
#define QUIRC_H_

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

struct quirc;

/* Obtain the library version string. */
const char *quirc_version(void);

/* Construct a new QR-code recognizer. This function will return NULL
 * if sufficient memory could not be allocated.
 */
struct quirc *quirc_new(void);

/* Destroy a QR-code recognizer. */
void quirc_destroy(struct quirc *q);

/* Resize the QR-code recognizer. The size of an image must be
 * specified before codes can be analyzed.
 *
 * This function returns 0 on success, or -1 if sufficient memory could
 * not be allocated.
 */
int quirc_resize(struct quirc *q, int w, int h);

/* These functions are used to process images for QR-code recognition.
 * quirc_begin() must first be called to obtain access to a buffer into
 * which the input image should be placed. Optionally, the current
 * width and height may be returned.
 *
 * After filling the buffer, quirc_end() should be called to process
 * the image for QR-code recognition. The locations and content of each
 * code may be obtained using accessor functions described below.
 */
uint8_t *quirc_begin(struct quirc *q, int *w, int *h);
void quirc_end(struct quirc *q);

/* This structure describes a location in the input image buffer. */
struct quirc_point {
	int	x;
	int	y;
};

/* This enum describes the various decoder errors which may occur. */
typedef enum {
	QUIRC_SUCCESS = 0,
	QUIRC_ERROR_INVALID_GRID_SIZE,
	QUIRC_ERROR_INVALID_VERSION,
	QUIRC_ERROR_FORMAT_ECC,
	QUIRC_ERROR_DATA_ECC,
	QUIRC_ERROR_UNKNOWN_DATA_TYPE,
	QUIRC_ERROR_DATA_OVERFLOW,
	QUIRC_ERROR_DATA_UNDERFLOW
} quirc_decode_error_t;

/* Return a string error message for an error code. */
const char *quirc_strerror(quirc_decode_error_t err);

/* Limits on the maximum size of QR-codes and their content. */
#define QUIRC_MAX_BITMAP	3917
#define QUIRC_MAX_PAYLOAD	8896

/* QR-code ECC types. */
#define QUIRC_ECC_LEVEL_M     0
#define QUIRC_ECC_LEVEL_L     1
#define QUIRC_ECC_LEVEL_H     2
#define QUIRC_ECC_LEVEL_Q     3

/* QR-code data types. */
#define QUIRC_DATA_TYPE_NUMERIC       1
#define QUIRC_DATA_TYPE_ALPHA         2
#define QUIRC_DATA_TYPE_BYTE          4
#define QUIRC_DATA_TYPE_KANJI         8

/* Common character encodings */
#define QUIRC_ECI_ISO_8859_1		1
#define QUIRC_ECI_IBM437		2
#define QUIRC_ECI_ISO_8859_2		4
#define QUIRC_ECI_ISO_8859_3		5
#define QUIRC_ECI_ISO_8859_4		6
#define QUIRC_ECI_ISO_8859_5		7
#define QUIRC_ECI_ISO_8859_6		8
#define QUIRC_ECI_ISO_8859_7		9
#define QUIRC_ECI_ISO_8859_8		10
#define QUIRC_ECI_ISO_8859_9		11
#define QUIRC_ECI_WINDOWS_874		13
#define QUIRC_ECI_ISO_8859_13		15
#define QUIRC_ECI_ISO_8859_15		17
#define QUIRC_ECI_SHIFT_JIS		20
#define QUIRC_ECI_UTF_8			26

/* This structure is used to return information about detected QR codes
 * in the input image.
 */
struct quirc_code {
	/* The four corners of the QR-code, from top left, clockwise */
	struct quirc_point	corners[4];

	/* The number of cells across in the QR-code. The cell bitmap
	 * is a bitmask giving the actual values of cells. If the cell
	 * at (x, y) is black, then the following bit is set:
	 *
	 *     cell_bitmap[i >> 3] & (1 << (i & 7))
	 *
	 * where i = (y * size) + x.
	 */
	int			size;
	uint8_t			cell_bitmap[QUIRC_MAX_BITMAP];
};

/* This structure holds the decoded QR-code data */
struct quirc_data {
	/* Various parameters of the QR-code. These can mostly be
	 * ignored if you only care about the data.
	 */
	int			version;
	int			ecc_level;
	int			mask;

/* This field is the highest-valued data type found in the QR
 * code.
 */
int			data_type;

/* Data payload. For the Kanji datatype, payload is encoded as
 * Shift-JIS. For all other datatypes, payload is ASCII text.
 */
uint8_t			payload[QUIRC_MAX_PAYLOAD];
int			payload_len;
/* ECI assignment number */
uint32_t		eci;
};
/* Return the number of QR-codes identified in the last processed
 * image.
 * */
 * int quirc_count(const struct quirc *q);
 * /* Extract the QR-code specified by the given index. */
 * void quirc_extract(const struct quirc *q, int index,
	   struct quirc_code *code);
	   /* Decode a QR-code, returning the payload data. */
	   quirc_decode_error_t quirc_decode(const struct quirc_code *code,
			  struct quirc_data *data);
			  #ifdef __cplusplus
			  }
 #endif
 #endif

quirc.c文件

#include <stdlib.h>
#include <string.h>
#include "quirc_internal.h"

const char *quirc_version(void)
{
	return "1.0";
}

struct quirc *quirc_new(void)
{
	struct quirc *q = malloc(sizeof(*q));

	if (!q)
		return NULL;

	memset(q, 0, sizeof(*q));
	return q;
}

void quirc_destroy(struct quirc *q)
{
	free(q->image);
	/* q->pixels may alias q->image when their type representation is of the
	   same size, so we need to be careful here to avoid a double free */
	if (!QUIRC_PIXEL_ALIAS_IMAGE)
		free(q->pixels);
	free(q);
}

int quirc_resize(struct quirc *q, int w, int h)
{
	uint8_t		*image  = NULL;
	quirc_pixel_t	*pixels = NULL;

	/*
	 * XXX: w and h should be size_t (or at least unsigned) as negatives
	 * values would not make much sense. The downside is that it would break
	 * both the API and ABI. Thus, at the moment, let's just do a sanity
	 * check.
	 */
	if (w < 0 || h < 0)
		goto fail;

	/*
	 * alloc a new buffer for q->image. We avoid realloc(3) because we want
	 * on failure to be leave `q` in a consistant, unmodified state.
	 */
	image = calloc(w, h);
	if (!image)
		goto fail;

	/* compute the "old" (i.e. currently allocated) and the "new"
	   (i.e. requested) image dimensions */
	size_t olddim = q->w * q->h;
	size_t newdim = w * h;
	size_t min = (olddim < newdim ? olddim : newdim);

	/*
	 * copy the data into the new buffer, avoiding (a) to read beyond the
	 * old buffer when the new size is greater and (b) to write beyond the
	 * new buffer when the new size is smaller, hence the min computation.
	 */
	(void)memcpy(image, q->image, min);

	/* alloc a new buffer for q->pixels if needed */
	if (!QUIRC_PIXEL_ALIAS_IMAGE) {
		pixels = calloc(newdim, sizeof(quirc_pixel_t));
		if (!pixels)
			goto fail;
	}

	/* alloc succeeded, update `q` with the new size and buffers */
	q->w = w;
	q->h = h;
	free(q->image);
	q->image = image;
	if (!QUIRC_PIXEL_ALIAS_IMAGE) {
		free(q->pixels);
		q->pixels = pixels;
	}

	return 0;
	/* NOTREACHED */
fail:
	free(image);
	free(pixels);

	return -1;
}

int quirc_count(const struct quirc *q)
{
	return q->num_grids;
}

static const char *const error_table[] = {
	[QUIRC_SUCCESS] = "Success",
	[QUIRC_ERROR_INVALID_GRID_SIZE] = "Invalid grid size",
	[QUIRC_ERROR_INVALID_VERSION] = "Invalid version",
	[QUIRC_ERROR_FORMAT_ECC] = "Format data ECC failure",
	[QUIRC_ERROR_DATA_ECC] = "ECC failure",
	[QUIRC_ERROR_UNKNOWN_DATA_TYPE] = "Unknown data type",
	[QUIRC_ERROR_DATA_OVERFLOW] = "Data overflow",
	[QUIRC_ERROR_DATA_UNDERFLOW] = "Data underflow"
};

const char *quirc_strerror(quirc_decode_error_t err)
{
	if (err >= 0 && err < sizeof(error_table) / sizeof(error_table[0]))
		return error_table[err];

	return "Unknown error";
}
Logo

鸿蒙生态一站式服务平台。

更多推荐