summaryrefslogtreecommitdiffstats
path: root/cqrlogo.c
diff options
context:
space:
mode:
Diffstat (limited to 'cqrlogo.c')
-rw-r--r--cqrlogo.c175
1 files changed, 131 insertions, 44 deletions
diff --git a/cqrlogo.c b/cqrlogo.c
index a5f6d7c..3b243c5 100644
--- a/cqrlogo.c
+++ b/cqrlogo.c
@@ -8,18 +8,110 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <inttypes.h>
#include <regex.h>
-#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <png.h>
#include <qrencode.h>
#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;
}