libqrencode在生成编码后,如何生成二维码图片。可以通过libpng来生成二维码图片文件。但在在网络通信中,先生成二维码图片文件,再读取文件数据,发送出去,这是一种可行的方法。
但是有没有一种生成二维码图片数据是存放在内存中,而不是以文件形式呢?如果有,这样就不需要生成二维码图片文件后,再次读取文件数据,就可以省略这一步了。
在libpng库 中是可以自己定义写操作的。主要是通过函数png_set_write_fn,关键是需要自己定义写处理函数及相关的数据结构
1、定义数据结构
#define MAX_DATA_LEN 1024
typedef struct BinData
{
char data[MAX_DATA_LEN];
int len;
}BinData;
2、定义写处理函数
static void write_function(png_structp pp, png_bytep data, png_size_t size)
{
BinData *p = (BinData*)png_get_io_ptr(pp);
char *p_data = p->data + p->len;
memcpy(p_data, data, size);
p->len += size;
}
3、测试代码如下(其它还是使用libqrencode中的qrenc.c,只是修改writepng函数)
static int writePNG(QRcode *qrcode, BinData* bindatap)
{
png_structp png_ptr;
png_infop info_ptr;
png_colorp palette;
png_byte alpha_values[2];
unsigned char *row, *p, *q;
int x, y, xx, yy, bit;
int realwidth;
realwidth = (qrcode->width + margin * 2) * size;
row = (unsigned char *)malloc((realwidth + 7) / 8);
if(row == NULL) {
fprintf(stderr, "Failed to allocate memory.\n");
exit(EXIT_FAILURE);
}
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if(png_ptr == NULL) {
fprintf(stderr, "Failed to initialize PNG writer.\n");
exit(EXIT_FAILURE);
}
info_ptr = png_create_info_struct(png_ptr);
if(info_ptr == NULL) {
fprintf(stderr, "Failed to initialize PNG write.\n");
exit(EXIT_FAILURE);
}
if(setjmp(png_jmpbuf(png_ptr))) {
png_destroy_write_struct(&png_ptr, &info_ptr);
fprintf(stderr, "Failed to write PNG image.\n");
exit(EXIT_FAILURE);
}
palette = (png_colorp) malloc(sizeof(png_color) * 2);
if(palette == NULL) {
fprintf(stderr, "Failed to allocate memory.\n");
exit(EXIT_FAILURE);
}
palette[0].red = fg_color[0];
palette[0].green = fg_color[1];
palette[0].blue = fg_color[2];
palette[1].red = bg_color[0];
palette[1].green = bg_color[1];
palette[1].blue = bg_color[2];
alpha_values[0] = fg_color[3];
alpha_values[1] = bg_color[3];
png_set_PLTE(png_ptr, info_ptr, palette, 2);
png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL);
png_set_write_fn(png_ptr, bindatap, write_function, NULL);
png_set_IHDR(png_ptr, info_ptr,
realwidth, realwidth,
1,
PNG_COLOR_TYPE_PALETTE,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_set_pHYs(png_ptr, info_ptr,
dpi * INCHES_PER_METER,
dpi * INCHES_PER_METER,
PNG_RESOLUTION_METER);
png_write_info(png_ptr, info_ptr);
/* top margin */
memset(row, 0xff, (realwidth + 7) / 8);
for(y=0; y<margin * size; y++) {
png_write_row(png_ptr, row);
}
/* data */
p = qrcode->data;
for(y=0; y<qrcode->width; y++) {
bit = 7;
memset(row, 0xff, (realwidth + 7) / 8);
q = row;
q += margin * size / 8;
bit = 7 - (margin * size % 8);
for(x=0; x<qrcode->width; x++) {
for(xx=0; xx<size; xx++) {
*q ^= (*p & 1) << bit;
bit--;
if(bit < 0) {
q++;
bit = 7;
}
}
p++;
}
for(yy=0; yy<size; yy++) {
png_write_row(png_ptr, row);
}
}
/* bottom margin */
memset(row, 0xff, (realwidth + 7) / 8);
for(y=0; y<margin * size; y++) {
png_write_row(png_ptr, row);
}
png_write_end(png_ptr, info_ptr);
png_destroy_write_struct(&png_ptr, &info_ptr);
free(row);
free(palette);
return 0;
}