From 559eb9633e1f97d70112f02538ae5e9a0e46f4d5 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sun, 27 Sep 2009 16:31:03 +0900 Subject: bitmap handling routines --- lpg/libqr/Makefile | 4 +- lpg/libqr/code-common.c | 7 ++- lpg/libqr/code-common.h | 6 +-- lpg/libqr/code-create.c | 7 ++- lpg/libqr/code-layout.c | 4 +- lpg/libqr/code-render.c | 119 ------------------------------------------- lpg/libqr/qr-bitmap-pbm.c | 47 +++++++++++++++++ lpg/libqr/qr-bitmap-render.c | 118 ++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/qr-bitmap.c | 70 +++++++++++++++++++++++++ lpg/libqr/qr-bitmap.h | 29 +++++++++++ lpg/libqr/qr/code.h | 8 --- lpg/libqr/test.c | 2 +- 12 files changed, 281 insertions(+), 140 deletions(-) delete mode 100644 lpg/libqr/code-render.c create mode 100644 lpg/libqr/qr-bitmap-pbm.c create mode 100644 lpg/libqr/qr-bitmap-render.c create mode 100644 lpg/libqr/qr-bitmap.c create mode 100644 lpg/libqr/qr-bitmap.h (limited to 'lpg') diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index e9783f6..1571de4 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -3,10 +3,12 @@ OBJECTS := bitstream.o \ code-create.o \ code-layout.o \ code-parse.o \ - code-render.o \ data-common.o \ data-create.o \ data-parse.o \ + qr-bitmap.o \ + qr-bitmap-pbm.o \ + qr-bitmap-render.o \ rs-encode.o CFLAGS := -std=c89 -pedantic -I. -Wall diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index 25c1115..32f6492 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -2,11 +2,14 @@ #include #include "code-common.h" +#include "qr-bitmap.h" void qr_code_destroy(struct qr_code * code) { - free(code->modules); - free(code); + if (code) { + qr_bitmap_destroy(code->modules); + free(code); + } } int qr_code_width(const struct qr_code * code) diff --git a/lpg/libqr/code-common.h b/lpg/libqr/code-common.h index 17a45d7..fce8dce 100644 --- a/lpg/libqr/code-common.h +++ b/lpg/libqr/code-common.h @@ -3,11 +3,11 @@ #include #include "bitstream.h" +#include "qr-bitmap.h" struct qr_code { - int format; - unsigned char * modules; - size_t line_stride; + int format; + struct qr_bitmap * modules; }; int code_side_length(int format); diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index a462ea3..5c0f2b7 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -29,10 +29,10 @@ static void x_dump(struct bitstream * bits) static void setpx(struct qr_code * code, int x, int y) { - size_t off = y * code->line_stride + x / CHAR_BIT; + size_t off = y * code->modules->stride + x / CHAR_BIT; unsigned char bit = 1 << (x % CHAR_BIT); - code->modules[off] |= bit; + code->modules->bits[off] |= bit; } static void draw_locator(struct qr_code * code, int x, int y) @@ -209,8 +209,7 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, dim = code_side_length(data->format); code->format = data->format; - code->line_stride = dim / CHAR_BIT + ((dim % CHAR_BIT) ? 1 : 0); - code->modules = calloc(dim * code->line_stride, sizeof(unsigned char)); + code->modules = qr_bitmap_create(dim, dim, 0); if (!code->modules) goto fail; diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 228758a..09f29a8 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -36,8 +36,8 @@ static int is_data_bit(const struct qr_iterator * i) static void set_pointer(struct qr_iterator * i) { i->mask = 1 << (i->column % CHAR_BIT); - i->p = i->code->modules - + i->code->line_stride * i->row + i->p = i->code->modules->bits + + i->code->modules->stride * i->row + i->column / CHAR_BIT; } diff --git a/lpg/libqr/code-render.c b/lpg/libqr/code-render.c deleted file mode 100644 index cdffe24..0000000 --- a/lpg/libqr/code-render.c +++ /dev/null @@ -1,119 +0,0 @@ -#include -#include -#include -#include - -#include "code-common.h" - -/* CHAR_BIT | mod_bits (multi-byte) */ -static void render_line_1(unsigned char * out, - const unsigned char * in, - size_t mod_bits, - size_t dim, - unsigned long mark, - unsigned long space) -{ - unsigned char in_mask; - size_t n, b; - - in_mask = 1; - n = dim; - - while (n-- > 0) { - unsigned long v = (*in & in_mask) ? mark : space; - - if ((in_mask <<= 1) == 0) { - in_mask = 1; - ++in; - } - - b = mod_bits / CHAR_BIT; - while (b-- > 0) { - *out++ = (unsigned char) v; - v >>= CHAR_BIT; - } - } -} - -/* mod_bits | CHAR_BIT (packed) */ -static void render_line_2(unsigned char * out, - const unsigned char * in, - size_t mod_bits, - size_t dim, - unsigned long mark, - unsigned long space) -{ - unsigned char in_mask; - size_t n, b, step, shift; - - in_mask = 1; - step = CHAR_BIT / mod_bits; - shift = CHAR_BIT - mod_bits; - n = dim; - - while (n > 0) { - unsigned char tmp = 0; - - b = step; - while (b-- > 0) { - unsigned long v = (*in & in_mask) ? mark : space; - - if ((in_mask <<= 1) == 0) { - in_mask = 1; - ++in; - } - - tmp = (tmp >> mod_bits) | (v << shift); - if (--n == 0) { - tmp >>= b * mod_bits; - break; - } - }; - - *out++ = tmp; - } -} - -void qr_code_render(const struct qr_code * code, - void * buffer, - size_t mod_bits, - size_t line_stride, - size_t line_repeat, - unsigned long mark, - unsigned long space) -{ - unsigned char * out; - const unsigned char * in; - size_t n, dim; - int pack; - - pack = (mod_bits < CHAR_BIT); - assert(!pack || (CHAR_BIT % mod_bits == 0)); - assert( pack || (mod_bits % CHAR_BIT == 0)); - - in = code->modules; - out = buffer; - dim = qr_code_width(code); - - n = dim; - while (n-- > 0) { - size_t rpt; - unsigned char * next; - - if (pack) - render_line_2(out, in, mod_bits, dim, mark, space); - else - render_line_1(out, in, mod_bits, dim, mark, space); - - rpt = line_repeat; - next = out + line_stride; - while (rpt-- > 0) { - memcpy(next, out, line_stride); - next += line_stride; - } - - in += code->line_stride; - out = next; - } -} - diff --git a/lpg/libqr/qr-bitmap-pbm.c b/lpg/libqr/qr-bitmap-pbm.c new file mode 100644 index 0000000..3bcddb2 --- /dev/null +++ b/lpg/libqr/qr-bitmap-pbm.c @@ -0,0 +1,47 @@ +#include +#include +#include "qr-bitmap.h" + +int qr_bitmap_write_pbm(const char * path, + const char * comment, + const struct qr_bitmap * bmp) +{ + FILE * out; + size_t count, x, y; + + out = fopen(path, "w"); + if (!out) + return -1; + + count = 0; + + count += fputs("P1\n", out); + + if (comment) + count += fprintf(out, "# %s\n", comment); + + count += fprintf(out, "%u %u\n", + (unsigned)bmp->width, + (unsigned)bmp->height); + + for (y = 0; y < bmp->height; ++y) { + unsigned char * row = bmp->bits + y * bmp->stride; + + for (x = 0; x < bmp->width; ++x) { + int bit = row[x / CHAR_BIT] & (1 << x % CHAR_BIT); + + if (x > 0) + fputc(' ', out); + fputc(bit ? '1' : '0', out); + } + count += fputc('\n', out); + } + + if (ferror(out)) + count = -1; + + fclose(out); + + return count; +} + diff --git a/lpg/libqr/qr-bitmap-render.c b/lpg/libqr/qr-bitmap-render.c new file mode 100644 index 0000000..4f6c921 --- /dev/null +++ b/lpg/libqr/qr-bitmap-render.c @@ -0,0 +1,118 @@ +#include +#include +#include + +#include "qr-bitmap.h" + +/* CHAR_BIT | mod_bits (multi-byte) */ +static void render_line_1(unsigned char * out, + const unsigned char * in, + size_t mod_bits, + size_t dim, + unsigned long mark, + unsigned long space) +{ + unsigned char in_mask; + size_t n, b; + + in_mask = 1; + n = dim; + + while (n-- > 0) { + unsigned long v = (*in & in_mask) ? mark : space; + + if ((in_mask <<= 1) == 0) { + in_mask = 1; + ++in; + } + + b = mod_bits / CHAR_BIT; + while (b-- > 0) { + *out++ = (unsigned char) v; + v >>= CHAR_BIT; + } + } +} + +/* mod_bits | CHAR_BIT (packed) */ +static void render_line_2(unsigned char * out, + const unsigned char * in, + size_t mod_bits, + size_t dim, + unsigned long mark, + unsigned long space) +{ + unsigned char in_mask; + size_t n, b, step, shift; + + in_mask = 1; + step = CHAR_BIT / mod_bits; + shift = CHAR_BIT - mod_bits; + n = dim; + + while (n > 0) { + unsigned char tmp = 0; + + b = step; + while (b-- > 0) { + unsigned long v = (*in & in_mask) ? mark : space; + + if ((in_mask <<= 1) == 0) { + in_mask = 1; + ++in; + } + + tmp = (tmp >> mod_bits) | (v << shift); + if (--n == 0) { + tmp >>= b * mod_bits; + break; + } + }; + + *out++ = tmp; + } +} + +void qr_bitmap_render(const struct qr_bitmap * bmp, + void * buffer, + size_t mod_bits, + size_t line_stride, + size_t line_repeat, + unsigned long mark, + unsigned long space) +{ + unsigned char * out; + const unsigned char * in; + size_t n, dim; + int pack; + + pack = (mod_bits < CHAR_BIT); + assert(!pack || (CHAR_BIT % mod_bits == 0)); + assert( pack || (mod_bits % CHAR_BIT == 0)); + + in = bmp->bits; + out = buffer; + dim = bmp->width; + + n = dim; + while (n-- > 0) { + size_t rpt; + unsigned char * next; + + if (pack) + render_line_2(out, in, mod_bits, dim, mark, space); + else + render_line_1(out, in, mod_bits, dim, mark, space); + + rpt = line_repeat; + next = out + line_stride; + while (rpt-- > 0) { + memcpy(next, out, line_stride); + next += line_stride; + } + + in += bmp->stride; + out = next; + } +} + diff --git a/lpg/libqr/qr-bitmap.c b/lpg/libqr/qr-bitmap.c new file mode 100644 index 0000000..e42b550 --- /dev/null +++ b/lpg/libqr/qr-bitmap.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include +#include "qr-bitmap.h" + +struct qr_bitmap * qr_bitmap_create(int width, int height, int masked) +{ + struct qr_bitmap * out; + size_t size; + + out = malloc(sizeof(*out)); + if (!out) + goto fail; + + out->width = width; + out->height = height; + out->stride = (width / CHAR_BIT) + (width % CHAR_BIT ? 1 : 0); + + size = out->stride * height; + + out->mask = 0; + out->bits = malloc(size); + if (!out->bits) + goto fail; + memset(out->bits, 0, size); + + if (masked) { + out->mask = malloc(out->stride * width); + if (!out->mask) + goto fail; + memset(out->bits, 0xFF, size); + } + + return out; + +fail: + qr_bitmap_destroy(out); + return 0; +} + +void qr_bitmap_destroy(struct qr_bitmap * bmp) +{ + if (bmp) { + free(bmp->bits); + free(bmp->mask); + free(bmp); + } +} + +void qr_bitmap_merge(struct qr_bitmap * dest, const struct qr_bitmap * src) +{ + unsigned char * d, * s, * m; + size_t n; + + assert(dest->stride == src->stride); + assert(dest->height == src->height); + assert(src->mask); + + n = dest->stride * dest->height; + d = dest->bits; + s = src->bits; + m = src->mask; + + while (n--) { + *d &= ~*m; + *d++ |= *s++ & *m++; + } +} + diff --git a/lpg/libqr/qr-bitmap.h b/lpg/libqr/qr-bitmap.h new file mode 100644 index 0000000..d60049a --- /dev/null +++ b/lpg/libqr/qr-bitmap.h @@ -0,0 +1,29 @@ +#ifndef QR_BITMAP_H +#define QR_BITMAP_H + +struct qr_bitmap { + unsigned char * bits; + unsigned char * mask; + size_t stride; + size_t width, height; +}; + +struct qr_bitmap * qr_bitmap_create(int width, int height, int masked); +void qr_bitmap_destroy(struct qr_bitmap *); + +void qr_bitmap_merge(struct qr_bitmap * dest, const struct qr_bitmap * src); + +void qr_bitmap_render(const struct qr_bitmap * bmp, + void * buffer, + size_t mod_bits, + size_t line_stride, + size_t line_repeat, + unsigned long mark, + unsigned long space); + +int qr_bitmap_write_pbm(const char * path, + const char * comment, + const struct qr_bitmap * bmp); + +#endif + diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h index 6ae1aa9..56a9884 100644 --- a/lpg/libqr/qr/code.h +++ b/lpg/libqr/qr/code.h @@ -23,13 +23,5 @@ struct qr_code * qr_code_parse(const void * buffer, size_t line_stride, size_t line_count); -void qr_code_render(const struct qr_code * code, - void * buffer, - size_t mod_bits, - size_t line_stride, - size_t line_repeat, - unsigned long mark, - unsigned long space); - #endif diff --git a/lpg/libqr/test.c b/lpg/libqr/test.c index f51b90b..035908b 100644 --- a/lpg/libqr/test.c +++ b/lpg/libqr/test.c @@ -38,7 +38,7 @@ int main() { char buf[80*25]; int x, y; - qr_code_render(code, buf, 8, 80, 0, 1, 0); + qr_bitmap_render(code->modules, buf, 8, 80, 0, 1, 0); for (y=0;y<21;++y) { printf("\t|"); for (x=0;x<21;++x) { -- cgit v1.2.3-70-g09d2