From 34209651d4570cf717be4f9d7b28b22b06c2ded5 Mon Sep 17 00:00:00 2001 From: Christian Hesse Date: Tue, 9 Jul 2013 17:47:37 +0200 Subject: replace gdk-pixbuf with plain libpng --- Makefile | 6 ++- cqrlogo.c | 175 ++++++++++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 135 insertions(+), 46 deletions(-) diff --git a/Makefile b/Makefile index 855cedb..1e3c2e2 100644 --- a/Makefile +++ b/Makefile @@ -5,11 +5,13 @@ INSTALL := install CP := cp RM := rm CFLAGS += -O2 -Wall -Werror -CFLAGS += $(shell pkg-config --cflags --libs gdk-pixbuf-2.0) \ +CFLAGS += $(shell pkg-config --cflags --libs libpng) \ $(shell pkg-config --cflags --libs libqrencode) +VERSION = $(shell git describe --tags --long) all: cqrlogo.c config.h - $(CC) $(CFLAGS) -o cqrlogo cqrlogo.c + $(CC) $(CFLAGS) -o cqrlogo cqrlogo.c \ + -DVERSION="\"$(VERSION)\"" config.h: $(CP) config.def.h config.h diff --git a/cqrlogo.c b/cqrlogo.c index a5f6d7c..3b243c5 100644 --- a/cqrlogo.c +++ b/cqrlogo.c @@ -8,18 +8,110 @@ #include #include #include +#include #include -#include +#include #include #include "config.h" -GdkPixbuf * encode_qrcode (char *text, int scale, int border) { +/* a bitmap */ +struct bitmap_t { + int width; + int height; + uint8_t *pixel; +}; + +/*** generate_png ***/ +int generate_png (struct bitmap_t *bitmap, char *http_referer) { + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + png_byte ** row_pointers = NULL; + int x, y, depth = 8; + + if ((png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL)) == NULL) + return 1; + + if ((info_ptr = png_create_info_struct (png_ptr)) == NULL || + (setjmp (png_jmpbuf (png_ptr)))) { + png_destroy_write_struct (&png_ptr, &info_ptr); + return 1; + } + + png_set_IHDR (png_ptr, info_ptr, bitmap->width, bitmap->height, depth, + PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + +#ifdef PNG_TEXT_SUPPORTED + png_text text[3]; + + text[0].compression = PNG_TEXT_COMPRESSION_zTXt; + text[0].key = "comment"; + text[0].text = "QR-Code created by cqrlogo - https://github.com/eworm-de/cqrlogo"; + + text[1].compression = PNG_TEXT_COMPRESSION_zTXt; + text[1].key = "version"; + text[1].text = VERSION; + + text[2].compression = PNG_TEXT_COMPRESSION_zTXt; + text[2].key = "referer"; + text[2].text = http_referer; + + png_set_text(png_ptr, info_ptr, text, 3); +#endif + + row_pointers = png_malloc (png_ptr, bitmap->height * sizeof (png_byte *)); + for (y = 0; y < bitmap->height; ++y) { + png_byte *row = png_malloc (png_ptr, sizeof (uint8_t) * bitmap->width); + row_pointers[y] = row; + for (x = 0; x < bitmap->width; ++x) { + *row++ = bitmap->pixel[y * bitmap->width + x]; + } + } + + png_init_io (png_ptr, stdout); + png_set_rows (png_ptr, info_ptr, row_pointers); + png_write_png (png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + for (y = 0; y < bitmap->height; y++) { + png_free (png_ptr, row_pointers[y]); + } + png_free (png_ptr, row_pointers); + + return 0; +} + +/*** bitmap_new ***/ +struct bitmap_t * bitmap_new(int width, int height) { + struct bitmap_t *bitmap; + + if ((bitmap = malloc(sizeof(struct bitmap_t))) == NULL) + return NULL; + + bitmap->width = width; + bitmap->height = height; + if ((bitmap->pixel = malloc(width * height * sizeof(uint8_t))) == NULL) { + free(bitmap); + return NULL; + } + + /* initialize with white */ + memset(bitmap->pixel, 0xff, width * height); + + return bitmap; +} + +/*** bitmap_free ***/ +void bitmap_free(struct bitmap_t * bitmap) { + free(bitmap->pixel); + free(bitmap); +} + +/*** encode_qrcode ***/ +struct bitmap_t * encode_qrcode (char *text, int scale, int border) { QRcode *qrcode; - GdkPixbuf *pixbuf, *pixbuf_scaled; - int i, j, k, rowstride, channels; - guchar *pixel; + struct bitmap_t *bitmap, *scaled; + int i, j, k, l; unsigned char *data; qrcode = QRcode_encodeData(strlen(text), (unsigned char *)text, 0, QRCODE_LEVEL); @@ -29,46 +121,46 @@ GdkPixbuf * encode_qrcode (char *text, int scale, int border) { data = qrcode->data; - pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, FALSE, 8, - qrcode->width + border * 2, qrcode->width + border * 2); - - pixel = gdk_pixbuf_get_pixels (pixbuf); - rowstride = gdk_pixbuf_get_rowstride (pixbuf); - channels = gdk_pixbuf_get_n_channels (pixbuf); - - gdk_pixbuf_fill(pixbuf, 0xffffffff); + /* wirte QR code to bitmap */ + if ((bitmap = bitmap_new(qrcode->width + border * 2, qrcode->width + border * 2)) == NULL) + return NULL; for (i = border; i < qrcode->width + border; i++) for (j = border; j < qrcode->width + border; j++) { - for (k = 0; k < channels; k++) - pixel[i * rowstride + j * channels + k] = !(*data & 0x1) * 0xff; + bitmap->pixel[i * (qrcode->width + border * 2) + j] = !(*data & 0x1) * 0xff; data++; } - pixbuf_scaled = gdk_pixbuf_scale_simple (pixbuf, - (qrcode->width + border * 2) * scale, - (qrcode->width + border * 2) * scale, - GDK_INTERP_NEAREST); - QRcode_free(qrcode); - g_object_unref(pixbuf); + + if (scale == 1) + return bitmap; + + /* scale bitmap */ + if ((scaled = bitmap_new(bitmap->width * scale, bitmap->height * scale)) == NULL) + return NULL; + for (i = 0; i < bitmap->height; i++) + for (j = 0; j < bitmap->width; j++) + for (k = 0; k < scale; k++) + for (l = 0; l < scale; l++) + scaled->pixel[i * bitmap->width * scale * scale + k * bitmap->width * scale + j * scale + l] = + bitmap->pixel[i * bitmap->width + j]; + + + bitmap_free(bitmap); - return pixbuf_scaled; + return scaled; } int main(int argc, char **argv) { char * http_referer, * server_name, * pattern; regex_t preg; regmatch_t pmatch[1]; - int rc = 0, referer = 0; - size_t bytes = 0; + int referer = 0; - GdkPixbuf *pixbuf; + struct bitmap_t * bitmap; char *match = NULL; int scale = QRCODE_SCALE, border = QRCODE_BORDER; - gchar *buffer; - gsize size; - /* get query string for later use */ char * query_string = getenv("QUERY_STRING"); @@ -85,8 +177,10 @@ int main(int argc, char **argv) { /* prepare pattern matching */ pattern = malloc(28 + strlen(server_name)); sprintf(pattern, "^[hH][tT][tT][pP][sS]\\?://%s/", server_name); - if ((rc = regcomp(&preg, pattern, 0)) != 0) - fprintf(stderr, "regcomp() failed, returning nonzero (%d)\n", rc); + if (regcomp(&preg, pattern, 0) != 0) { + fprintf(stderr, "regcomp() failed, returning nonzero\n"); + return EXIT_FAILURE; + } /* check if the QR-Code is for the correct server */ if ((referer = regexec(&preg, http_referer, 1, pmatch, 0)) != 0) { @@ -108,13 +202,8 @@ int main(int argc, char **argv) { sscanf(match, "border=%u", &border); } - /* initialize type system for glib < 2.36 */ -#ifndef GLIB_VERSION_2_36 - g_type_init(); -#endif - - if ((pixbuf = encode_qrcode(http_referer, scale, border)) == NULL) { - if ((pixbuf = encode_qrcode(server_name, scale, border)) == NULL) { + if ((bitmap = encode_qrcode(http_referer, scale, border)) == NULL) { + if ((bitmap = encode_qrcode(server_name, scale, border)) == NULL) { fprintf(stderr, "Could not generate QR-Code.\n"); return EXIT_FAILURE; } @@ -133,16 +222,14 @@ int main(int argc, char **argv) { } /* print PNG data */ - gdk_pixbuf_save_to_buffer (pixbuf, &buffer, &size, "png", NULL, - "compression", "9", - "tEXt::comment", "QR-Code created by cqrlogo - https://github.com/eworm-de/cqrlogo", - "tEXt::referer", http_referer, NULL); - if ((bytes = fwrite (buffer, 1, size, stdout)) != size) - fprintf(stderr, "fwrite() failed, wrote %zu of %zu bytes.\n", bytes, (size_t)size); + if (generate_png(bitmap, http_referer)) { + fprintf(stderr, "Failed to generate PNG.\n"); + return EXIT_FAILURE; + } if (referer) free(http_referer); - g_object_unref(pixbuf); + free(bitmap); return EXIT_SUCCESS; } -- cgit v1.2.3-54-g00ecf