From ef01767c732629b7eff7d1601e76a1bac58f5bfd Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 5 Sep 2009 09:33:22 +0900 Subject: The story so far --- lpg/libqr/.gitignore | 5 + lpg/libqr/Makefile | 25 +++++ lpg/libqr/bitstream.c | 203 +++++++++++++++++++++++++++++++++++++++++ lpg/libqr/bitstream.h | 44 +++++++++ lpg/libqr/code-common.c | 36 ++++++++ lpg/libqr/code-common.h | 19 ++++ lpg/libqr/code-create.c | 121 ++++++++++++++++++++++++ lpg/libqr/code-parse.c | 12 +++ lpg/libqr/code-render.c | 119 ++++++++++++++++++++++++ lpg/libqr/data-common.c | 58 ++++++++++++ lpg/libqr/data-common.h | 19 ++++ lpg/libqr/data-create.c | 223 +++++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/data-parse.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/qr/code.h | 35 +++++++ lpg/libqr/qr/data.h | 34 +++++++ lpg/libqr/qr/types.h | 8 ++ lpg/libqr/test.c | 37 ++++++++ 17 files changed, 1235 insertions(+) create mode 100644 lpg/libqr/.gitignore create mode 100644 lpg/libqr/Makefile create mode 100644 lpg/libqr/bitstream.c create mode 100644 lpg/libqr/bitstream.h create mode 100644 lpg/libqr/code-common.c create mode 100644 lpg/libqr/code-common.h create mode 100644 lpg/libqr/code-create.c create mode 100644 lpg/libqr/code-parse.c create mode 100644 lpg/libqr/code-render.c create mode 100644 lpg/libqr/data-common.c create mode 100644 lpg/libqr/data-common.h create mode 100644 lpg/libqr/data-create.c create mode 100644 lpg/libqr/data-parse.c create mode 100644 lpg/libqr/qr/code.h create mode 100644 lpg/libqr/qr/data.h create mode 100644 lpg/libqr/qr/types.h create mode 100644 lpg/libqr/test.c diff --git a/lpg/libqr/.gitignore b/lpg/libqr/.gitignore new file mode 100644 index 0000000..dbfb6fb --- /dev/null +++ b/lpg/libqr/.gitignore @@ -0,0 +1,5 @@ +*~ +*.o +*.a +*.so +test diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile new file mode 100644 index 0000000..e36b09f --- /dev/null +++ b/lpg/libqr/Makefile @@ -0,0 +1,25 @@ +OBJECTS := bitstream.o \ + code-common.o \ + code-create.o \ + code-parse.o \ + code-render.o \ + data-common.o \ + data-create.o \ + data-parse.o + +CFLAGS := -std=c89 -pedantic -I. -Wall +CFLAGS += -g +#CFLAGS += -O3 -DNDEBUG + +all : libqr test + +$(OBJECTS) : $(wildcard *.h qr/*.h) + +libqr : libqr.a($(OBJECTS)) + +test : libqr.a test.c + +.PHONY : clean +clean: + $(RM) qr/*~ *~ *.o *.a *.so test + diff --git a/lpg/libqr/bitstream.c b/lpg/libqr/bitstream.c new file mode 100644 index 0000000..a2b2b58 --- /dev/null +++ b/lpg/libqr/bitstream.c @@ -0,0 +1,203 @@ +/** + * It would perhaps be more sensible just to store the bits + * as an array of char or similar, but this way is more fun. + * This is a pretty inefficient implementation, althought I + * suspect that won't be a problem. + */ + +#include +#include +#include +#include + +#include "bitstream.h" + +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +struct bitstream { + size_t pos; /* bits */ + size_t count; /* bits */ + size_t bufsiz; /* bytes */ + unsigned char * buffer; +}; + +static size_t bits_to_bytes(size_t bits) +{ + return (bits / CHAR_BIT) + (bits % CHAR_BIT != 0); +} + +static int ensure_available(struct bitstream * stream, size_t bits) +{ + size_t need_bits = stream->pos + bits; + size_t need_bytes = need_bits / CHAR_BIT + ((need_bits % CHAR_BIT) ? 0 : 1); + size_t newsize; + + if (stream->bufsiz >= need_bytes) + return 0; + + newsize = MAX(stream->bufsiz, 100); + while (newsize < need_bytes) + newsize *= 2; + + return bitstream_resize(stream, newsize); +} + +struct bitstream * bitstream_create(void) +{ + struct bitstream * obj; + + obj = malloc(sizeof(*obj)); + + if (obj) { + obj->pos = 0; + obj->count = 0; + obj->bufsiz = 0; + obj->buffer = 0; + } + + return obj; +} + +int bitstream_resize(struct bitstream * stream, size_t bits) +{ + size_t newsize; + void * newbuf; + + newsize = bits_to_bytes(bits); + newbuf = realloc(stream->buffer, newsize); + + if (newbuf) { + stream->bufsiz = newsize; + stream->buffer = newbuf; + } + + return newbuf ? 0 : -1; +} + +void bitstream_destroy(struct bitstream * stream) +{ + free(stream->buffer); + free(stream); +} + +struct bitstream * bitstream_copy(const struct bitstream * src) +{ + struct bitstream * ret; + + ret = bitstream_create(); + if (!ret) + return 0; + + if (bitstream_resize(ret, src->count) != 0) { + free(ret); + return 0; + } + + ret->pos = src->pos; + ret->count = src->count; + memcpy(ret->buffer, src->buffer, src->bufsiz); + + return ret; +} + +void bitstream_seek(struct bitstream * stream, size_t pos) +{ + assert(pos <= stream->count); + stream->pos = pos; +} + +size_t bitstream_tell(const struct bitstream * stream) +{ + return stream->pos; +} + +size_t bitstream_remaining(const struct bitstream * stream) +{ + return stream->count - stream->pos; +} + +size_t bitstream_size(const struct bitstream * stream) +{ + return stream->count; +} + +unsigned int bitstream_read(struct bitstream * stream, size_t bits) +{ + unsigned int result = 0; + unsigned char * byte; + size_t bitnum; + + assert(bitstream_remaining(stream) >= bits); + + byte = stream->buffer + (stream->pos / CHAR_BIT); + bitnum = stream->pos % CHAR_BIT; + + stream->pos += bits; + + while (bits-- > 0) { + int bit = (*byte >> bitnum++) & 0x1; + result = (result << 1) | bit; + if (bitnum == CHAR_BIT) { + bitnum = 0; + ++byte; + } + } + + return result; +} + +void bitstream_unpack(struct bitstream * stream, + unsigned int * result, + size_t count, + size_t bitsize) +{ + assert(bitstream_remaining(stream) >= (count * bitsize)); + + while (count--) + *(result++) = bitstream_read(stream, bitsize); +} + +int bitstream_write(struct bitstream * stream, + unsigned int value, + size_t bits) +{ + unsigned char * byte; + size_t bitnum; + + if (ensure_available(stream, bits) != 0) + return -1; + + byte = stream->buffer + (stream->pos / CHAR_BIT); + bitnum = stream->pos % CHAR_BIT; + + stream->pos += bits; + stream->count = stream->pos; /* truncate */ + + while (bits-- > 0) { + int bit = (value >> bits) & 0x1; + unsigned char mask = 1 << bitnum++; + *byte = (*byte & ~mask) | (bit ? mask : 0); + if (bitnum == CHAR_BIT) { + bitnum = 0; + ++byte; + } + } + + return 0; +} + +int bitstream_pack(struct bitstream * stream, + const unsigned int * values, + size_t count, + size_t bitsize) +{ + if (ensure_available(stream, count * bitsize) != 0) + return -1; + + while (count--) + bitstream_write(stream, *(values++), bitsize); + + return 0; +} + diff --git a/lpg/libqr/bitstream.h b/lpg/libqr/bitstream.h new file mode 100644 index 0000000..12412bc --- /dev/null +++ b/lpg/libqr/bitstream.h @@ -0,0 +1,44 @@ +#ifndef QR_BITSTREAM_H +#define QR_BITSTREAM_H + +#include + +/** + * Note: when writing / reading multiple bits, the + * _most_ significant bits come first in the stream. + * (That is, the order you would naturally write the + * number in binary) + */ + +struct bitstream; + +struct bitstream * bitstream_create(void); +int bitstream_resize(struct bitstream *, size_t bits); +void bitstream_destroy(struct bitstream *); +struct bitstream * bitstream_copy(const struct bitstream *); + +void bitstream_seek(struct bitstream *, size_t pos); +size_t bitstream_tell(const struct bitstream *); +size_t bitstream_remaining(const struct bitstream *); +size_t bitstream_size(const struct bitstream *); + +unsigned int bitstream_read(struct bitstream *, size_t bits); + +void bitstream_unpack(struct bitstream *, + unsigned int * result, + size_t count, + size_t bitsize); + +int bitstream_write(struct bitstream *, + unsigned int value, + size_t bits); + +int bitstream_pack(struct bitstream *, + const unsigned int * values, + size_t count, + size_t bitsize); + +int bitstream_cat(struct bitstream *, const struct bitstream * src); + +#endif + diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c new file mode 100644 index 0000000..08b16df --- /dev/null +++ b/lpg/libqr/code-common.c @@ -0,0 +1,36 @@ +#include +#include + +#include "code-common.h" + +void qr_code_destroy(struct qr_code * code) +{ + free(code->modules); + free(code); +} + +int qr_code_width(const struct qr_code * code) +{ + return code_side_length(code->format); +} + +int code_side_length(int format) +{ + return format * 4 + 17; +} + +int code_finder_count(int format) +{ + int x = format / 7; + return format > 1 ? x*x + 4*x + 1 : 0; +} + +size_t code_total_capacity(int format) +{ + /* XXX: figure out the "correct" formula */ + return 160 + + 25 * code_finder_count(format) + - 10 * (format / 7) + + 2 * code_side_length(format); +} + diff --git a/lpg/libqr/code-common.h b/lpg/libqr/code-common.h new file mode 100644 index 0000000..52666e6 --- /dev/null +++ b/lpg/libqr/code-common.h @@ -0,0 +1,19 @@ +#ifndef CODE_COMMON_H +#define CODE_COMMON_H + +#include +#include "bitstream.h" + +struct qr_code { + int format; + unsigned char * modules; + size_t line_stride; +}; + +int code_side_length(int format); +int code_finder_count(int format); + +size_t code_total_capacity(int format); + +#endif + diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c new file mode 100644 index 0000000..d09c2fe --- /dev/null +++ b/lpg/libqr/code-create.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#include "code-common.h" +#include "data-common.h" + +#define MIN(a, b) ((b) < (a) ? (b) : (a)) + +#include +static void x_dump(struct bitstream * bits) +{ + size_t i, n; + + bitstream_seek(bits, 0); + n = bitstream_size(bits); + for (i = 0; i < n; ++i) { + printf("%d", bitstream_read(bits, 1)); + if (i % 8 == 7) + printf(" "); + if ((i+1) % (7 * 8) == 0) + printf("\n"); + } + printf("\n"); +} + +static int add_ecc(struct bitstream * bits, int format, enum qr_ec_level ec) +{ + puts("Before ecc:"); + x_dump(bits); + + return -1; +} + +static int pad_data(struct bitstream * bits, size_t limit) +{ + /* This function is not very nice. Sorry. */ + + size_t count, n; + + assert(bitstream_size(bits) <= limit); + + if (bitstream_resize(bits, limit) != 0) + return -1; + + n = bitstream_size(bits); + bitstream_seek(bits, n); + count = limit - n; + + /* First append the terminator (0000) if possible, + * and pad with zeros up to an 8-bit boundary + */ + n = (n + 4) % 8; + if (n != 0) + n = 8 - n; + n = MIN(count, n + 4); + bitstream_write(bits, 0, n); + count -= n; + + assert(count % 8 == 0); /* since data codewords are 8 bits */ + + /* Finally pad with the repeating sequence 11101100 00010001 */ + while (count >= 16) { + bitstream_write(bits, 0xEC11, 16); + count -= 16; + } + if (count > 0) { + assert(count == 8); + bitstream_write(bits, 0xEC, 8); + } + + return 0; +} + +static struct bitstream * make_data(int format, + enum qr_ec_level ec, + struct bitstream * data) +{ + size_t data_bits = 16 * 8 /*XXX*/; + struct bitstream * out; + + out = bitstream_copy(data); + if (!out) + return 0; + + if (pad_data(out, data_bits) != 0) + goto fail; + + if (add_ecc(out, format, ec) != 0) + goto fail; + + return out; +fail: + bitstream_destroy(out); + return 0; +} + +struct qr_code * qr_code_create(enum qr_ec_level ec, + const struct qr_data * data) +{ + struct qr_code * code; + struct bitstream * ecdata; + + code = malloc(sizeof(*code)); + if (!code) + return 0; + + code->format = data->format; + ecdata = make_data(data->format, ec, data->bits); + + if (!ecdata) { + free(code); + return 0; + } + + /* TODO: allocate bitmap; layout */ + + return 0; +} + diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c new file mode 100644 index 0000000..0d3a71d --- /dev/null +++ b/lpg/libqr/code-parse.c @@ -0,0 +1,12 @@ +#include + +#include "code-common.h" + +struct qr_code * qr_code_parse(const void * buffer, + size_t line_bits, + size_t line_stride, + size_t line_count) +{ + return 0; +} + diff --git a/lpg/libqr/code-render.c b/lpg/libqr/code-render.c new file mode 100644 index 0000000..cdffe24 --- /dev/null +++ b/lpg/libqr/code-render.c @@ -0,0 +1,119 @@ +#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/data-common.c b/lpg/libqr/data-common.c new file mode 100644 index 0000000..123e5c4 --- /dev/null +++ b/lpg/libqr/data-common.c @@ -0,0 +1,58 @@ +#include +#include + +#include "bitstream.h" +#include "data-common.h" + +const enum qr_data_type QR_TYPE_CODES[16] = { + QR_DATA_INVALID, /* 0000 */ + QR_DATA_NUMERIC, /* 0001 */ + QR_DATA_ALPHA, /* 0010 */ + QR_DATA_MIXED, /* 0011 */ + QR_DATA_8BIT, /* 0100 */ + QR_DATA_FNC1, /* 0101 */ + QR_DATA_INVALID, /* 0110 */ + QR_DATA_ECI, /* 0111 */ + QR_DATA_KANJI, /* 1000 */ + QR_DATA_FNC1, /* 1001 */ + QR_DATA_INVALID, /* 1010 */ + QR_DATA_INVALID, /* 1011 */ + QR_DATA_INVALID, /* 1100 */ + QR_DATA_INVALID, /* 1101 */ + QR_DATA_INVALID, /* 1110 */ + QR_DATA_INVALID, /* 1111 */ +}; + +void qr_free_data(struct qr_data * data) +{ + bitstream_destroy(data->bits); + free(data); +} + +size_t get_size_field_length(int format, enum qr_data_type type) +{ + static const size_t QR_SIZE_LENGTHS[3][4] = { + { 10, 9, 8, 8 }, + { 12, 11, 16, 10 }, + { 14, 13, 16, 12 } + }; + int row, col; + + switch (type) { + case QR_DATA_NUMERIC: col = 0; break; + case QR_DATA_ALPHA: col = 1; break; + case QR_DATA_8BIT: col = 2; break; + case QR_DATA_KANJI: col = 3; break; + default: return 0; + } + + if (format < 10) + row = 0; + else if (format < 27) + row = 1; + else + row = 2; + + return QR_SIZE_LENGTHS[row][col]; +} + diff --git a/lpg/libqr/data-common.h b/lpg/libqr/data-common.h new file mode 100644 index 0000000..d5f6e45 --- /dev/null +++ b/lpg/libqr/data-common.h @@ -0,0 +1,19 @@ +#ifndef DATA_COMMON_H +#define DATA_COMMON_H + +#include + +#include "bitstream.h" + +struct qr_data { + int format; /* 1 ~ 40 */ + struct bitstream * bits; + size_t offset; +}; + +extern const enum qr_data_type QR_TYPE_CODES[16]; + +size_t get_size_field_length(int format, enum qr_data_type); + +#endif + diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c new file mode 100644 index 0000000..2910997 --- /dev/null +++ b/lpg/libqr/data-create.c @@ -0,0 +1,223 @@ +/** + * Not "pure" C - only works with ASCII + */ + +/** XXX: check that the data will fit! **/ +/** NOTE: should store ec type in qr_data **/ + +#include +#include +#include + +#include "bitstream.h" +#include "data-common.h" + +static void write_type_and_length(struct qr_data * data, + enum qr_data_type type, + size_t length) +{ + (void)bitstream_write(data->bits, QR_TYPE_CODES[type], 4); + (void)bitstream_write(data->bits, length, + get_size_field_length(data->format, type)); +} + +static struct qr_data * encode_numeric(struct qr_data * data, + const char * input, + size_t length) +{ + struct bitstream * stream = data->bits; + size_t bits; + + bits = 4 + get_size_field_length(data->format, QR_DATA_NUMERIC) + + 10 * (length / 3); + + if (length % 3 == 1) + bits += 4; + else if (length % 3 == 2) + bits += 7; + + stream = data->bits; + if (bitstream_resize(stream, + bitstream_size(stream) + bits) != 0) + return 0; + + write_type_and_length(data, QR_DATA_NUMERIC, length); + + for (; length >= 3; length -= 3) { + unsigned int x; + + if (!isdigit(input[0]) || + !isdigit(input[1]) || + !isdigit(input[2])) + return 0; + + x = (input[0] - '0') * 100 + + (input[1] - '0') * 10 + + (input[2] - '0'); + bitstream_write(stream, x, 10); + input += 3; + } + + if (length > 0) { + unsigned int x; + + if (!isdigit(*input)) + return 0; + + x = *input++ - '0'; + + if (length == 2) { + if (!isdigit(*input)) + return 0; + x = x * 10 + (*input - '0'); + } + + bitstream_write(stream, x, length == 2 ? 7 : 4); + } + + return data; +} + +static int get_alpha_code(char c) +{ + if (isdigit(c)) + return c - '0'; + else if (isalpha(c)) + return toupper(c) - 'A' + 10; + + switch (c) { + case ' ': return 36; + case '$': return 37; + case '%': return 38; + case '*': return 39; + case '+': return 40; + case '-': return 41; + case '.': return 42; + case '/': return 43; + case ':': return 44; + default: return -1; + } +} + +static struct qr_data * encode_alpha(struct qr_data * data, + const char * input, + size_t length) +{ + struct bitstream * stream = data->bits; + size_t bits; + + bits = 4 + get_size_field_length(data->format, QR_DATA_ALPHA) + + 11 * (length / 2) + + 6 * (length % 2); + + stream = data->bits; + if (bitstream_resize(stream, + bitstream_size(stream) + bits) != 0) + return 0; + + write_type_and_length(data, QR_DATA_ALPHA, length); + + for (; length >= 2; length -= 2) { + unsigned int x; + int c1, c2; + + c1 = get_alpha_code(*input++); + c2 = get_alpha_code(*input++); + + if (c1 < 0 || c2 < 0) + return 0; + + x = c1 * 45 + c2; + bitstream_write(stream, x, 11); + } + + if (length > 0) { + int c = get_alpha_code(*input); + + if (c < 0) + return 0; + + bitstream_write(stream, c, 6); + } + + return data; +} + +static struct qr_data * encode_8bit(struct qr_data * data, + const char * input, + size_t length) +{ + struct bitstream * stream = data->bits; + size_t bits; + + bits = 4 + get_size_field_length(data->format, QR_DATA_8BIT) + + 8 * length; + + stream = data->bits; + if (bitstream_resize(stream, + bitstream_size(stream) + bits) != 0) + return 0; + + write_type_and_length(data, QR_DATA_8BIT, length); + + while (length--) + bitstream_write(stream, *input++, 8); + + return data; +} + +static struct qr_data * encode_kanji(struct qr_data * data, + const char * input, + size_t length) +{ + return 0; +} + +struct qr_data * qr_create_data(int format, + enum qr_data_type type, + const char * input, + size_t length) +{ + struct qr_data * data; + + if (format < 1 || format > 40) + return 0; + + data = malloc(sizeof(*data)); + if (!data) + return 0; + + data->format = format; + data->bits = bitstream_create(); + data->offset = 0; + + if (data->bits) { + struct qr_data * ret; + + switch (type) { + case QR_DATA_NUMERIC: + ret = encode_numeric(data, input, length); break; + case QR_DATA_ALPHA: + ret = encode_alpha(data, input, length); break; + case QR_DATA_8BIT: + ret = encode_8bit(data, input, length); break; + case QR_DATA_KANJI: + ret = encode_kanji(data, input, length); break; + default: + /* unsupported / invalid */ + ret = 0; + break; + } + + if (!ret) { + bitstream_destroy(data->bits); + free(data); + } + + return ret; + } else { + free(data); + return 0; + } +} + diff --git a/lpg/libqr/data-parse.c b/lpg/libqr/data-parse.c new file mode 100644 index 0000000..9129ed7 --- /dev/null +++ b/lpg/libqr/data-parse.c @@ -0,0 +1,237 @@ +#include +#include +#include +#include + +#include "bitstream.h" +#include "data-common.h" + +static enum qr_data_type read_data_type(struct bitstream * stream) +{ + const size_t length = 4; + unsigned int type; + + if (bitstream_remaining(stream) < length) + return QR_DATA_INVALID; + + type = bitstream_read(stream, length); + assert(type < 16); + + return QR_TYPE_CODES[type]; +} + +static enum qr_data_type parse_numeric(const struct qr_data * data, + char ** output, + size_t * length) +{ + struct bitstream * stream; + size_t field_len, bits; + unsigned int digits; + unsigned int chunk; + char * p, * buffer; + + stream = data->bits; + buffer = 0; + + field_len = get_size_field_length(data->format, QR_DATA_NUMERIC); + if (bitstream_remaining(stream) < field_len) + goto invalid; + + digits = bitstream_read(stream, field_len); + + bits = (digits / 3) * 10; + if (digits % 3 == 1) + bits += 4; + else if (digits % 3 == 2) + bits += 7; + + if (bitstream_remaining(stream) < bits) + goto invalid; + + buffer = malloc(digits + 1); + if (!buffer) + goto invalid; + + p = buffer; + + for (; bits >= 10; bits -= 10) { + chunk = bitstream_read(stream, 10); + if (chunk >= 1000) + goto invalid; + sprintf(p, "%03u", chunk); + p += 3; + } + + if (bits > 0) { + chunk = bitstream_read(stream, bits); + if (chunk >= (bits >= 7 ? 100 : 10)) + goto invalid; + sprintf(p, "%0*u", bits >= 7 ? 2 : 1, chunk); + } + + *output = buffer; + *length = digits; + + return QR_DATA_NUMERIC; +invalid: + free(buffer); + return QR_DATA_INVALID; +} + +static enum qr_data_type parse_alpha(const struct qr_data * data, + char ** output, + size_t * length) +{ + static const char charset[45] = + "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; + struct bitstream * stream; + size_t field_len, bits; + unsigned int chars; + unsigned int chunk; + char * p, * buffer; + + stream = data->bits; + buffer = 0; + + field_len = get_size_field_length(data->format, QR_DATA_ALPHA); + if (bitstream_remaining(stream) < field_len) + goto invalid; + + chars = bitstream_read(stream, field_len); + + bits = (chars / 2) * 11; + if (chars % 2 == 1) + bits += 6; + + if (bitstream_remaining(stream) < bits) + goto invalid; + + buffer = malloc(chars + 1); + if (!buffer) + goto invalid; + + p = buffer; + + for (; bits >= 11; bits -= 11) { + unsigned int c1, c2; + chunk = bitstream_read(stream, 11); + c1 = chunk / 45; + c2 = chunk % 45; + if (c1 >= 45) + goto invalid; + *p++ = charset[c1]; + *p++ = charset[c2]; + } + + if (bits > 0) { + chunk = bitstream_read(stream, bits); + if (chunk >= 45) + goto invalid; + *p = charset[chunk]; + } + + *output = buffer; + *length = chars; + + return QR_DATA_ALPHA; +invalid: + free(buffer); + return QR_DATA_INVALID; +} + +static enum qr_data_type parse_8bit(const struct qr_data * data, + char ** output, + size_t * length) +{ + struct bitstream * stream; + size_t field_len; + unsigned int bytes; + char * p; + + stream = data->bits; + + field_len = get_size_field_length(data->format, QR_DATA_8BIT); + if (bitstream_remaining(stream) < field_len) + return QR_DATA_INVALID; + + bytes = bitstream_read(stream, field_len); + + if (bitstream_remaining(stream) < bytes * 8) + return QR_DATA_INVALID; + + *output = malloc(bytes + 1); + if (!*output) + return QR_DATA_INVALID; + + p = *output; + *length = bytes; + + while (bytes-- > 0) + *p++ = bitstream_read(stream, 8); + + *p = '\0'; + + return QR_DATA_8BIT; +} + +static enum qr_data_type parse_kanji(const struct qr_data * data, + char ** output, + size_t * length) +{ + return QR_DATA_INVALID; +} + +enum qr_data_type qr_get_data_type(const struct qr_data * data) +{ + bitstream_seek(data->bits, data->offset); + return read_data_type(data->bits); +} + +int qr_get_data_length(const struct qr_data * data) +{ + size_t field_len; + enum qr_data_type type; + + bitstream_seek(data->bits, data->offset); + + type = read_data_type(data->bits); + + switch (type) { + case QR_DATA_NUMERIC: + case QR_DATA_ALPHA: + case QR_DATA_8BIT: + case QR_DATA_KANJI: + field_len = get_size_field_length(data->format, type); + break; + default: + /* unsupported / invalid */ + return -1; + } + + if (bitstream_remaining(data->bits) < field_len) + return -1; + + return (int) bitstream_read(data->bits, field_len); +} + +enum qr_data_type qr_parse_data(const struct qr_data * input, + char ** output, + size_t * length) +{ + bitstream_seek(input->bits, input->offset); + + switch (read_data_type(input->bits)) { + case QR_DATA_NUMERIC: + return parse_numeric(input, output, length); + case QR_DATA_ALPHA: + return parse_alpha(input, output, length); + case QR_DATA_8BIT: + return parse_8bit(input, output, length); + case QR_DATA_KANJI: + return parse_kanji(input, output, length); + default: + /* unsupported / invalid */ + return QR_DATA_INVALID; + } +} + diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h new file mode 100644 index 0000000..6ae1aa9 --- /dev/null +++ b/lpg/libqr/qr/code.h @@ -0,0 +1,35 @@ +#ifndef QR_CODE_H +#define QR_CODE_H + +#include +#include "types.h" + +enum qr_ec_level { + QR_EC_LEVEL_L, + QR_EC_LEVEL_M, + QR_EC_LEVEL_Q, + QR_EC_LEVEL_H +}; + +struct qr_code * qr_code_create(enum qr_ec_level ec, + const struct qr_data * data); + +void qr_code_destroy(struct qr_code *); + +int qr_code_width(const struct qr_code *); + +struct qr_code * qr_code_parse(const void * buffer, + size_t line_bits, + 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/qr/data.h b/lpg/libqr/qr/data.h new file mode 100644 index 0000000..5fbdded --- /dev/null +++ b/lpg/libqr/qr/data.h @@ -0,0 +1,34 @@ +#ifndef QR_DATA_H +#define QR_DATA_H + +#include +#include "types.h" + +enum qr_data_type { + QR_DATA_INVALID = -1, + QR_DATA_ECI = 7, + QR_DATA_NUMERIC = 1, + QR_DATA_ALPHA = 2, + QR_DATA_8BIT = 4, + QR_DATA_KANJI = 8, /* JIS X 0208 */ + QR_DATA_MIXED = 3, + QR_DATA_FNC1 = 9 +}; + +struct qr_data * qr_create_data(int format, /* 1 ~ 40 */ + enum qr_data_type type, + const char * input, + size_t length); + +void qr_free_data(struct qr_data *); + +enum qr_data_type qr_get_data_type(const struct qr_data *); + +int qr_get_data_length(const struct qr_data *); + +enum qr_data_type qr_parse_data(const struct qr_data * input, + char ** output, + size_t * length); + +#endif + diff --git a/lpg/libqr/qr/types.h b/lpg/libqr/qr/types.h new file mode 100644 index 0000000..bb44cde --- /dev/null +++ b/lpg/libqr/qr/types.h @@ -0,0 +1,8 @@ +#ifndef QR_TYPES_H +#define QR_TYPES_H + +struct qr_data; +struct qr_code; + +#endif + diff --git a/lpg/libqr/test.c b/lpg/libqr/test.c new file mode 100644 index 0000000..76d0b97 --- /dev/null +++ b/lpg/libqr/test.c @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +#include "bitstream.h" + +int main() { + + struct qr_code * code; + struct qr_data * data; + enum qr_data_type type; + char *str; + size_t len; + + type = QR_DATA_NUMERIC; + str = "01234567"; + len = strlen(str); + + data = qr_create_data(1, type, str, len); + assert(data); + assert(qr_get_data_type(data) == type); + assert(qr_get_data_length(data) == len); + + type = qr_parse_data(data, &str, &len); + printf("[%d] %d\n", type, (int)len); + printf("\"%s\"\n", str); + + code = qr_code_create(QR_EC_LEVEL_M, data); + assert(code); + + printf("Code width %d\n", qr_code_width(code)); + + return 0; +} + -- cgit v1.2.3-70-g09d2 From d8f5f47084245b5b2d589d60db316f8943a96c5b Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 5 Sep 2009 17:27:50 +0900 Subject: Correct formula for capacity --- lpg/libqr/code-common.c | 29 ++++++++++++++++++----------- lpg/libqr/code-common.h | 1 - 2 files changed, 18 insertions(+), 12 deletions(-) diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index 08b16df..25c1115 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -19,18 +19,25 @@ int code_side_length(int format) return format * 4 + 17; } -int code_finder_count(int format) -{ - int x = format / 7; - return format > 1 ? x*x + 4*x + 1 : 0; -} - size_t code_total_capacity(int format) { - /* XXX: figure out the "correct" formula */ - return 160 - + 25 * code_finder_count(format) - - 10 * (format / 7) - + 2 * code_side_length(format); + int side = format * 4 + 17; + + int alignment_side = format > 1 ? (format / 7) + 2 : 0; + + int alignment_count = alignment_side >= 2 ? + alignment_side * alignment_side - 3 : 0; + + int locator_bits = 8*8*3; + + int format_bits = 8*4 - 1 + (format >= 7 ? 6*3*2 : 0); + + int timing_bits = 2 * (side - 8*2 - + (alignment_side > 2 ? (alignment_side - 2) * 5 : 0)); + + int function_bits = timing_bits + format_bits + locator_bits + + alignment_count * 5*5; + + return side * side - function_bits; } diff --git a/lpg/libqr/code-common.h b/lpg/libqr/code-common.h index 52666e6..17a45d7 100644 --- a/lpg/libqr/code-common.h +++ b/lpg/libqr/code-common.h @@ -11,7 +11,6 @@ struct qr_code { }; int code_side_length(int format); -int code_finder_count(int format); size_t code_total_capacity(int format); -- cgit v1.2.3-70-g09d2 From 55d8ac4768d03001b746ce0af0ad0e15031e4041 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Tue, 15 Sep 2009 07:56:20 +0900 Subject: RS encode (not working yet) --- lpg/libqr/Makefile | 3 ++- lpg/libqr/code-create.c | 11 ++++++++++- lpg/libqr/rs-encode.c | 47 +++++++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/rs.h | 9 +++++++++ lpg/libqr/test.c | 1 + 5 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 lpg/libqr/rs-encode.c create mode 100644 lpg/libqr/rs.h diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index e36b09f..1f34caf 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -5,7 +5,8 @@ OBJECTS := bitstream.o \ code-render.o \ data-common.o \ data-create.o \ - data-parse.o + data-parse.o \ + rs-encode.o CFLAGS := -std=c89 -pedantic -I. -Wall CFLAGS += -g diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index d09c2fe..484dbe3 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -5,6 +5,7 @@ #include "code-common.h" #include "data-common.h" +#include "rs.h" #define MIN(a, b) ((b) < (a) ? (b) : (a)) @@ -29,7 +30,15 @@ static int add_ecc(struct bitstream * bits, int format, enum qr_ec_level ec) { puts("Before ecc:"); x_dump(bits); - + { + const int g[10] = { 251, 67, 61, 118, 70, 64, 94, 32, 45 }; + int rs_words = 10; /* 1-M */ + struct bitstream * rs; + + rs = rs_generate_words(rs_words, g, bits); + puts("ecc part:"); + x_dump(rs); + } return -1; } diff --git a/lpg/libqr/rs-encode.c b/lpg/libqr/rs-encode.c new file mode 100644 index 0000000..ec99c6b --- /dev/null +++ b/lpg/libqr/rs-encode.c @@ -0,0 +1,47 @@ +#include +#include +#include "bitstream.h" +#include "rs.h" + +struct bitstream * rs_generate_words(int k, const int * coeff, struct bitstream * data) +{ + struct bitstream * ec = 0; + unsigned int * b = 0; + size_t n, i, dlen; + + dlen = bitstream_size(data); + assert(dlen % 8 == 0); + dlen /= 8; + + ec = bitstream_create(); + if (!ec) + return 0; + + if (bitstream_resize(ec, k * 8) != 0) + goto fail; + + b = calloc(k, sizeof(*b)); + if (!b) + goto fail; + + /* First, prepare the registers (b) with data bits. Note that + * the registers are in reverse of the normal order + */ + bitstream_seek(data, 0); + for (n = 0; n < dlen; ++n) { + unsigned int x = b[0] + bitstream_read(data, 8); + for (i = 0; i < k-1; ++i) + b[i] = b[i+1] + coeff[(k-1) - i] * x; + b[k-1] = coeff[0] * x; + } + + /* Read off the registers */ + bitstream_pack(ec, b, k, 8); + + free(b); + return ec; +fail: + bitstream_destroy(ec); + return 0; +} + diff --git a/lpg/libqr/rs.h b/lpg/libqr/rs.h new file mode 100644 index 0000000..98e3aa0 --- /dev/null +++ b/lpg/libqr/rs.h @@ -0,0 +1,9 @@ +#ifndef RS_H +#define RS_H + +#include "bitstream.h" + +struct bitstream * rs_generate_words(int k, const int * coeff, struct bitstream * data); + +#endif + diff --git a/lpg/libqr/test.c b/lpg/libqr/test.c index 76d0b97..ec77bfe 100644 --- a/lpg/libqr/test.c +++ b/lpg/libqr/test.c @@ -5,6 +5,7 @@ #include #include "bitstream.h" +#include "code-common.h" int main() { -- cgit v1.2.3-70-g09d2 From 69b03a15eb048c05b31a5cc6128c27acc77c1dd5 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Tue, 15 Sep 2009 19:03:26 +0900 Subject: Figure out how to encode RS --- lpg/libqr/code-create.c | 4 +-- lpg/libqr/rs-encode.c | 76 ++++++++++++++++++++++++++++++++++++++++--------- lpg/libqr/rs.h | 2 +- 3 files changed, 66 insertions(+), 16 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 484dbe3..389dcd5 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -31,13 +31,13 @@ static int add_ecc(struct bitstream * bits, int format, enum qr_ec_level ec) puts("Before ecc:"); x_dump(bits); { - const int g[10] = { 251, 67, 61, 118, 70, 64, 94, 32, 45 }; int rs_words = 10; /* 1-M */ struct bitstream * rs; - rs = rs_generate_words(rs_words, g, bits); + rs = rs_generate_words(rs_words, bits); puts("ecc part:"); x_dump(rs); + bitstream_destroy(rs); } return -1; } diff --git a/lpg/libqr/rs-encode.c b/lpg/libqr/rs-encode.c index ec99c6b..ea54d77 100644 --- a/lpg/libqr/rs-encode.c +++ b/lpg/libqr/rs-encode.c @@ -3,11 +3,56 @@ #include "bitstream.h" #include "rs.h" -struct bitstream * rs_generate_words(int k, const int * coeff, struct bitstream * data) +static unsigned int gf_mult(unsigned int a, unsigned int b) +{ + /* Reduce modulo x^8 + x^4 + x^3 + x^2 + 1 + * using the peasant's algorithm + */ + const unsigned int m = 0x11D; + unsigned int x = 0; + int i; + + for (i = 0; i < 8; ++i) { + x ^= (b & 0x1) ? a : 0; + a = (a << 1) ^ ((a & 0x80) ? m : 0); + b >>= 1; + } + + return x & 0xFF; +} + +static unsigned int * make_generator(int k) +{ + unsigned int * g; + unsigned int a; + int i, j; + + g = calloc(k, sizeof(*g)); + if (!g) + return 0; + + g[0] = 1; /* Start with g(x) = 1 */ + a = 1; /* 2^0 = 1 */ + + for (i = 0; i < k; ++i) { + /* Multiply our poly g(x) by (x + 2^i) */ + for (j = k - 1; j > 0; --j) + g[j] = gf_mult(g[j], a) ^ g[j-1]; + g[0] = gf_mult(g[0], a); + + a = gf_mult(a, 2); + } + + return g; +} + +struct bitstream * rs_generate_words(int n, struct bitstream * data) { struct bitstream * ec = 0; unsigned int * b = 0; - size_t n, i, dlen; + unsigned int * g; + size_t dlen; + int i, r; dlen = bitstream_size(data); assert(dlen % 8 == 0); @@ -17,30 +62,35 @@ struct bitstream * rs_generate_words(int k, const int * coeff, struct bitstream if (!ec) return 0; - if (bitstream_resize(ec, k * 8) != 0) + if (bitstream_resize(ec, n * 8) != 0) goto fail; - b = calloc(k, sizeof(*b)); + b = calloc(n, sizeof(*b)); if (!b) goto fail; - /* First, prepare the registers (b) with data bits. Note that - * the registers are in reverse of the normal order - */ + g = make_generator(n); + if (!g) + goto fail; + + /* First, prepare the registers (b) with data bits */ bitstream_seek(data, 0); - for (n = 0; n < dlen; ++n) { - unsigned int x = b[0] + bitstream_read(data, 8); - for (i = 0; i < k-1; ++i) - b[i] = b[i+1] + coeff[(k-1) - i] * x; - b[k-1] = coeff[0] * x; + for (i = 0; i < dlen; ++i) { + unsigned int x = b[n-1] ^ bitstream_read(data, 8); + for (r = n-1; r > 0; --r) + b[r] = b[r-1] ^ gf_mult(g[r], x); + b[0] = gf_mult(g[0], x); } /* Read off the registers */ - bitstream_pack(ec, b, k, 8); + for (r = 0; r < n; ++r) + bitstream_write(ec, b[(n-1)-r], 8); + free(g); free(b); return ec; fail: + free(b); bitstream_destroy(ec); return 0; } diff --git a/lpg/libqr/rs.h b/lpg/libqr/rs.h index 98e3aa0..48b1f01 100644 --- a/lpg/libqr/rs.h +++ b/lpg/libqr/rs.h @@ -3,7 +3,7 @@ #include "bitstream.h" -struct bitstream * rs_generate_words(int k, const int * coeff, struct bitstream * data); +struct bitstream * rs_generate_words(int n, struct bitstream * data); #endif -- cgit v1.2.3-70-g09d2 From 825c45bed29693e9420abecdeb4ebcd03aa3accd Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 26 Sep 2009 11:44:37 +0900 Subject: implement bitstream_cat() --- lpg/libqr/bitstream.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/lpg/libqr/bitstream.c b/lpg/libqr/bitstream.c index a2b2b58..fd58ea3 100644 --- a/lpg/libqr/bitstream.c +++ b/lpg/libqr/bitstream.c @@ -201,3 +201,32 @@ int bitstream_pack(struct bitstream * stream, return 0; } +int bitstream_cat(struct bitstream * dest, const struct bitstream * src) +{ + size_t count = bitstream_size(src); + size_t srcpos; + + if (ensure_available(dest, count) != 0) + return -1; + + srcpos = bitstream_tell(src); + bitstream_seek((struct bitstream *)src, 0); + + /* uint must be at least 16 bits */ + for (; count >= 16; count -= 16) + bitstream_write( + dest, + bitstream_read((struct bitstream *)src, 16), + 16); + + if (count > 0) + bitstream_write( + dest, + bitstream_read((struct bitstream *)src, count), + count); + + bitstream_seek((struct bitstream *)src, srcpos); + + return 0; +} + -- cgit v1.2.3-70-g09d2 From 64a96442629b720b2e2b1cc3997ee3dbc6a71b90 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 26 Sep 2009 11:45:30 +0900 Subject: get ready for multiple RS blocks --- lpg/libqr/code-create.c | 94 +++++++++++++++++++++++++++++++++++++------------ lpg/libqr/rs-encode.c | 12 +++---- lpg/libqr/rs.h | 4 ++- 3 files changed, 80 insertions(+), 30 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 389dcd5..9ed59de 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -26,22 +26,6 @@ static void x_dump(struct bitstream * bits) printf("\n"); } -static int add_ecc(struct bitstream * bits, int format, enum qr_ec_level ec) -{ - puts("Before ecc:"); - x_dump(bits); - { - int rs_words = 10; /* 1-M */ - struct bitstream * rs; - - rs = rs_generate_words(rs_words, bits); - puts("ecc part:"); - x_dump(rs); - bitstream_destroy(rs); - } - return -1; -} - static int pad_data(struct bitstream * bits, size_t limit) { /* This function is not very nice. Sorry. */ @@ -86,23 +70,87 @@ static struct bitstream * make_data(int format, enum qr_ec_level ec, struct bitstream * data) { - size_t data_bits = 16 * 8 /*XXX*/; - struct bitstream * out; - - out = bitstream_copy(data); + const size_t total_bits = code_total_capacity(format); + const size_t total_words = total_bits / 8; + size_t block_count, data_words, rs_words; + size_t i; + struct bitstream * dcopy = 0; + struct bitstream * out = 0; + struct bitstream ** blocks = 0; + + /* Set up the output stream */ + out = bitstream_create(); if (!out) return 0; - if (pad_data(out, data_bits) != 0) + if (bitstream_resize(out, total_bits) != 0) goto fail; - if (add_ecc(out, format, ec) != 0) + /** + * XXX: For our test case (1-M) there is only one RS block. + * This is not the case for most other formats, so we'll + * have to deal with this eventually. + */ + block_count = 1; + data_words = 16; + rs_words = 10; + assert(data_words + rs_words == total_words); + + /* Make a copy of the data and pad it */ + dcopy = bitstream_copy(data); + if (!dcopy) + goto fail; + + if (pad_data(dcopy, data_words * 8) != 0) goto fail; + puts("Pad data:"); + x_dump(dcopy); + + /* Make space for the RS blocks */ + blocks = calloc(block_count, sizeof(*blocks)); + if (!blocks) + goto fail; + + /* Generate RS codewords */ + bitstream_seek(dcopy, 0); + puts("Generate RS blocks:"); + for (i = 0; i < block_count; ++i) { + /* XXX: some blocks may be longer */ + blocks[i] = rs_generate_words(dcopy, data_words, rs_words); + if (!blocks[i]) { + while (i--) + bitstream_destroy(blocks[i]); + free(blocks); + blocks = 0; + goto fail; + } + x_dump(blocks[i]); + } + + /* Finally, write everything out in the correct order */ + /* XXX: need to handle multiple blocks */ + bitstream_cat(out, dcopy); + bitstream_cat(out, blocks[0]); + bitstream_write(out, 0, total_bits - total_words * 8); + + puts("Final bitstream:"); + x_dump(out); +exit: + if (blocks) { + while (block_count--) + bitstream_destroy(blocks[block_count]); + free(blocks); + } + if (dcopy) + bitstream_destroy(dcopy); + return out; + fail: bitstream_destroy(out); - return 0; + out = 0; + goto exit; } struct qr_code * qr_code_create(enum qr_ec_level ec, diff --git a/lpg/libqr/rs-encode.c b/lpg/libqr/rs-encode.c index ea54d77..1e6c6bf 100644 --- a/lpg/libqr/rs-encode.c +++ b/lpg/libqr/rs-encode.c @@ -46,17 +46,17 @@ static unsigned int * make_generator(int k) return g; } -struct bitstream * rs_generate_words(int n, struct bitstream * data) +struct bitstream * rs_generate_words(struct bitstream * data, + size_t data_words, + size_t rs_words) { struct bitstream * ec = 0; unsigned int * b = 0; unsigned int * g; - size_t dlen; + size_t n = rs_words; int i, r; - dlen = bitstream_size(data); - assert(dlen % 8 == 0); - dlen /= 8; + assert(bitstream_remaining(data) >= data_words * 8); ec = bitstream_create(); if (!ec) @@ -75,7 +75,7 @@ struct bitstream * rs_generate_words(int n, struct bitstream * data) /* First, prepare the registers (b) with data bits */ bitstream_seek(data, 0); - for (i = 0; i < dlen; ++i) { + for (i = 0; i < data_words; ++i) { unsigned int x = b[n-1] ^ bitstream_read(data, 8); for (r = n-1; r > 0; --r) b[r] = b[r-1] ^ gf_mult(g[r], x); diff --git a/lpg/libqr/rs.h b/lpg/libqr/rs.h index 48b1f01..e640044 100644 --- a/lpg/libqr/rs.h +++ b/lpg/libqr/rs.h @@ -3,7 +3,9 @@ #include "bitstream.h" -struct bitstream * rs_generate_words(int n, struct bitstream * data); +struct bitstream * rs_generate_words(struct bitstream * data, + size_t data_words, + size_t rs_words); #endif -- cgit v1.2.3-70-g09d2 From 28849b589dcd933b2527d9f231ce6668ed7d19fa Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 26 Sep 2009 16:08:27 +0900 Subject: (partially) layout code --- lpg/libqr/Makefile | 1 + lpg/libqr/code-create.c | 82 +++++++++++++++++++++++++++---- lpg/libqr/code-layout.c | 125 ++++++++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/code-layout.h | 12 +++++ lpg/libqr/test.c | 15 ++++++ 5 files changed, 227 insertions(+), 8 deletions(-) create mode 100644 lpg/libqr/code-layout.c create mode 100644 lpg/libqr/code-layout.h diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index 1f34caf..e9783f6 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -1,6 +1,7 @@ OBJECTS := bitstream.o \ code-common.o \ code-create.o \ + code-layout.o \ code-parse.o \ code-render.o \ data-common.o \ diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 9ed59de..a462ea3 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -4,6 +4,7 @@ #include #include "code-common.h" +#include "code-layout.h" #include "data-common.h" #include "rs.h" @@ -26,6 +27,46 @@ static void x_dump(struct bitstream * bits) printf("\n"); } +static void setpx(struct qr_code * code, int x, int y) +{ + size_t off = y * code->line_stride + x / CHAR_BIT; + unsigned char bit = 1 << (x % CHAR_BIT); + + code->modules[off] |= bit; +} + +static void draw_locator(struct qr_code * code, int x, int y) +{ + int i; + for (i = 0; i < 6; ++i) { + setpx(code, x + i, y + 0); + setpx(code, x + 6, y + i); + setpx(code, x + i + 1, y + 6); + setpx(code, x, y + i + 1); + } + for (i = 0; i < 9; ++i) + setpx(code, x + 2 + i % 3, y + 2 + i / 3); +} + +static void draw_fixed_bits(struct qr_code * code) +{ + int dim = code_side_length(code->format); + int i; + + /* Locator pattern */ + draw_locator(code, 0, 0); + draw_locator(code, 0, dim - 7); + draw_locator(code, dim - 7, 0); + + /* Timing pattern */ + for (i = 8; i < dim - 8; i += 2) { + setpx(code, i, 6); + setpx(code, 6, i); + } + + /* XXX: alignment pattern */ +} + static int pad_data(struct bitstream * bits, size_t limit) { /* This function is not very nice. Sorry. */ @@ -157,22 +198,47 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, const struct qr_data * data) { struct qr_code * code; - struct bitstream * ecdata; + struct bitstream * bits = 0; + struct qr_iterator * layout; + size_t dim; code = malloc(sizeof(*code)); if (!code) return 0; + dim = code_side_length(data->format); + code->format = data->format; - ecdata = make_data(data->format, ec, data->bits); + code->line_stride = dim / CHAR_BIT + ((dim % CHAR_BIT) ? 1 : 0); + code->modules = calloc(dim * code->line_stride, sizeof(unsigned char)); - if (!ecdata) { - free(code); - return 0; - } + if (!code->modules) + goto fail; - /* TODO: allocate bitmap; layout */ + draw_fixed_bits(code); - return 0; + bits = make_data(data->format, ec, data->bits); + if (!bits) + goto fail; + + layout = qr_layout_begin(code); + if (!layout) + goto fail; + + bitstream_seek(bits, 0); + while (bitstream_remaining(bits) >= 8) + qr_layout_write(layout, bitstream_read(bits, 8)); + qr_layout_end(layout); + +exit: + if (bits) + bitstream_destroy(bits); + + return code; + +fail: + qr_code_destroy(code); + code = 0; + goto exit; } diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c new file mode 100644 index 0000000..228758a --- /dev/null +++ b/lpg/libqr/code-layout.c @@ -0,0 +1,125 @@ +#include +#include +#include "code-common.h" +#include "code-layout.h" + +struct qr_iterator { + struct qr_code * code; + int dim; + int column; + int row; + int up; + int mask; + unsigned char * p; +}; + +static int is_data_bit(const struct qr_iterator * i) +{ + if (i->row == 6 || i->column == 6) /* timing */ + return 0; + + if (i->column < 9 && i->row < 9) /* top-left */ + return 0; + + if (i->column >= i->dim - 8 && i->row < 9) /* top-right */ + return 0; + + if (i->column < 9 && i->row >= i->dim - 8) /* bottom-left */ + return 0; + + /* XXX: format data */ + /* XXX: alignment pattern */ + + return 1; +} + +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->column / CHAR_BIT; +} + +static void advance(struct qr_iterator * i) +{ + do { + /* This XOR is to account for the vertical strip of + * timing bits in column 6 which displaces everything. + */ + if ((i->column < 6) ^ !(i->column % 2)) { + /* Right-hand part or at left edge */ + i->column -= 1; + } else { + /* Left-hand part */ + i->column += 1; + + if (( i->up && i->row == 0) || + (!i->up && i->row == i->dim - 1)) { + /* Hit the top / bottom */ + i->column -= 2; + i->up = !i->up; + } else { + i->row += i->up ? -1 : 1; + } + } + + if (i->column < 0) + continue; /* don't go off left edge */ + + /* Check for one-past-end */ + if (i->column == 0 && i->row >= i->dim - 8) + break; + + } while (!is_data_bit(i)); + + set_pointer(i); +} + +struct qr_iterator * qr_layout_begin(struct qr_code * code) +{ + struct qr_iterator * i; + + i = malloc(sizeof(*i)); + if (i) { + i->dim = code_side_length(code->format); + i->code = code; + i->column = i->dim - 1; + i->row = i->dim - 1; + i->up = 1; + set_pointer(i); + } + + return i; +} + +void qr_layout_end(struct qr_iterator * i) +{ + free(i); +} + +unsigned int qr_layout_read(struct qr_iterator * i) +{ + unsigned int x = 0; + int b; + + for (b = 0; b < 8; ++b) { + x |= (*i->p & i->mask) ? 1 : 0; + advance(i); + x <<= 1; + } + + return x; +} + +void qr_layout_write(struct qr_iterator * i, unsigned int x) +{ + int b; + + for (b = 0; b < 8; ++b) { + *i->p |= (x & 0x80) ? i->mask : 0; + advance(i); + x <<= 1; + } +} + diff --git a/lpg/libqr/code-layout.h b/lpg/libqr/code-layout.h new file mode 100644 index 0000000..79e9730 --- /dev/null +++ b/lpg/libqr/code-layout.h @@ -0,0 +1,12 @@ +#ifndef CODE_LAYOUT_H +#define CODE_LAYOUT_H + +struct qr_iterator; + +struct qr_iterator * qr_layout_begin(struct qr_code *); +unsigned int qr_layout_read(struct qr_iterator *); +void qr_layout_write(struct qr_iterator *, unsigned int); +void qr_layout_end(struct qr_iterator *); + +#endif + diff --git a/lpg/libqr/test.c b/lpg/libqr/test.c index ec77bfe..f51b90b 100644 --- a/lpg/libqr/test.c +++ b/lpg/libqr/test.c @@ -33,6 +33,21 @@ int main() { printf("Code width %d\n", qr_code_width(code)); + { + /* Hack: render the code using ANSI terminal art */ + char buf[80*25]; + int x, y; + + qr_code_render(code, buf, 8, 80, 0, 1, 0); + for (y=0;y<21;++y) { + printf("\t|"); + for (x=0;x<21;++x) { + printf("%s ", buf[y*80+x]?"\033[7m":"\033[0m"); + } + printf("\033[0m|\n"); + } + } + return 0; } -- cgit v1.2.3-70-g09d2 From 24e968c84075344de2b6b31dc054bfe988eacd04 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sun, 27 Sep 2009 14:10:12 +0900 Subject: Add COPYING information --- lpg/libqr/COPYING | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 lpg/libqr/COPYING diff --git a/lpg/libqr/COPYING b/lpg/libqr/COPYING new file mode 100644 index 0000000..10a9711 --- /dev/null +++ b/lpg/libqr/COPYING @@ -0,0 +1,17 @@ +I, the author, hereby release this work into the public +domain. + +Where the above is not possible, I release this work as +"Copyright-Free", or (at your option) under the terms of +the Creative Commons CC0 license: + + http://creativecommons.org/publicdomain/zero/1.0/ + +The author waives all rights concerning the modification, +reproduction and/or distribution of this work, or +derivatives thereof, in whole or part, and in any form. +Attribution is not required. + + +Leo Howell, September 2009 + -- cgit v1.2.3-70-g09d2 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 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 From 388507a61df32c0bddf7e61c5da013c3f29d32d4 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sun, 27 Sep 2009 16:53:16 +0900 Subject: bitstream -> qr_bitstream --- lpg/libqr/Makefile | 4 +- lpg/libqr/bitstream.c | 232 ----------------------------------------------- lpg/libqr/bitstream.h | 44 --------- lpg/libqr/code-common.h | 2 +- lpg/libqr/code-create.c | 66 +++++++------- lpg/libqr/data-common.c | 4 +- lpg/libqr/data-common.h | 4 +- lpg/libqr/data-create.c | 38 ++++---- lpg/libqr/data-parse.c | 52 +++++------ lpg/libqr/qr-bitstream.c | 232 +++++++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/qr-bitstream.h | 44 +++++++++ lpg/libqr/rs-encode.c | 20 ++-- lpg/libqr/rs.h | 4 +- lpg/libqr/test.c | 2 +- 14 files changed, 374 insertions(+), 374 deletions(-) delete mode 100644 lpg/libqr/bitstream.c delete mode 100644 lpg/libqr/bitstream.h create mode 100644 lpg/libqr/qr-bitstream.c create mode 100644 lpg/libqr/qr-bitstream.h diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index 1571de4..49f89d4 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -1,5 +1,4 @@ -OBJECTS := bitstream.o \ - code-common.o \ +OBJECTS := code-common.o \ code-create.o \ code-layout.o \ code-parse.o \ @@ -9,6 +8,7 @@ OBJECTS := bitstream.o \ qr-bitmap.o \ qr-bitmap-pbm.o \ qr-bitmap-render.o \ + qr-bitstream.o \ rs-encode.o CFLAGS := -std=c89 -pedantic -I. -Wall diff --git a/lpg/libqr/bitstream.c b/lpg/libqr/bitstream.c deleted file mode 100644 index fd58ea3..0000000 --- a/lpg/libqr/bitstream.c +++ /dev/null @@ -1,232 +0,0 @@ -/** - * It would perhaps be more sensible just to store the bits - * as an array of char or similar, but this way is more fun. - * This is a pretty inefficient implementation, althought I - * suspect that won't be a problem. - */ - -#include -#include -#include -#include - -#include "bitstream.h" - -#define MAX(a, b) ((a) < (b) ? (b) : (a)) -#define MIN(a, b) ((a) > (b) ? (b) : (a)) - -struct bitstream { - size_t pos; /* bits */ - size_t count; /* bits */ - size_t bufsiz; /* bytes */ - unsigned char * buffer; -}; - -static size_t bits_to_bytes(size_t bits) -{ - return (bits / CHAR_BIT) + (bits % CHAR_BIT != 0); -} - -static int ensure_available(struct bitstream * stream, size_t bits) -{ - size_t need_bits = stream->pos + bits; - size_t need_bytes = need_bits / CHAR_BIT + ((need_bits % CHAR_BIT) ? 0 : 1); - size_t newsize; - - if (stream->bufsiz >= need_bytes) - return 0; - - newsize = MAX(stream->bufsiz, 100); - while (newsize < need_bytes) - newsize *= 2; - - return bitstream_resize(stream, newsize); -} - -struct bitstream * bitstream_create(void) -{ - struct bitstream * obj; - - obj = malloc(sizeof(*obj)); - - if (obj) { - obj->pos = 0; - obj->count = 0; - obj->bufsiz = 0; - obj->buffer = 0; - } - - return obj; -} - -int bitstream_resize(struct bitstream * stream, size_t bits) -{ - size_t newsize; - void * newbuf; - - newsize = bits_to_bytes(bits); - newbuf = realloc(stream->buffer, newsize); - - if (newbuf) { - stream->bufsiz = newsize; - stream->buffer = newbuf; - } - - return newbuf ? 0 : -1; -} - -void bitstream_destroy(struct bitstream * stream) -{ - free(stream->buffer); - free(stream); -} - -struct bitstream * bitstream_copy(const struct bitstream * src) -{ - struct bitstream * ret; - - ret = bitstream_create(); - if (!ret) - return 0; - - if (bitstream_resize(ret, src->count) != 0) { - free(ret); - return 0; - } - - ret->pos = src->pos; - ret->count = src->count; - memcpy(ret->buffer, src->buffer, src->bufsiz); - - return ret; -} - -void bitstream_seek(struct bitstream * stream, size_t pos) -{ - assert(pos <= stream->count); - stream->pos = pos; -} - -size_t bitstream_tell(const struct bitstream * stream) -{ - return stream->pos; -} - -size_t bitstream_remaining(const struct bitstream * stream) -{ - return stream->count - stream->pos; -} - -size_t bitstream_size(const struct bitstream * stream) -{ - return stream->count; -} - -unsigned int bitstream_read(struct bitstream * stream, size_t bits) -{ - unsigned int result = 0; - unsigned char * byte; - size_t bitnum; - - assert(bitstream_remaining(stream) >= bits); - - byte = stream->buffer + (stream->pos / CHAR_BIT); - bitnum = stream->pos % CHAR_BIT; - - stream->pos += bits; - - while (bits-- > 0) { - int bit = (*byte >> bitnum++) & 0x1; - result = (result << 1) | bit; - if (bitnum == CHAR_BIT) { - bitnum = 0; - ++byte; - } - } - - return result; -} - -void bitstream_unpack(struct bitstream * stream, - unsigned int * result, - size_t count, - size_t bitsize) -{ - assert(bitstream_remaining(stream) >= (count * bitsize)); - - while (count--) - *(result++) = bitstream_read(stream, bitsize); -} - -int bitstream_write(struct bitstream * stream, - unsigned int value, - size_t bits) -{ - unsigned char * byte; - size_t bitnum; - - if (ensure_available(stream, bits) != 0) - return -1; - - byte = stream->buffer + (stream->pos / CHAR_BIT); - bitnum = stream->pos % CHAR_BIT; - - stream->pos += bits; - stream->count = stream->pos; /* truncate */ - - while (bits-- > 0) { - int bit = (value >> bits) & 0x1; - unsigned char mask = 1 << bitnum++; - *byte = (*byte & ~mask) | (bit ? mask : 0); - if (bitnum == CHAR_BIT) { - bitnum = 0; - ++byte; - } - } - - return 0; -} - -int bitstream_pack(struct bitstream * stream, - const unsigned int * values, - size_t count, - size_t bitsize) -{ - if (ensure_available(stream, count * bitsize) != 0) - return -1; - - while (count--) - bitstream_write(stream, *(values++), bitsize); - - return 0; -} - -int bitstream_cat(struct bitstream * dest, const struct bitstream * src) -{ - size_t count = bitstream_size(src); - size_t srcpos; - - if (ensure_available(dest, count) != 0) - return -1; - - srcpos = bitstream_tell(src); - bitstream_seek((struct bitstream *)src, 0); - - /* uint must be at least 16 bits */ - for (; count >= 16; count -= 16) - bitstream_write( - dest, - bitstream_read((struct bitstream *)src, 16), - 16); - - if (count > 0) - bitstream_write( - dest, - bitstream_read((struct bitstream *)src, count), - count); - - bitstream_seek((struct bitstream *)src, srcpos); - - return 0; -} - diff --git a/lpg/libqr/bitstream.h b/lpg/libqr/bitstream.h deleted file mode 100644 index 12412bc..0000000 --- a/lpg/libqr/bitstream.h +++ /dev/null @@ -1,44 +0,0 @@ -#ifndef QR_BITSTREAM_H -#define QR_BITSTREAM_H - -#include - -/** - * Note: when writing / reading multiple bits, the - * _most_ significant bits come first in the stream. - * (That is, the order you would naturally write the - * number in binary) - */ - -struct bitstream; - -struct bitstream * bitstream_create(void); -int bitstream_resize(struct bitstream *, size_t bits); -void bitstream_destroy(struct bitstream *); -struct bitstream * bitstream_copy(const struct bitstream *); - -void bitstream_seek(struct bitstream *, size_t pos); -size_t bitstream_tell(const struct bitstream *); -size_t bitstream_remaining(const struct bitstream *); -size_t bitstream_size(const struct bitstream *); - -unsigned int bitstream_read(struct bitstream *, size_t bits); - -void bitstream_unpack(struct bitstream *, - unsigned int * result, - size_t count, - size_t bitsize); - -int bitstream_write(struct bitstream *, - unsigned int value, - size_t bits); - -int bitstream_pack(struct bitstream *, - const unsigned int * values, - size_t count, - size_t bitsize); - -int bitstream_cat(struct bitstream *, const struct bitstream * src); - -#endif - diff --git a/lpg/libqr/code-common.h b/lpg/libqr/code-common.h index fce8dce..cf96217 100644 --- a/lpg/libqr/code-common.h +++ b/lpg/libqr/code-common.h @@ -2,7 +2,7 @@ #define CODE_COMMON_H #include -#include "bitstream.h" +#include "qr-bitstream.h" #include "qr-bitmap.h" struct qr_code { diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 5c0f2b7..c6451ac 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -11,14 +11,14 @@ #define MIN(a, b) ((b) < (a) ? (b) : (a)) #include -static void x_dump(struct bitstream * bits) +static void x_dump(struct qr_bitstream * bits) { size_t i, n; - bitstream_seek(bits, 0); - n = bitstream_size(bits); + qr_bitstream_seek(bits, 0); + n = qr_bitstream_size(bits); for (i = 0; i < n; ++i) { - printf("%d", bitstream_read(bits, 1)); + printf("%d", qr_bitstream_read(bits, 1)); if (i % 8 == 7) printf(" "); if ((i+1) % (7 * 8) == 0) @@ -67,19 +67,19 @@ static void draw_fixed_bits(struct qr_code * code) /* XXX: alignment pattern */ } -static int pad_data(struct bitstream * bits, size_t limit) +static int pad_data(struct qr_bitstream * bits, size_t limit) { /* This function is not very nice. Sorry. */ size_t count, n; - assert(bitstream_size(bits) <= limit); + assert(qr_bitstream_size(bits) <= limit); - if (bitstream_resize(bits, limit) != 0) + if (qr_bitstream_resize(bits, limit) != 0) return -1; - n = bitstream_size(bits); - bitstream_seek(bits, n); + n = qr_bitstream_size(bits); + qr_bitstream_seek(bits, n); count = limit - n; /* First append the terminator (0000) if possible, @@ -89,42 +89,42 @@ static int pad_data(struct bitstream * bits, size_t limit) if (n != 0) n = 8 - n; n = MIN(count, n + 4); - bitstream_write(bits, 0, n); + qr_bitstream_write(bits, 0, n); count -= n; assert(count % 8 == 0); /* since data codewords are 8 bits */ /* Finally pad with the repeating sequence 11101100 00010001 */ while (count >= 16) { - bitstream_write(bits, 0xEC11, 16); + qr_bitstream_write(bits, 0xEC11, 16); count -= 16; } if (count > 0) { assert(count == 8); - bitstream_write(bits, 0xEC, 8); + qr_bitstream_write(bits, 0xEC, 8); } return 0; } -static struct bitstream * make_data(int format, +static struct qr_bitstream * make_data(int format, enum qr_ec_level ec, - struct bitstream * data) + struct qr_bitstream * data) { const size_t total_bits = code_total_capacity(format); const size_t total_words = total_bits / 8; size_t block_count, data_words, rs_words; size_t i; - struct bitstream * dcopy = 0; - struct bitstream * out = 0; - struct bitstream ** blocks = 0; + struct qr_bitstream * dcopy = 0; + struct qr_bitstream * out = 0; + struct qr_bitstream ** blocks = 0; /* Set up the output stream */ - out = bitstream_create(); + out = qr_bitstream_create(); if (!out) return 0; - if (bitstream_resize(out, total_bits) != 0) + if (qr_bitstream_resize(out, total_bits) != 0) goto fail; /** @@ -138,7 +138,7 @@ static struct bitstream * make_data(int format, assert(data_words + rs_words == total_words); /* Make a copy of the data and pad it */ - dcopy = bitstream_copy(data); + dcopy = qr_bitstream_copy(data); if (!dcopy) goto fail; @@ -154,14 +154,14 @@ static struct bitstream * make_data(int format, goto fail; /* Generate RS codewords */ - bitstream_seek(dcopy, 0); + qr_bitstream_seek(dcopy, 0); puts("Generate RS blocks:"); for (i = 0; i < block_count; ++i) { /* XXX: some blocks may be longer */ blocks[i] = rs_generate_words(dcopy, data_words, rs_words); if (!blocks[i]) { while (i--) - bitstream_destroy(blocks[i]); + qr_bitstream_destroy(blocks[i]); free(blocks); blocks = 0; goto fail; @@ -171,25 +171,25 @@ static struct bitstream * make_data(int format, /* Finally, write everything out in the correct order */ /* XXX: need to handle multiple blocks */ - bitstream_cat(out, dcopy); - bitstream_cat(out, blocks[0]); - bitstream_write(out, 0, total_bits - total_words * 8); + qr_bitstream_cat(out, dcopy); + qr_bitstream_cat(out, blocks[0]); + qr_bitstream_write(out, 0, total_bits - total_words * 8); puts("Final bitstream:"); x_dump(out); exit: if (blocks) { while (block_count--) - bitstream_destroy(blocks[block_count]); + qr_bitstream_destroy(blocks[block_count]); free(blocks); } if (dcopy) - bitstream_destroy(dcopy); + qr_bitstream_destroy(dcopy); return out; fail: - bitstream_destroy(out); + qr_bitstream_destroy(out); out = 0; goto exit; } @@ -198,7 +198,7 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, const struct qr_data * data) { struct qr_code * code; - struct bitstream * bits = 0; + struct qr_bitstream * bits = 0; struct qr_iterator * layout; size_t dim; @@ -224,14 +224,14 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, if (!layout) goto fail; - bitstream_seek(bits, 0); - while (bitstream_remaining(bits) >= 8) - qr_layout_write(layout, bitstream_read(bits, 8)); + qr_bitstream_seek(bits, 0); + while (qr_bitstream_remaining(bits) >= 8) + qr_layout_write(layout, qr_bitstream_read(bits, 8)); qr_layout_end(layout); exit: if (bits) - bitstream_destroy(bits); + qr_bitstream_destroy(bits); return code; diff --git a/lpg/libqr/data-common.c b/lpg/libqr/data-common.c index 123e5c4..c64527a 100644 --- a/lpg/libqr/data-common.c +++ b/lpg/libqr/data-common.c @@ -1,7 +1,7 @@ #include #include -#include "bitstream.h" +#include "qr-bitstream.h" #include "data-common.h" const enum qr_data_type QR_TYPE_CODES[16] = { @@ -25,7 +25,7 @@ const enum qr_data_type QR_TYPE_CODES[16] = { void qr_free_data(struct qr_data * data) { - bitstream_destroy(data->bits); + qr_bitstream_destroy(data->bits); free(data); } diff --git a/lpg/libqr/data-common.h b/lpg/libqr/data-common.h index d5f6e45..1522b09 100644 --- a/lpg/libqr/data-common.h +++ b/lpg/libqr/data-common.h @@ -3,11 +3,11 @@ #include -#include "bitstream.h" +#include "qr-bitstream.h" struct qr_data { int format; /* 1 ~ 40 */ - struct bitstream * bits; + struct qr_bitstream * bits; size_t offset; }; diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c index 2910997..a918413 100644 --- a/lpg/libqr/data-create.c +++ b/lpg/libqr/data-create.c @@ -9,15 +9,15 @@ #include #include -#include "bitstream.h" +#include "qr-bitstream.h" #include "data-common.h" static void write_type_and_length(struct qr_data * data, enum qr_data_type type, size_t length) { - (void)bitstream_write(data->bits, QR_TYPE_CODES[type], 4); - (void)bitstream_write(data->bits, length, + (void)qr_bitstream_write(data->bits, QR_TYPE_CODES[type], 4); + (void)qr_bitstream_write(data->bits, length, get_size_field_length(data->format, type)); } @@ -25,7 +25,7 @@ static struct qr_data * encode_numeric(struct qr_data * data, const char * input, size_t length) { - struct bitstream * stream = data->bits; + struct qr_bitstream * stream = data->bits; size_t bits; bits = 4 + get_size_field_length(data->format, QR_DATA_NUMERIC) @@ -37,8 +37,8 @@ static struct qr_data * encode_numeric(struct qr_data * data, bits += 7; stream = data->bits; - if (bitstream_resize(stream, - bitstream_size(stream) + bits) != 0) + if (qr_bitstream_resize(stream, + qr_bitstream_size(stream) + bits) != 0) return 0; write_type_and_length(data, QR_DATA_NUMERIC, length); @@ -54,7 +54,7 @@ static struct qr_data * encode_numeric(struct qr_data * data, x = (input[0] - '0') * 100 + (input[1] - '0') * 10 + (input[2] - '0'); - bitstream_write(stream, x, 10); + qr_bitstream_write(stream, x, 10); input += 3; } @@ -72,7 +72,7 @@ static struct qr_data * encode_numeric(struct qr_data * data, x = x * 10 + (*input - '0'); } - bitstream_write(stream, x, length == 2 ? 7 : 4); + qr_bitstream_write(stream, x, length == 2 ? 7 : 4); } return data; @@ -103,7 +103,7 @@ static struct qr_data * encode_alpha(struct qr_data * data, const char * input, size_t length) { - struct bitstream * stream = data->bits; + struct qr_bitstream * stream = data->bits; size_t bits; bits = 4 + get_size_field_length(data->format, QR_DATA_ALPHA) @@ -111,8 +111,8 @@ static struct qr_data * encode_alpha(struct qr_data * data, + 6 * (length % 2); stream = data->bits; - if (bitstream_resize(stream, - bitstream_size(stream) + bits) != 0) + if (qr_bitstream_resize(stream, + qr_bitstream_size(stream) + bits) != 0) return 0; write_type_and_length(data, QR_DATA_ALPHA, length); @@ -128,7 +128,7 @@ static struct qr_data * encode_alpha(struct qr_data * data, return 0; x = c1 * 45 + c2; - bitstream_write(stream, x, 11); + qr_bitstream_write(stream, x, 11); } if (length > 0) { @@ -137,7 +137,7 @@ static struct qr_data * encode_alpha(struct qr_data * data, if (c < 0) return 0; - bitstream_write(stream, c, 6); + qr_bitstream_write(stream, c, 6); } return data; @@ -147,21 +147,21 @@ static struct qr_data * encode_8bit(struct qr_data * data, const char * input, size_t length) { - struct bitstream * stream = data->bits; + struct qr_bitstream * stream = data->bits; size_t bits; bits = 4 + get_size_field_length(data->format, QR_DATA_8BIT) + 8 * length; stream = data->bits; - if (bitstream_resize(stream, - bitstream_size(stream) + bits) != 0) + if (qr_bitstream_resize(stream, + qr_bitstream_size(stream) + bits) != 0) return 0; write_type_and_length(data, QR_DATA_8BIT, length); while (length--) - bitstream_write(stream, *input++, 8); + qr_bitstream_write(stream, *input++, 8); return data; } @@ -188,7 +188,7 @@ struct qr_data * qr_create_data(int format, return 0; data->format = format; - data->bits = bitstream_create(); + data->bits = qr_bitstream_create(); data->offset = 0; if (data->bits) { @@ -210,7 +210,7 @@ struct qr_data * qr_create_data(int format, } if (!ret) { - bitstream_destroy(data->bits); + qr_bitstream_destroy(data->bits); free(data); } diff --git a/lpg/libqr/data-parse.c b/lpg/libqr/data-parse.c index 9129ed7..d497bdf 100644 --- a/lpg/libqr/data-parse.c +++ b/lpg/libqr/data-parse.c @@ -3,18 +3,18 @@ #include #include -#include "bitstream.h" +#include "qr-bitstream.h" #include "data-common.h" -static enum qr_data_type read_data_type(struct bitstream * stream) +static enum qr_data_type read_data_type(struct qr_bitstream * stream) { const size_t length = 4; unsigned int type; - if (bitstream_remaining(stream) < length) + if (qr_bitstream_remaining(stream) < length) return QR_DATA_INVALID; - type = bitstream_read(stream, length); + type = qr_bitstream_read(stream, length); assert(type < 16); return QR_TYPE_CODES[type]; @@ -24,7 +24,7 @@ static enum qr_data_type parse_numeric(const struct qr_data * data, char ** output, size_t * length) { - struct bitstream * stream; + struct qr_bitstream * stream; size_t field_len, bits; unsigned int digits; unsigned int chunk; @@ -34,10 +34,10 @@ static enum qr_data_type parse_numeric(const struct qr_data * data, buffer = 0; field_len = get_size_field_length(data->format, QR_DATA_NUMERIC); - if (bitstream_remaining(stream) < field_len) + if (qr_bitstream_remaining(stream) < field_len) goto invalid; - digits = bitstream_read(stream, field_len); + digits = qr_bitstream_read(stream, field_len); bits = (digits / 3) * 10; if (digits % 3 == 1) @@ -45,7 +45,7 @@ static enum qr_data_type parse_numeric(const struct qr_data * data, else if (digits % 3 == 2) bits += 7; - if (bitstream_remaining(stream) < bits) + if (qr_bitstream_remaining(stream) < bits) goto invalid; buffer = malloc(digits + 1); @@ -55,7 +55,7 @@ static enum qr_data_type parse_numeric(const struct qr_data * data, p = buffer; for (; bits >= 10; bits -= 10) { - chunk = bitstream_read(stream, 10); + chunk = qr_bitstream_read(stream, 10); if (chunk >= 1000) goto invalid; sprintf(p, "%03u", chunk); @@ -63,7 +63,7 @@ static enum qr_data_type parse_numeric(const struct qr_data * data, } if (bits > 0) { - chunk = bitstream_read(stream, bits); + chunk = qr_bitstream_read(stream, bits); if (chunk >= (bits >= 7 ? 100 : 10)) goto invalid; sprintf(p, "%0*u", bits >= 7 ? 2 : 1, chunk); @@ -84,7 +84,7 @@ static enum qr_data_type parse_alpha(const struct qr_data * data, { static const char charset[45] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"; - struct bitstream * stream; + struct qr_bitstream * stream; size_t field_len, bits; unsigned int chars; unsigned int chunk; @@ -94,16 +94,16 @@ static enum qr_data_type parse_alpha(const struct qr_data * data, buffer = 0; field_len = get_size_field_length(data->format, QR_DATA_ALPHA); - if (bitstream_remaining(stream) < field_len) + if (qr_bitstream_remaining(stream) < field_len) goto invalid; - chars = bitstream_read(stream, field_len); + chars = qr_bitstream_read(stream, field_len); bits = (chars / 2) * 11; if (chars % 2 == 1) bits += 6; - if (bitstream_remaining(stream) < bits) + if (qr_bitstream_remaining(stream) < bits) goto invalid; buffer = malloc(chars + 1); @@ -114,7 +114,7 @@ static enum qr_data_type parse_alpha(const struct qr_data * data, for (; bits >= 11; bits -= 11) { unsigned int c1, c2; - chunk = bitstream_read(stream, 11); + chunk = qr_bitstream_read(stream, 11); c1 = chunk / 45; c2 = chunk % 45; if (c1 >= 45) @@ -124,7 +124,7 @@ static enum qr_data_type parse_alpha(const struct qr_data * data, } if (bits > 0) { - chunk = bitstream_read(stream, bits); + chunk = qr_bitstream_read(stream, bits); if (chunk >= 45) goto invalid; *p = charset[chunk]; @@ -143,7 +143,7 @@ static enum qr_data_type parse_8bit(const struct qr_data * data, char ** output, size_t * length) { - struct bitstream * stream; + struct qr_bitstream * stream; size_t field_len; unsigned int bytes; char * p; @@ -151,12 +151,12 @@ static enum qr_data_type parse_8bit(const struct qr_data * data, stream = data->bits; field_len = get_size_field_length(data->format, QR_DATA_8BIT); - if (bitstream_remaining(stream) < field_len) + if (qr_bitstream_remaining(stream) < field_len) return QR_DATA_INVALID; - bytes = bitstream_read(stream, field_len); + bytes = qr_bitstream_read(stream, field_len); - if (bitstream_remaining(stream) < bytes * 8) + if (qr_bitstream_remaining(stream) < bytes * 8) return QR_DATA_INVALID; *output = malloc(bytes + 1); @@ -167,7 +167,7 @@ static enum qr_data_type parse_8bit(const struct qr_data * data, *length = bytes; while (bytes-- > 0) - *p++ = bitstream_read(stream, 8); + *p++ = qr_bitstream_read(stream, 8); *p = '\0'; @@ -183,7 +183,7 @@ static enum qr_data_type parse_kanji(const struct qr_data * data, enum qr_data_type qr_get_data_type(const struct qr_data * data) { - bitstream_seek(data->bits, data->offset); + qr_bitstream_seek(data->bits, data->offset); return read_data_type(data->bits); } @@ -192,7 +192,7 @@ int qr_get_data_length(const struct qr_data * data) size_t field_len; enum qr_data_type type; - bitstream_seek(data->bits, data->offset); + qr_bitstream_seek(data->bits, data->offset); type = read_data_type(data->bits); @@ -208,17 +208,17 @@ int qr_get_data_length(const struct qr_data * data) return -1; } - if (bitstream_remaining(data->bits) < field_len) + if (qr_bitstream_remaining(data->bits) < field_len) return -1; - return (int) bitstream_read(data->bits, field_len); + return (int) qr_bitstream_read(data->bits, field_len); } enum qr_data_type qr_parse_data(const struct qr_data * input, char ** output, size_t * length) { - bitstream_seek(input->bits, input->offset); + qr_bitstream_seek(input->bits, input->offset); switch (read_data_type(input->bits)) { case QR_DATA_NUMERIC: diff --git a/lpg/libqr/qr-bitstream.c b/lpg/libqr/qr-bitstream.c new file mode 100644 index 0000000..3df2549 --- /dev/null +++ b/lpg/libqr/qr-bitstream.c @@ -0,0 +1,232 @@ +/** + * It would perhaps be more sensible just to store the bits + * as an array of char or similar, but this way is more fun. + * This is a pretty inefficient implementation, althought I + * suspect that won't be a problem. + */ + +#include +#include +#include +#include + +#include "qr-bitstream.h" + +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +struct qr_bitstream { + size_t pos; /* bits */ + size_t count; /* bits */ + size_t bufsiz; /* bytes */ + unsigned char * buffer; +}; + +static size_t bits_to_bytes(size_t bits) +{ + return (bits / CHAR_BIT) + (bits % CHAR_BIT != 0); +} + +static int ensure_available(struct qr_bitstream * stream, size_t bits) +{ + size_t need_bits = stream->pos + bits; + size_t need_bytes = need_bits / CHAR_BIT + ((need_bits % CHAR_BIT) ? 0 : 1); + size_t newsize; + + if (stream->bufsiz >= need_bytes) + return 0; + + newsize = MAX(stream->bufsiz, 100); + while (newsize < need_bytes) + newsize *= 2; + + return qr_bitstream_resize(stream, newsize); +} + +struct qr_bitstream * qr_bitstream_create(void) +{ + struct qr_bitstream * obj; + + obj = malloc(sizeof(*obj)); + + if (obj) { + obj->pos = 0; + obj->count = 0; + obj->bufsiz = 0; + obj->buffer = 0; + } + + return obj; +} + +int qr_bitstream_resize(struct qr_bitstream * stream, size_t bits) +{ + size_t newsize; + void * newbuf; + + newsize = bits_to_bytes(bits); + newbuf = realloc(stream->buffer, newsize); + + if (newbuf) { + stream->bufsiz = newsize; + stream->buffer = newbuf; + } + + return newbuf ? 0 : -1; +} + +void qr_bitstream_destroy(struct qr_bitstream * stream) +{ + free(stream->buffer); + free(stream); +} + +struct qr_bitstream * qr_bitstream_copy(const struct qr_bitstream * src) +{ + struct qr_bitstream * ret; + + ret = qr_bitstream_create(); + if (!ret) + return 0; + + if (qr_bitstream_resize(ret, src->count) != 0) { + free(ret); + return 0; + } + + ret->pos = src->pos; + ret->count = src->count; + memcpy(ret->buffer, src->buffer, src->bufsiz); + + return ret; +} + +void qr_bitstream_seek(struct qr_bitstream * stream, size_t pos) +{ + assert(pos <= stream->count); + stream->pos = pos; +} + +size_t qr_bitstream_tell(const struct qr_bitstream * stream) +{ + return stream->pos; +} + +size_t qr_bitstream_remaining(const struct qr_bitstream * stream) +{ + return stream->count - stream->pos; +} + +size_t qr_bitstream_size(const struct qr_bitstream * stream) +{ + return stream->count; +} + +unsigned int qr_bitstream_read(struct qr_bitstream * stream, size_t bits) +{ + unsigned int result = 0; + unsigned char * byte; + size_t bitnum; + + assert(qr_bitstream_remaining(stream) >= bits); + + byte = stream->buffer + (stream->pos / CHAR_BIT); + bitnum = stream->pos % CHAR_BIT; + + stream->pos += bits; + + while (bits-- > 0) { + int bit = (*byte >> bitnum++) & 0x1; + result = (result << 1) | bit; + if (bitnum == CHAR_BIT) { + bitnum = 0; + ++byte; + } + } + + return result; +} + +void qr_bitstream_unpack(struct qr_bitstream * stream, + unsigned int * result, + size_t count, + size_t bitsize) +{ + assert(qr_bitstream_remaining(stream) >= (count * bitsize)); + + while (count--) + *(result++) = qr_bitstream_read(stream, bitsize); +} + +int qr_bitstream_write(struct qr_bitstream * stream, + unsigned int value, + size_t bits) +{ + unsigned char * byte; + size_t bitnum; + + if (ensure_available(stream, bits) != 0) + return -1; + + byte = stream->buffer + (stream->pos / CHAR_BIT); + bitnum = stream->pos % CHAR_BIT; + + stream->pos += bits; + stream->count = stream->pos; /* truncate */ + + while (bits-- > 0) { + int bit = (value >> bits) & 0x1; + unsigned char mask = 1 << bitnum++; + *byte = (*byte & ~mask) | (bit ? mask : 0); + if (bitnum == CHAR_BIT) { + bitnum = 0; + ++byte; + } + } + + return 0; +} + +int qr_bitstream_pack(struct qr_bitstream * stream, + const unsigned int * values, + size_t count, + size_t bitsize) +{ + if (ensure_available(stream, count * bitsize) != 0) + return -1; + + while (count--) + qr_bitstream_write(stream, *(values++), bitsize); + + return 0; +} + +int qr_bitstream_cat(struct qr_bitstream * dest, const struct qr_bitstream * src) +{ + size_t count = qr_bitstream_size(src); + size_t srcpos; + + if (ensure_available(dest, count) != 0) + return -1; + + srcpos = qr_bitstream_tell(src); + qr_bitstream_seek((struct qr_bitstream *)src, 0); + + /* uint must be at least 16 bits */ + for (; count >= 16; count -= 16) + qr_bitstream_write( + dest, + qr_bitstream_read((struct qr_bitstream *)src, 16), + 16); + + if (count > 0) + qr_bitstream_write( + dest, + qr_bitstream_read((struct qr_bitstream *)src, count), + count); + + qr_bitstream_seek((struct qr_bitstream *)src, srcpos); + + return 0; +} + diff --git a/lpg/libqr/qr-bitstream.h b/lpg/libqr/qr-bitstream.h new file mode 100644 index 0000000..298e53b --- /dev/null +++ b/lpg/libqr/qr-bitstream.h @@ -0,0 +1,44 @@ +#ifndef QR_BITSTREAM_H +#define QR_BITSTREAM_H + +#include + +/** + * Note: when writing / reading multiple bits, the + * _most_ significant bits come first in the stream. + * (That is, the order you would naturally write the + * number in binary) + */ + +struct qr_bitstream; + +struct qr_bitstream * qr_bitstream_create(void); +int qr_bitstream_resize(struct qr_bitstream *, size_t bits); +void qr_bitstream_destroy(struct qr_bitstream *); +struct qr_bitstream * qr_bitstream_copy(const struct qr_bitstream *); + +void qr_bitstream_seek(struct qr_bitstream *, size_t pos); +size_t qr_bitstream_tell(const struct qr_bitstream *); +size_t qr_bitstream_remaining(const struct qr_bitstream *); +size_t qr_bitstream_size(const struct qr_bitstream *); + +unsigned int qr_bitstream_read(struct qr_bitstream *, size_t bits); + +void qr_bitstream_unpack(struct qr_bitstream *, + unsigned int * result, + size_t count, + size_t bitsize); + +int qr_bitstream_write(struct qr_bitstream *, + unsigned int value, + size_t bits); + +int qr_bitstream_pack(struct qr_bitstream *, + const unsigned int * values, + size_t count, + size_t bitsize); + +int qr_bitstream_cat(struct qr_bitstream *, const struct qr_bitstream * src); + +#endif + diff --git a/lpg/libqr/rs-encode.c b/lpg/libqr/rs-encode.c index 1e6c6bf..42b404f 100644 --- a/lpg/libqr/rs-encode.c +++ b/lpg/libqr/rs-encode.c @@ -1,6 +1,6 @@ #include #include -#include "bitstream.h" +#include "qr-bitstream.h" #include "rs.h" static unsigned int gf_mult(unsigned int a, unsigned int b) @@ -46,23 +46,23 @@ static unsigned int * make_generator(int k) return g; } -struct bitstream * rs_generate_words(struct bitstream * data, +struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, size_t data_words, size_t rs_words) { - struct bitstream * ec = 0; + struct qr_bitstream * ec = 0; unsigned int * b = 0; unsigned int * g; size_t n = rs_words; int i, r; - assert(bitstream_remaining(data) >= data_words * 8); + assert(qr_bitstream_remaining(data) >= data_words * 8); - ec = bitstream_create(); + ec = qr_bitstream_create(); if (!ec) return 0; - if (bitstream_resize(ec, n * 8) != 0) + if (qr_bitstream_resize(ec, n * 8) != 0) goto fail; b = calloc(n, sizeof(*b)); @@ -74,9 +74,9 @@ struct bitstream * rs_generate_words(struct bitstream * data, goto fail; /* First, prepare the registers (b) with data bits */ - bitstream_seek(data, 0); + qr_bitstream_seek(data, 0); for (i = 0; i < data_words; ++i) { - unsigned int x = b[n-1] ^ bitstream_read(data, 8); + unsigned int x = b[n-1] ^ qr_bitstream_read(data, 8); for (r = n-1; r > 0; --r) b[r] = b[r-1] ^ gf_mult(g[r], x); b[0] = gf_mult(g[0], x); @@ -84,14 +84,14 @@ struct bitstream * rs_generate_words(struct bitstream * data, /* Read off the registers */ for (r = 0; r < n; ++r) - bitstream_write(ec, b[(n-1)-r], 8); + qr_bitstream_write(ec, b[(n-1)-r], 8); free(g); free(b); return ec; fail: free(b); - bitstream_destroy(ec); + qr_bitstream_destroy(ec); return 0; } diff --git a/lpg/libqr/rs.h b/lpg/libqr/rs.h index e640044..c87d852 100644 --- a/lpg/libqr/rs.h +++ b/lpg/libqr/rs.h @@ -1,9 +1,9 @@ #ifndef RS_H #define RS_H -#include "bitstream.h" +#include "qr-bitstream.h" -struct bitstream * rs_generate_words(struct bitstream * data, +struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, size_t data_words, size_t rs_words); diff --git a/lpg/libqr/test.c b/lpg/libqr/test.c index 035908b..4e288af 100644 --- a/lpg/libqr/test.c +++ b/lpg/libqr/test.c @@ -4,7 +4,7 @@ #include #include -#include "bitstream.h" +#include "qr-bitstream.h" #include "code-common.h" int main() { -- cgit v1.2.3-70-g09d2 From 36f38e01ddd23f332374093fa213ca08429729b1 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Mon, 28 Sep 2009 22:09:47 +0900 Subject: QR masks --- lpg/libqr/Makefile | 1 + lpg/libqr/qr-bitmap.c | 19 +++++++++++++++++++ lpg/libqr/qr-bitmap.h | 2 ++ lpg/libqr/qr-mask.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/qr-mask.h | 10 ++++++++++ 5 files changed, 78 insertions(+) create mode 100644 lpg/libqr/qr-mask.c create mode 100644 lpg/libqr/qr-mask.h diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index 49f89d4..5eba18b 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -9,6 +9,7 @@ OBJECTS := code-common.o \ qr-bitmap-pbm.o \ qr-bitmap-render.o \ qr-bitstream.o \ + qr-mask.o \ rs-encode.o CFLAGS := -std=c89 -pedantic -I. -Wall diff --git a/lpg/libqr/qr-bitmap.c b/lpg/libqr/qr-bitmap.c index e42b550..1a5ca52 100644 --- a/lpg/libqr/qr-bitmap.c +++ b/lpg/libqr/qr-bitmap.c @@ -48,6 +48,25 @@ void qr_bitmap_destroy(struct qr_bitmap * bmp) } } +struct qr_bitmap * qr_bitmap_clone(const struct qr_bitmap * src) +{ + struct qr_bitmap * bmp; + size_t size; + + bmp = qr_bitmap_create(src->width, src->height, !!src->mask); + if (!bmp) + return 0; + + assert(bmp->stride == src->stride); + + size = bmp->width * bmp->stride; + memcpy(bmp->bits, src->bits, size); + if (bmp->mask) + memcpy(bmp->mask, src->mask, size); + + return bmp; +} + void qr_bitmap_merge(struct qr_bitmap * dest, const struct qr_bitmap * src) { unsigned char * d, * s, * m; diff --git a/lpg/libqr/qr-bitmap.h b/lpg/libqr/qr-bitmap.h index d60049a..936b23d 100644 --- a/lpg/libqr/qr-bitmap.h +++ b/lpg/libqr/qr-bitmap.h @@ -11,6 +11,8 @@ struct qr_bitmap { struct qr_bitmap * qr_bitmap_create(int width, int height, int masked); void qr_bitmap_destroy(struct qr_bitmap *); +struct qr_bitmap * qr_bitmap_clone(const 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, diff --git a/lpg/libqr/qr-mask.c b/lpg/libqr/qr-mask.c new file mode 100644 index 0000000..2a63c0b --- /dev/null +++ b/lpg/libqr/qr-mask.c @@ -0,0 +1,46 @@ +#include +#include +#include "qr-bitmap.h" +#include "qr-mask.h" + +struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, + unsigned int mask) +{ + struct qr_bitmap * bmp; + int i, j; + + if (mask & ~0x7) + return 0; + + bmp = qr_bitmap_clone(orig); + if (!bmp) + return 0; + + /* Slow version for now; we can optimize later */ + + for (i = 0; i < bmp->height; ++i) { + unsigned char * p = bmp->bits + i * bmp->stride; + + for (j = 0; j < bmp->width; ++j) { + int bit = j % CHAR_BIT; + size_t off = j / CHAR_BIT; + int t; + + switch (mask) { + case 0: t = (i + j) % 2; break; + case 1: t = i % 2; break; + case 2: t = j % 3; break; + case 3: t = (i + j) % 3; break; + case 4: t = (i/2 + j/3) % 2; break; + case 5: t = ((i*j) % 2) + ((i*j) % 3); break; + case 6: t = (((i*j) % 2) + ((i*j) % 3)) % 2; break; + case 7: t = (((i*j) % 3) + ((i+j) % 2)) % 2; break; + } + + p[off] ^= (t == 0) << bit; + } + } + + return bmp; +} + diff --git a/lpg/libqr/qr-mask.h b/lpg/libqr/qr-mask.h new file mode 100644 index 0000000..b3f3523 --- /dev/null +++ b/lpg/libqr/qr-mask.h @@ -0,0 +1,10 @@ +#ifndef QR_MASK_H +#define QR_MASK_H + +#include "qr-bitmap.h" + +struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, + unsigned int mask); + +#endif + -- cgit v1.2.3-70-g09d2 From 1349e7a3e3dc15a9ac5e571a3b941bf6883cf8bb Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Mon, 28 Sep 2009 23:40:34 +0900 Subject: apply (incorrect!) mask to generated code --- lpg/libqr/code-create.c | 69 ++++++++++++++++++++++++++++++++++++------------- lpg/libqr/code-layout.c | 52 ++++++++++++++++++++++++++++--------- lpg/libqr/code-layout.h | 4 ++- lpg/libqr/qr-bitmap.c | 2 +- 4 files changed, 95 insertions(+), 32 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index c6451ac..ef419d3 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -6,10 +6,15 @@ #include "code-common.h" #include "code-layout.h" #include "data-common.h" +#include "qr-mask.h" #include "rs.h" #define MIN(a, b) ((b) < (a) ? (b) : (a)) +/* FIXME: the static functions should be in a better + * order, with prototypes. + */ + #include static void x_dump(struct qr_bitstream * bits) { @@ -27,44 +32,64 @@ static void x_dump(struct qr_bitstream * bits) printf("\n"); } -static void setpx(struct qr_code * code, int x, int y) +static int mask_data(struct qr_code * code) +{ + /* XXX */ + code->modules = qr_mask_apply(code->modules, 2); + return 2; +} + +static void setpx(struct qr_bitmap * bmp, int x, int y) { - size_t off = y * code->modules->stride + x / CHAR_BIT; + size_t off = y * bmp->stride + x / CHAR_BIT; unsigned char bit = 1 << (x % CHAR_BIT); - code->modules->bits[off] |= bit; + bmp->bits[off] |= bit; } -static void draw_locator(struct qr_code * code, int x, int y) +static void draw_locator(struct qr_bitmap * bmp, int x, int y) { int i; for (i = 0; i < 6; ++i) { - setpx(code, x + i, y + 0); - setpx(code, x + 6, y + i); - setpx(code, x + i + 1, y + 6); - setpx(code, x, y + i + 1); + setpx(bmp, x + i, y + 0); + setpx(bmp, x + 6, y + i); + setpx(bmp, x + i + 1, y + 6); + setpx(bmp, x, y + i + 1); } for (i = 0; i < 9; ++i) - setpx(code, x + 2 + i % 3, y + 2 + i / 3); + setpx(bmp, x + 2 + i % 3, y + 2 + i / 3); } -static void draw_fixed_bits(struct qr_code * code) +static int draw_functional(struct qr_code * code, + unsigned int mask) { + struct qr_bitmap * bmp; int dim = code_side_length(code->format); int i; + bmp = qr_bitmap_create(dim, dim, 0); + if (!bmp) + return -1; + /* Locator pattern */ - draw_locator(code, 0, 0); - draw_locator(code, 0, dim - 7); - draw_locator(code, dim - 7, 0); + draw_locator(bmp, 0, 0); + draw_locator(bmp, 0, dim - 7); + draw_locator(bmp, dim - 7, 0); /* Timing pattern */ for (i = 8; i < dim - 8; i += 2) { - setpx(code, i, 6); - setpx(code, 6, i); + setpx(bmp, i, 6); + setpx(bmp, 6, i); } /* XXX: alignment pattern */ + /* XXX: mask, format info */ + + qr_bitmap_merge(bmp, code->modules); + qr_bitmap_destroy(code->modules); + code->modules = bmp; + + return 0; } static int pad_data(struct qr_bitstream * bits, size_t limit) @@ -200,6 +225,7 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, struct qr_code * code; struct qr_bitstream * bits = 0; struct qr_iterator * layout; + int mask; size_t dim; code = malloc(sizeof(*code)); @@ -209,17 +235,17 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, dim = code_side_length(data->format); code->format = data->format; - code->modules = qr_bitmap_create(dim, dim, 0); + code->modules = qr_bitmap_create(dim, dim, 1); if (!code->modules) goto fail; - draw_fixed_bits(code); - bits = make_data(data->format, ec, data->bits); if (!bits) goto fail; + qr_layout_init_mask(code); + layout = qr_layout_begin(code); if (!layout) goto fail; @@ -229,6 +255,13 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, qr_layout_write(layout, qr_bitstream_read(bits, 8)); qr_layout_end(layout); + mask = mask_data(code); + if (mask < 0) + goto fail; + + if (draw_functional(code, mask) != 0) + goto fail; + exit: if (bits) qr_bitstream_destroy(bits); diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 09f29a8..46d2800 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -1,7 +1,10 @@ +#include #include #include +#include #include "code-common.h" #include "code-layout.h" +#include "qr-bitmap.h" struct qr_iterator { struct qr_code * code; @@ -13,24 +16,49 @@ struct qr_iterator { unsigned char * p; }; -static int is_data_bit(const struct qr_iterator * i) +void qr_layout_init_mask(struct qr_code * code) { - if (i->row == 6 || i->column == 6) /* timing */ - return 0; + int x, y; + int dim = code_side_length(code->format); + struct qr_bitmap * bmp = code->modules; + + assert(bmp->mask); + + memset(bmp->mask, 0, bmp->height * bmp->stride); + + /* slow and stupid, but I'm sleepy */ + for (y = 0; y < bmp->height; ++y) { + unsigned char * row = bmp->mask + y * bmp->stride; + for (x = 0; x < bmp->width; ++x) { + unsigned char bit = 1 << (x % CHAR_BIT); + int off = x / CHAR_BIT; + + if (x == 6 || y == 6) /* timing */ + continue; + + if (x < 9 && y < 9) /* top-left */ + continue; - if (i->column < 9 && i->row < 9) /* top-left */ - return 0; + if (x >= dim - 8 && y < 9) /* top-right */ + continue; - if (i->column >= i->dim - 8 && i->row < 9) /* top-right */ - return 0; + if (x < 9 && y >= dim - 8) /* bottom-left */ + continue; - if (i->column < 9 && i->row >= i->dim - 8) /* bottom-left */ - return 0; + /* XXX: format data */ + /* XXX: alignment pattern */ - /* XXX: format data */ - /* XXX: alignment pattern */ + row[off] |= bit; + } + } +} + +static int is_data_bit(const struct qr_iterator * i) +{ + unsigned char bit = 1 << (i->column % CHAR_BIT); + int off = (i->row * i->code->modules->stride) + (i->column / CHAR_BIT); - return 1; + return i->code->modules->mask[off] & bit; } static void set_pointer(struct qr_iterator * i) diff --git a/lpg/libqr/code-layout.h b/lpg/libqr/code-layout.h index 79e9730..3390548 100644 --- a/lpg/libqr/code-layout.h +++ b/lpg/libqr/code-layout.h @@ -3,7 +3,9 @@ struct qr_iterator; -struct qr_iterator * qr_layout_begin(struct qr_code *); +void qr_layout_init_mask(struct qr_code *); + +struct qr_iterator * qr_layout_begin(struct qr_code * code); unsigned int qr_layout_read(struct qr_iterator *); void qr_layout_write(struct qr_iterator *, unsigned int); void qr_layout_end(struct qr_iterator *); diff --git a/lpg/libqr/qr-bitmap.c b/lpg/libqr/qr-bitmap.c index 1a5ca52..2bd0c50 100644 --- a/lpg/libqr/qr-bitmap.c +++ b/lpg/libqr/qr-bitmap.c @@ -29,7 +29,7 @@ struct qr_bitmap * qr_bitmap_create(int width, int height, int masked) out->mask = malloc(out->stride * width); if (!out->mask) goto fail; - memset(out->bits, 0xFF, size); + memset(out->mask, 0xFF, size); } return out; -- cgit v1.2.3-70-g09d2 From 7b61f48876af1c0a91c32355862e8bcb2e6d126c Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Tue, 29 Sep 2009 17:16:07 +0900 Subject: add TODO --- lpg/libqr/TODO | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) create mode 100644 lpg/libqr/TODO diff --git a/lpg/libqr/TODO b/lpg/libqr/TODO new file mode 100644 index 0000000..6efa259 --- /dev/null +++ b/lpg/libqr/TODO @@ -0,0 +1,25 @@ +* Get sample generated OK +* Fix generation for all sizes (alignment pattern) +* Auto-sizing for data +* Sample app +* Merge some files +* Fix XXX, TODO +* Tidy code +* RELEASE v0.1 + +* Parsing +* RELEASE v0.2 + +* Detection +* RELEASE v0.3 + +* Test suite +* No-malloc +* Optimize +* Documentation +* RELEASE v0.4 (BETA) + +* RELEASE v1.0 + +* Other data types + -- cgit v1.2.3-70-g09d2 From 81eee33d754108de281fd279e0859de80a0e2586 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Tue, 29 Sep 2009 18:59:02 +0900 Subject: Fix bit/byte bug in bitstream --- lpg/libqr/qr-bitstream.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lpg/libqr/qr-bitstream.c b/lpg/libqr/qr-bitstream.c index 3df2549..b223f4c 100644 --- a/lpg/libqr/qr-bitstream.c +++ b/lpg/libqr/qr-bitstream.c @@ -30,14 +30,13 @@ static size_t bits_to_bytes(size_t bits) static int ensure_available(struct qr_bitstream * stream, size_t bits) { size_t need_bits = stream->pos + bits; - size_t need_bytes = need_bits / CHAR_BIT + ((need_bits % CHAR_BIT) ? 0 : 1); size_t newsize; - if (stream->bufsiz >= need_bytes) + if (stream->bufsiz * CHAR_BIT >= need_bits) return 0; - newsize = MAX(stream->bufsiz, 100); - while (newsize < need_bytes) + newsize = MAX(stream->bufsiz, 100) * CHAR_BIT; + while (newsize < need_bits) newsize *= 2; return qr_bitstream_resize(stream, newsize); -- cgit v1.2.3-70-g09d2 From 27ed9a6bb8e101f1eee5a953e9985f4d631a4aa9 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sun, 4 Oct 2009 14:35:01 +0900 Subject: Auto-select mask --- lpg/libqr/code-create.c | 206 ++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 199 insertions(+), 7 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index ef419d3..5582a30 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -11,6 +11,15 @@ #define MIN(a, b) ((b) < (a) ? (b) : (a)) +static int mask_data(struct qr_code * code); +static int score_mask(const struct qr_bitmap * bmp); +static int score_runs(const struct qr_bitmap * bmp, int base); +static int count_2blocks(const struct qr_bitmap * bmp); +static int count_locators(const struct qr_bitmap * bmp); +static int calc_bw_balance(const struct qr_bitmap * bmp); +static int get_px(const struct qr_bitmap * bmp, int x, int y); +static int get_mask(const struct qr_bitmap * bmp, int x, int y); + /* FIXME: the static functions should be in a better * order, with prototypes. */ @@ -32,13 +41,6 @@ static void x_dump(struct qr_bitstream * bits) printf("\n"); } -static int mask_data(struct qr_code * code) -{ - /* XXX */ - code->modules = qr_mask_apply(code->modules, 2); - return 2; -} - static void setpx(struct qr_bitmap * bmp, int x, int y) { size_t off = y * bmp->stride + x / CHAR_BIT; @@ -274,3 +276,193 @@ fail: goto exit; } +static int mask_data(struct qr_code * code) +{ + struct qr_bitmap * mask, * test; + int selected, score; + int i, best; + + mask = 0; + + /* Generate bitmap for each mask and evaluate */ + for (i = 0; i < 8; ++i) { + test = qr_mask_apply(code->modules, i); + if (!test) { + qr_bitmap_destroy(mask); + return -1; + } + score = score_mask(test); + printf("mask %d scored %d\n", i, score); + if (!mask || score < best) { + best = score; + selected = i; + qr_bitmap_destroy(mask); + mask = test; + } else { + qr_bitmap_destroy(test); + } + } + printf("Selected mask %d (%d)\n", selected, best); + + qr_bitmap_destroy(code->modules); + code->modules = mask; + + return selected; +} + +static int score_mask(const struct qr_bitmap * bmp) +{ + const int N[4] = { 3, 3, 40, 10 }; + int score = 0; + + score += score_runs(bmp, N[0]); + score += N[1] * count_2blocks(bmp); + score += N[2] * count_locators(bmp); + score += N[3] * ((abs(calc_bw_balance(bmp) - 50) + 4) / 5); + + return score; +} + +static int score_runs(const struct qr_bitmap * bmp, int base) +{ + /* Runs of 5+n bits -> N[0] + i */ + int x, y, flip; + int score = 0; + int count, last; + + for (flip = 0; flip <= 1; ++flip) { + for (y = 0; y < bmp->height; ++y) { + count = 0; + for (x = 0; x < bmp->width; ++x) { + int mask, bit; + if (flip) { + mask = get_mask(bmp, y, x); + bit = get_mask(bmp, y, x); + } else { + mask = get_mask(bmp, x, y); + bit = get_px(bmp, x, y); + } + + if (mask && + (count == 0 || !!bit == !!last)) { + ++count; + last = bit; + } else { + if (count >= 5) + score += base + count - 5; + count = 0; + } + } + } + } + + return score; +} + +static int count_2blocks(const struct qr_bitmap * bmp) +{ + /* Count the number of 2x2 blocks (on or off) */ + int x, y; + int count = 0; + + /* Slow and stupid */ + for (y = 0; y < bmp->height - 1; ++y) { + for (x = 0; x < bmp->width - 1; ++x) { + if (get_mask(bmp, x, y) && + get_mask(bmp, x+1, y) && + get_mask(bmp, x, y+1) && + get_mask(bmp, x+1, y+1)) { + int v[4]; + v[0] = get_px(bmp, x, y); + v[1] = get_px(bmp, x+1, y); + v[2] = get_px(bmp, x, y+1); + v[3] = get_px(bmp, x+1, y+1); + if (!(v[0] || v[1] || v[2] || v[3]) || + (v[0] && v[1] && v[2] && v[3])) { + ++count; + } + } + } + } + + return count; +} + +static int count_locators(const struct qr_bitmap * bmp) +{ + /* 1:1:3:1:1 patterns -> N[2] */ + int x, y, flip; + int count = 0; + + for (flip = 0; flip <= 1; ++flip) { + for (y = 0; y < bmp->height - 7; ++y) { + for (x = 0; x < bmp->width - 7; ++x) { + int bits[7]; + int i; + + for (i = 0; i < 7; ++i) + if (!(flip ? get_mask(bmp, y, x+i) : get_mask(bmp, x+i, y))) + continue; + + for (i = 0; i < 7; ++i) + bits[i] = flip ? get_px(bmp, y, x+i) : get_px(bmp, x+i, y); + + if (!bits[0]) + for (i = 0; i < 7; ++i) + bits[i] = !bits[i]; + + if ( bits[0] && !bits[1] && bits[2] && + bits[3] && bits[4] && !bits[5] && + bits[6]) + ++count; + } + } + } + + return count; +} + +static int calc_bw_balance(const struct qr_bitmap * bmp) +{ + /* Calculate the proportion (in percent) of "on" bits */ + int x, y; + unsigned char bit; + long on, total; + + assert(bmp->mask); /* we only need this case */ + + on = total = 0; + for (y = 0; y < bmp->height; ++y) { + size_t off = y * bmp->stride; + unsigned char * bits = bmp->bits + off; + unsigned char * mask = bmp->mask + off; + + for (x = 0; x < bmp->width / CHAR_BIT; ++x, ++bits, ++mask) { + for (bit = 1; bit; bit <<= 1) { + int m = *mask & bit; + + total += !!m; + on += !!(*bits & m); + } + } + } + + return (on * 100) / total; +} + +static int get_px(const struct qr_bitmap * bmp, int x, int y) +{ + size_t off = y * bmp->stride + x / CHAR_BIT; + unsigned char bit = 1 << (x % CHAR_BIT); + + return bmp->bits[off] & bit; +} + +static int get_mask(const struct qr_bitmap * bmp, int x, int y) +{ + size_t off = y * bmp->stride + x / CHAR_BIT; + unsigned char bit = 1 << (x % CHAR_BIT); + + return bmp->mask[off] & bit; +} + -- cgit v1.2.3-70-g09d2 From ad59de83b7f82cb812d23ac2bb948ac32fe0ac71 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Thu, 8 Oct 2009 12:18:31 +0900 Subject: Render ec level, mask info bits --- lpg/libqr/code-create.c | 100 +++++++++++++++++++++++++++++++++++++++++++++++- lpg/libqr/qr/code.h | 8 ++-- 2 files changed, 102 insertions(+), 6 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 5582a30..9ce46f7 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -19,6 +19,12 @@ static int count_locators(const struct qr_bitmap * bmp); static int calc_bw_balance(const struct qr_bitmap * bmp); static int get_px(const struct qr_bitmap * bmp, int x, int y); static int get_mask(const struct qr_bitmap * bmp, int x, int y); +static int draw_format(struct qr_bitmap * bmp, + struct qr_code * code, + enum qr_ec_level ec, + int mask); +static int calc_format_bits(enum qr_ec_level ec, int mask); +static unsigned long gal_residue(unsigned long a, unsigned long m); /* FIXME: the static functions should be in a better * order, with prototypes. @@ -63,6 +69,7 @@ static void draw_locator(struct qr_bitmap * bmp, int x, int y) } static int draw_functional(struct qr_code * code, + enum qr_ec_level ec, unsigned int mask) { struct qr_bitmap * bmp; @@ -85,8 +92,13 @@ static int draw_functional(struct qr_code * code, } /* XXX: alignment pattern */ - /* XXX: mask, format info */ + /* Format info */ + setpx(bmp, 8, dim - 8); + if (draw_format(bmp, code, ec, mask) != 0) + return -1; + + /* Merge data */ qr_bitmap_merge(bmp, code->modules); qr_bitmap_destroy(code->modules); code->modules = bmp; @@ -261,7 +273,7 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, if (mask < 0) goto fail; - if (draw_functional(code, mask) != 0) + if (draw_functional(code, ec, mask) != 0) goto fail; exit: @@ -466,3 +478,87 @@ static int get_mask(const struct qr_bitmap * bmp, int x, int y) return bmp->mask[off] & bit; } +static int draw_format(struct qr_bitmap * bmp, + struct qr_code * code, + enum qr_ec_level ec, + int mask) +{ + int i; + size_t dim; + long bits; + + dim = bmp->width; + + bits = calc_format_bits(ec, mask); + if (bits < 0) + return -1; + + for (i = 0; i < 8; ++i) { + if (bits & 0x1) { + setpx(bmp, 8, i); + setpx(bmp, dim - 1 - i, 8); + } + bits >>= 1; + } + + for (i = 0; i < 7; ++i) { + if (bits & 0x1) { + setpx(bmp, 8, dim - 7 + i); + setpx(bmp, 6 - i + (i == 0), 8); + } + bits >>= 1; + } + + /* XXX: size info for 7~40 */ + + return 0; +} + +static int calc_format_bits(enum qr_ec_level ec, int mask) +{ + int bits; + + bits = (ec & 0x3) << 3 | (mask & 0x7); + + /* Compute (15, 5) BCH code with + * G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1 + */ + + bits <<= 15 - 5; + bits |= (unsigned int)gal_residue(bits, 0x537); + + /* XOR mask: 101 0100 0001 0010 */ + bits ^= 0x5412; + + return bits; +} + +/* Calculate the residue of a modulo m */ +static unsigned long gal_residue(unsigned long a, + unsigned long m) +{ + unsigned long o = 1; + int n = 1; + + /* Find one past the highest bit of the modulus */ + while (m & ~(o - 1)) + o <<= 1; + + /* Find the highest n such that O(m * x^n) <= O(a) */ + while (a & ~(o - 1)) { + o <<= 1; + ++n; + } + + /* For each n, try to reduce a by (m * x^n) */ + while (n--) { + o >>= 1; + + /* o is the highest bit of (m * x^n) */ + if (a & o) + a ^= m << n; + } + + return a; +} + diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h index 56a9884..dba0040 100644 --- a/lpg/libqr/qr/code.h +++ b/lpg/libqr/qr/code.h @@ -5,10 +5,10 @@ #include "types.h" enum qr_ec_level { - QR_EC_LEVEL_L, - QR_EC_LEVEL_M, - QR_EC_LEVEL_Q, - QR_EC_LEVEL_H + QR_EC_LEVEL_L = 0x1, + QR_EC_LEVEL_M = 0x0, + QR_EC_LEVEL_Q = 0x3, + QR_EC_LEVEL_H = 0x2 }; struct qr_code * qr_code_create(enum qr_ec_level ec, -- cgit v1.2.3-70-g09d2 From 62e8a6f2ad89be06c7e649c0fc4c564ecad2d070 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Thu, 8 Oct 2009 14:38:37 +0900 Subject: code format --> version --- lpg/libqr/code-common.c | 15 +++++---------- lpg/libqr/code-common.h | 6 ++---- lpg/libqr/code-create.c | 17 ++++++++--------- lpg/libqr/code-layout.c | 4 ++-- lpg/libqr/data-common.c | 6 +++--- lpg/libqr/data-common.h | 4 ++-- lpg/libqr/data-create.c | 14 +++++++------- lpg/libqr/data-parse.c | 8 ++++---- 8 files changed, 33 insertions(+), 41 deletions(-) diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index 32f6492..dc2a8f0 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -14,26 +14,21 @@ void qr_code_destroy(struct qr_code * code) int qr_code_width(const struct qr_code * code) { - return code_side_length(code->format); + return code->version * 4 + 17; } -int code_side_length(int format) +size_t code_total_capacity(int version) { - return format * 4 + 17; -} - -size_t code_total_capacity(int format) -{ - int side = format * 4 + 17; + int side = version * 4 + 17; - int alignment_side = format > 1 ? (format / 7) + 2 : 0; + int alignment_side = version > 1 ? (version / 7) + 2 : 0; int alignment_count = alignment_side >= 2 ? alignment_side * alignment_side - 3 : 0; int locator_bits = 8*8*3; - int format_bits = 8*4 - 1 + (format >= 7 ? 6*3*2 : 0); + int format_bits = 8*4 - 1 + (version >= 7 ? 6*3*2 : 0); int timing_bits = 2 * (side - 8*2 - (alignment_side > 2 ? (alignment_side - 2) * 5 : 0)); diff --git a/lpg/libqr/code-common.h b/lpg/libqr/code-common.h index cf96217..11538d8 100644 --- a/lpg/libqr/code-common.h +++ b/lpg/libqr/code-common.h @@ -6,13 +6,11 @@ #include "qr-bitmap.h" struct qr_code { - int format; + int version; struct qr_bitmap * modules; }; -int code_side_length(int format); - -size_t code_total_capacity(int format); +size_t code_total_capacity(int version); #endif diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 9ce46f7..6c56f45 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -73,7 +73,7 @@ static int draw_functional(struct qr_code * code, unsigned int mask) { struct qr_bitmap * bmp; - int dim = code_side_length(code->format); + int dim = qr_code_width(code); int i; bmp = qr_bitmap_create(dim, dim, 0); @@ -146,11 +146,11 @@ static int pad_data(struct qr_bitstream * bits, size_t limit) return 0; } -static struct qr_bitstream * make_data(int format, - enum qr_ec_level ec, - struct qr_bitstream * data) +static struct qr_bitstream * make_data(int version, + enum qr_ec_level ec, + struct qr_bitstream * data) { - const size_t total_bits = code_total_capacity(format); + const size_t total_bits = code_total_capacity(version); const size_t total_words = total_bits / 8; size_t block_count, data_words, rs_words; size_t i; @@ -246,15 +246,14 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, if (!code) return 0; - dim = code_side_length(data->format); - - code->format = data->format; + code->version = data->version; + dim = qr_code_width(code); code->modules = qr_bitmap_create(dim, dim, 1); if (!code->modules) goto fail; - bits = make_data(data->format, ec, data->bits); + bits = make_data(data->version, ec, data->bits); if (!bits) goto fail; diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 46d2800..4be3871 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -19,7 +19,7 @@ struct qr_iterator { void qr_layout_init_mask(struct qr_code * code) { int x, y; - int dim = code_side_length(code->format); + int dim = qr_code_width(code); struct qr_bitmap * bmp = code->modules; assert(bmp->mask); @@ -110,7 +110,7 @@ struct qr_iterator * qr_layout_begin(struct qr_code * code) i = malloc(sizeof(*i)); if (i) { - i->dim = code_side_length(code->format); + i->dim = qr_code_width(code); i->code = code; i->column = i->dim - 1; i->row = i->dim - 1; diff --git a/lpg/libqr/data-common.c b/lpg/libqr/data-common.c index c64527a..ac2f198 100644 --- a/lpg/libqr/data-common.c +++ b/lpg/libqr/data-common.c @@ -29,7 +29,7 @@ void qr_free_data(struct qr_data * data) free(data); } -size_t get_size_field_length(int format, enum qr_data_type type) +size_t get_size_field_length(int version, enum qr_data_type type) { static const size_t QR_SIZE_LENGTHS[3][4] = { { 10, 9, 8, 8 }, @@ -46,9 +46,9 @@ size_t get_size_field_length(int format, enum qr_data_type type) default: return 0; } - if (format < 10) + if (version < 10) row = 0; - else if (format < 27) + else if (version < 27) row = 1; else row = 2; diff --git a/lpg/libqr/data-common.h b/lpg/libqr/data-common.h index 1522b09..bc2b381 100644 --- a/lpg/libqr/data-common.h +++ b/lpg/libqr/data-common.h @@ -6,14 +6,14 @@ #include "qr-bitstream.h" struct qr_data { - int format; /* 1 ~ 40 */ + int version; /* 1 ~ 40 */ struct qr_bitstream * bits; size_t offset; }; extern const enum qr_data_type QR_TYPE_CODES[16]; -size_t get_size_field_length(int format, enum qr_data_type); +size_t get_size_field_length(int version, enum qr_data_type); #endif diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c index a918413..2c2737f 100644 --- a/lpg/libqr/data-create.c +++ b/lpg/libqr/data-create.c @@ -18,7 +18,7 @@ static void write_type_and_length(struct qr_data * data, { (void)qr_bitstream_write(data->bits, QR_TYPE_CODES[type], 4); (void)qr_bitstream_write(data->bits, length, - get_size_field_length(data->format, type)); + get_size_field_length(data->version, type)); } static struct qr_data * encode_numeric(struct qr_data * data, @@ -28,7 +28,7 @@ static struct qr_data * encode_numeric(struct qr_data * data, struct qr_bitstream * stream = data->bits; size_t bits; - bits = 4 + get_size_field_length(data->format, QR_DATA_NUMERIC) + bits = 4 + get_size_field_length(data->version, QR_DATA_NUMERIC) + 10 * (length / 3); if (length % 3 == 1) @@ -106,7 +106,7 @@ static struct qr_data * encode_alpha(struct qr_data * data, struct qr_bitstream * stream = data->bits; size_t bits; - bits = 4 + get_size_field_length(data->format, QR_DATA_ALPHA) + bits = 4 + get_size_field_length(data->version, QR_DATA_ALPHA) + 11 * (length / 2) + 6 * (length % 2); @@ -150,7 +150,7 @@ static struct qr_data * encode_8bit(struct qr_data * data, struct qr_bitstream * stream = data->bits; size_t bits; - bits = 4 + get_size_field_length(data->format, QR_DATA_8BIT) + bits = 4 + get_size_field_length(data->version, QR_DATA_8BIT) + 8 * length; stream = data->bits; @@ -173,21 +173,21 @@ static struct qr_data * encode_kanji(struct qr_data * data, return 0; } -struct qr_data * qr_create_data(int format, +struct qr_data * qr_create_data(int version, enum qr_data_type type, const char * input, size_t length) { struct qr_data * data; - if (format < 1 || format > 40) + if (version < 1 || version > 40) return 0; data = malloc(sizeof(*data)); if (!data) return 0; - data->format = format; + data->version = version; data->bits = qr_bitstream_create(); data->offset = 0; diff --git a/lpg/libqr/data-parse.c b/lpg/libqr/data-parse.c index d497bdf..4868cd2 100644 --- a/lpg/libqr/data-parse.c +++ b/lpg/libqr/data-parse.c @@ -33,7 +33,7 @@ static enum qr_data_type parse_numeric(const struct qr_data * data, stream = data->bits; buffer = 0; - field_len = get_size_field_length(data->format, QR_DATA_NUMERIC); + field_len = get_size_field_length(data->version, QR_DATA_NUMERIC); if (qr_bitstream_remaining(stream) < field_len) goto invalid; @@ -93,7 +93,7 @@ static enum qr_data_type parse_alpha(const struct qr_data * data, stream = data->bits; buffer = 0; - field_len = get_size_field_length(data->format, QR_DATA_ALPHA); + field_len = get_size_field_length(data->version, QR_DATA_ALPHA); if (qr_bitstream_remaining(stream) < field_len) goto invalid; @@ -150,7 +150,7 @@ static enum qr_data_type parse_8bit(const struct qr_data * data, stream = data->bits; - field_len = get_size_field_length(data->format, QR_DATA_8BIT); + field_len = get_size_field_length(data->version, QR_DATA_8BIT); if (qr_bitstream_remaining(stream) < field_len) return QR_DATA_INVALID; @@ -201,7 +201,7 @@ int qr_get_data_length(const struct qr_data * data) case QR_DATA_ALPHA: case QR_DATA_8BIT: case QR_DATA_KANJI: - field_len = get_size_field_length(data->format, type); + field_len = get_size_field_length(data->version, type); break; default: /* unsupported / invalid */ -- cgit v1.2.3-70-g09d2 From 6359bfddcc5868093418784fa2e972581ebd82b6 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Thu, 8 Oct 2009 14:48:28 +0900 Subject: render version bits --- lpg/libqr/code-create.c | 29 ++++++++++++++++++++++++++++- lpg/libqr/code-layout.c | 9 ++++++++- 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 6c56f45..9936981 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -24,6 +24,7 @@ static int draw_format(struct qr_bitmap * bmp, enum qr_ec_level ec, int mask); static int calc_format_bits(enum qr_ec_level ec, int mask); +static long calc_version_bits(int version); static unsigned long gal_residue(unsigned long a, unsigned long m); /* FIXME: the static functions should be in a better @@ -508,7 +509,18 @@ static int draw_format(struct qr_bitmap * bmp, bits >>= 1; } - /* XXX: size info for 7~40 */ + if (code->version >= 7) { + bits = calc_version_bits(code->version); + + for (i = 0; i < 18; ++i) { + if (bits & 0x1) { + int a = i % 3, b = i / 3; + setpx(bmp, dim - 11 + a, b); + setpx(bmp, b, dim - 11 + a); + } + bits >>= 1; + } + } return 0; } @@ -532,6 +544,21 @@ static int calc_format_bits(enum qr_ec_level ec, int mask) return bits; } +static long calc_version_bits(int version) +{ + long bits; + + bits = version & 0x3F; + + /* (18, 6) BCH code + * G(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 + */ + bits <<= 18 - 6; + bits |= gal_residue(bits, 0x1F25); + + return bits; +} + /* Calculate the residue of a modulo m */ static unsigned long gal_residue(unsigned long a, unsigned long m) diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 4be3871..ed01112 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -45,7 +45,14 @@ void qr_layout_init_mask(struct qr_code * code) if (x < 9 && y >= dim - 8) /* bottom-left */ continue; - /* XXX: format data */ + /* version info */ + if (code->version >= 7) { + if (y < 6 && x >= dim - 11) + continue; + if (x < 6 && y >= dim - 11) + continue; + } + /* XXX: alignment pattern */ row[off] |= bit; -- cgit v1.2.3-70-g09d2 From ce330147acca10cd66c370847bdc3e824a83a0c6 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Thu, 8 Oct 2009 16:41:56 +0900 Subject: add qrgen sample app --- lpg/libqr/.gitignore | 2 +- lpg/libqr/Makefile | 20 ++--- lpg/libqr/code-common.c | 3 +- lpg/libqr/code-common.h | 2 +- lpg/libqr/code-layout.c | 2 +- lpg/libqr/qr-bitmap-pbm.c | 47 ---------- lpg/libqr/qr-bitmap-render.c | 2 +- lpg/libqr/qr-bitmap.c | 2 +- lpg/libqr/qr-bitmap.h | 31 ------- lpg/libqr/qr-mask.c | 2 +- lpg/libqr/qr-mask.h | 2 +- lpg/libqr/qr/bitmap.h | 27 ++++++ lpg/libqr/qrgen.c | 210 +++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/test.c | 53 ----------- 14 files changed, 255 insertions(+), 150 deletions(-) delete mode 100644 lpg/libqr/qr-bitmap-pbm.c delete mode 100644 lpg/libqr/qr-bitmap.h create mode 100644 lpg/libqr/qr/bitmap.h create mode 100644 lpg/libqr/qrgen.c delete mode 100644 lpg/libqr/test.c diff --git a/lpg/libqr/.gitignore b/lpg/libqr/.gitignore index dbfb6fb..41c2dbc 100644 --- a/lpg/libqr/.gitignore +++ b/lpg/libqr/.gitignore @@ -2,4 +2,4 @@ *.o *.a *.so -test +qrgen diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index 5eba18b..19e8791 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -1,12 +1,11 @@ OBJECTS := code-common.o \ - code-create.o \ - code-layout.o \ - code-parse.o \ - data-common.o \ - data-create.o \ - data-parse.o \ + code-create.o \ + code-layout.o \ + code-parse.o \ + data-common.o \ + data-create.o \ + data-parse.o \ qr-bitmap.o \ - qr-bitmap-pbm.o \ qr-bitmap-render.o \ qr-bitstream.o \ qr-mask.o \ @@ -16,15 +15,16 @@ CFLAGS := -std=c89 -pedantic -I. -Wall CFLAGS += -g #CFLAGS += -O3 -DNDEBUG -all : libqr test +all : libqr qrgen $(OBJECTS) : $(wildcard *.h qr/*.h) libqr : libqr.a($(OBJECTS)) -test : libqr.a test.c +qrgen : libqr qrgen.c + $(CC) $(CFLAGS) -o qrgen qrgen.c libqr.a .PHONY : clean clean: - $(RM) qr/*~ *~ *.o *.a *.so test + $(RM) qr/*~ *~ *.o *.a *.so qrgen diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index dc2a8f0..150dfc5 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -1,8 +1,7 @@ #include #include - +#include #include "code-common.h" -#include "qr-bitmap.h" void qr_code_destroy(struct qr_code * code) { diff --git a/lpg/libqr/code-common.h b/lpg/libqr/code-common.h index 11538d8..0459708 100644 --- a/lpg/libqr/code-common.h +++ b/lpg/libqr/code-common.h @@ -2,8 +2,8 @@ #define CODE_COMMON_H #include +#include #include "qr-bitstream.h" -#include "qr-bitmap.h" struct qr_code { int version; diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index ed01112..54947d1 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -2,9 +2,9 @@ #include #include #include +#include #include "code-common.h" #include "code-layout.h" -#include "qr-bitmap.h" struct qr_iterator { struct qr_code * code; diff --git a/lpg/libqr/qr-bitmap-pbm.c b/lpg/libqr/qr-bitmap-pbm.c deleted file mode 100644 index 3bcddb2..0000000 --- a/lpg/libqr/qr-bitmap-pbm.c +++ /dev/null @@ -1,47 +0,0 @@ -#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 index 4f6c921..197e947 100644 --- a/lpg/libqr/qr-bitmap-render.c +++ b/lpg/libqr/qr-bitmap-render.c @@ -2,7 +2,7 @@ #include #include -#include "qr-bitmap.h" +#include /* CHAR_BIT | mod_bits (multi-byte) */ static void render_line_1(unsigned char * out, diff --git a/lpg/libqr/qr-bitmap.c b/lpg/libqr/qr-bitmap.c index 2bd0c50..7d2d900 100644 --- a/lpg/libqr/qr-bitmap.c +++ b/lpg/libqr/qr-bitmap.c @@ -2,7 +2,7 @@ #include #include #include -#include "qr-bitmap.h" +#include struct qr_bitmap * qr_bitmap_create(int width, int height, int masked) { diff --git a/lpg/libqr/qr-bitmap.h b/lpg/libqr/qr-bitmap.h deleted file mode 100644 index 936b23d..0000000 --- a/lpg/libqr/qr-bitmap.h +++ /dev/null @@ -1,31 +0,0 @@ -#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 *); - -struct qr_bitmap * qr_bitmap_clone(const 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-mask.c b/lpg/libqr/qr-mask.c index 2a63c0b..7ff78a4 100644 --- a/lpg/libqr/qr-mask.c +++ b/lpg/libqr/qr-mask.c @@ -1,6 +1,6 @@ #include #include -#include "qr-bitmap.h" +#include #include "qr-mask.h" struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, diff --git a/lpg/libqr/qr-mask.h b/lpg/libqr/qr-mask.h index b3f3523..eb254af 100644 --- a/lpg/libqr/qr-mask.h +++ b/lpg/libqr/qr-mask.h @@ -1,7 +1,7 @@ #ifndef QR_MASK_H #define QR_MASK_H -#include "qr-bitmap.h" +#include struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, unsigned int mask); diff --git a/lpg/libqr/qr/bitmap.h b/lpg/libqr/qr/bitmap.h new file mode 100644 index 0000000..83e82ab --- /dev/null +++ b/lpg/libqr/qr/bitmap.h @@ -0,0 +1,27 @@ +#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 *); + +struct qr_bitmap * qr_bitmap_clone(const 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); + +#endif + diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c new file mode 100644 index 0000000..9899373 --- /dev/null +++ b/lpg/libqr/qrgen.c @@ -0,0 +1,210 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "qr-bitstream.h" +#include "code-common.h" + +struct config { + int version; + enum qr_ec_level ec; + enum qr_data_type dtype; + int ansi; + const char * input; +}; + +struct qr_code * create(int version, + enum qr_ec_level ec, + enum qr_data_type dtype, + const char * input) +{ + struct qr_data * data; + struct qr_code * code; + size_t len; + + len = strlen(input); + + data = qr_create_data(version, dtype, input, len); + + if (!data) { + /* BUG: this could also indicate OOM or + * some other error. + */ + fprintf(stderr, "Invalid data\n"); + exit(1); + } + + code = qr_code_create(ec, data); + + if (!code) { + perror("Failed to create code"); + qr_free_data(data); + exit(2); + } + + return code; +} + +void output_pbm(const struct qr_bitmap * bmp, const char * comment) +{ + unsigned char * row; + int x, y; + + puts("P1"); + + if (comment) + printf("# %s\n", comment); + + printf("%u %u\n", + (unsigned)bmp->width + 8, + (unsigned)bmp->height + 8); + + row = bmp->bits; + + for (y = -4; y < (int)bmp->height + 4; ++y) { + + if (y < 0 || y >= (int)bmp->height) { + for (x = 0; x < (int)bmp->width + 8; ++x) + printf("0 "); + putchar('\n'); + continue; + } + + printf("0 0 0 0 "); + + for (x = 0; x < (int)bmp->width; ++x) { + + int mask = 1 << x % CHAR_BIT; + int byte = row[x / CHAR_BIT]; + + printf("%c ", (byte & mask) ? '1' : '0'); + } + + puts("0 0 0 0"); + row += bmp->stride; + } +} + +void output_ansi(const struct qr_bitmap * bmp) +{ + const char * out[2] = { + " ", + "\033[7m \033[0m", + }; + + unsigned char * line; + int x, y; + + line = bmp->bits; + + for (y = 0; y < bmp->height; ++y) { + + for (x = 0; x < bmp->width; ++x) { + + int mask = 1 << (x % CHAR_BIT); + int byte = line[x / CHAR_BIT]; + + printf("%s", out[!!(byte & mask)]); + } + + putchar('\n'); + + line += bmp->stride; + } +} + +void show_help() { + fprintf(stderr, "(help message)\n"); +} + +void set_default_config(struct config * conf) +{ + conf->version = 1; + conf->ec = QR_EC_LEVEL_M; + conf->dtype = QR_DATA_NUMERIC; + conf->ansi = 1; + conf->input = "01234567"; +} + +void parse_options(int argc, char ** argv, struct config * conf) +{ + int c; + + for (;;) { + c = getopt(argc, argv, ":?vetap"); + + if (c == -1) /* no more options */ + break; + + switch (c) { + case '?': /* help */ + show_help(); + exit(0); + break; + case 'v': /* version */ + if (!optarg) { + fprintf(stderr, "No version\n"); + exit(1); + } + conf->version = atoi(optarg); + if (conf->version < 1 || conf->version > 40) { + fprintf(stderr, + "Version must be between 1 and 40\n"); + exit(1); + } + break; + case 'e': /* ec */ + fprintf(stderr, "XXX: ignored \"ec\"\n"); break; + case 't': /* type */ + fprintf(stderr, "XXX: ignored \"type\"\n"); break; + case 'a': /* ansi */ + conf->ansi = 1; break; + case 'p': /* pnm */ + conf->ansi = 0; break; + case ':': default: + fprintf(stderr, "Unknown option: \"%s\"\n", + argv[optind]); + exit(1); + break; + } + } + + + if (optind < argc) + conf->input = argv[optind++]; + + if (!conf->input) { + fprintf(stderr, "No data (try -? for help)\n"); + exit(1); + } +} + +int main(int argc, char ** argv) { + + struct config conf; + struct qr_code * code; + + set_default_config(&conf); + parse_options(argc, argv, &conf); + + code = create(conf.version, + conf.ec, + conf.dtype, + conf.input); + + if (conf.ansi) + output_ansi(code->modules); + else + output_pbm(code->modules, "qrgen v0.1"); + + qr_code_destroy(code); + + return 0; +} + diff --git a/lpg/libqr/test.c b/lpg/libqr/test.c deleted file mode 100644 index 4e288af..0000000 --- a/lpg/libqr/test.c +++ /dev/null @@ -1,53 +0,0 @@ -#include -#include -#include -#include -#include - -#include "qr-bitstream.h" -#include "code-common.h" - -int main() { - - struct qr_code * code; - struct qr_data * data; - enum qr_data_type type; - char *str; - size_t len; - - type = QR_DATA_NUMERIC; - str = "01234567"; - len = strlen(str); - - data = qr_create_data(1, type, str, len); - assert(data); - assert(qr_get_data_type(data) == type); - assert(qr_get_data_length(data) == len); - - type = qr_parse_data(data, &str, &len); - printf("[%d] %d\n", type, (int)len); - printf("\"%s\"\n", str); - - code = qr_code_create(QR_EC_LEVEL_M, data); - assert(code); - - printf("Code width %d\n", qr_code_width(code)); - - { - /* Hack: render the code using ANSI terminal art */ - char buf[80*25]; - int x, y; - - 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) { - printf("%s ", buf[y*80+x]?"\033[7m":"\033[0m"); - } - printf("\033[0m|\n"); - } - } - - return 0; -} - -- cgit v1.2.3-70-g09d2 From 5d9157331d8dd08010790bc9d17053bac279f524 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Thu, 8 Oct 2009 16:48:51 +0900 Subject: debug output to stderr --- lpg/libqr/code-create.c | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 9936981..2e0a0b2 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -39,13 +39,13 @@ static void x_dump(struct qr_bitstream * bits) qr_bitstream_seek(bits, 0); n = qr_bitstream_size(bits); for (i = 0; i < n; ++i) { - printf("%d", qr_bitstream_read(bits, 1)); + fprintf(stderr, "%d", qr_bitstream_read(bits, 1)); if (i % 8 == 7) - printf(" "); + fputc(' ', stderr); if ((i+1) % (7 * 8) == 0) - printf("\n"); + fputc('\n', stderr); } - printf("\n"); + fputc('\n', stderr); } static void setpx(struct qr_bitmap * bmp, int x, int y) @@ -185,7 +185,7 @@ static struct qr_bitstream * make_data(int version, if (pad_data(dcopy, data_words * 8) != 0) goto fail; - puts("Pad data:"); + fputs("Pad data:\n", stderr); x_dump(dcopy); /* Make space for the RS blocks */ @@ -195,7 +195,7 @@ static struct qr_bitstream * make_data(int version, /* Generate RS codewords */ qr_bitstream_seek(dcopy, 0); - puts("Generate RS blocks:"); + fputs("Generate RS blocks:\n", stderr); for (i = 0; i < block_count; ++i) { /* XXX: some blocks may be longer */ blocks[i] = rs_generate_words(dcopy, data_words, rs_words); @@ -215,7 +215,7 @@ static struct qr_bitstream * make_data(int version, qr_bitstream_cat(out, blocks[0]); qr_bitstream_write(out, 0, total_bits - total_words * 8); - puts("Final bitstream:"); + fputs("Final bitstream:\n", stderr); x_dump(out); exit: if (blocks) { @@ -304,7 +304,7 @@ static int mask_data(struct qr_code * code) return -1; } score = score_mask(test); - printf("mask %d scored %d\n", i, score); + fprintf(stderr, "mask %d scored %d\n", i, score); if (!mask || score < best) { best = score; selected = i; @@ -314,7 +314,7 @@ static int mask_data(struct qr_code * code) qr_bitmap_destroy(test); } } - printf("Selected mask %d (%d)\n", selected, best); + fprintf(stderr, "Selected mask %d (%d)\n", selected, best); qr_bitmap_destroy(code->modules); code->modules = mask; -- cgit v1.2.3-70-g09d2 From 0b61708d12b30ce6dc174554794d674eb9f99dad Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Thu, 8 Oct 2009 17:41:19 +0900 Subject: fix option handling --- lpg/libqr/qrgen.c | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index 9899373..8b9f1f0 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -137,39 +137,45 @@ void parse_options(int argc, char ** argv, struct config * conf) int c; for (;;) { - c = getopt(argc, argv, ":?vetap"); + c = getopt(argc, argv, ":hv:e:t:ap"); if (c == -1) /* no more options */ break; switch (c) { - case '?': /* help */ + case 'h': /* help */ show_help(); exit(0); break; case 'v': /* version */ - if (!optarg) { - fprintf(stderr, "No version\n"); - exit(1); - } conf->version = atoi(optarg); if (conf->version < 1 || conf->version > 40) { fprintf(stderr, - "Version must be between 1 and 40\n"); + "Version must be between 1 and 40\n"); exit(1); } break; case 'e': /* ec */ - fprintf(stderr, "XXX: ignored \"ec\"\n"); break; + fprintf(stderr, "XXX: ignored \"ec\"\n"); + break; case 't': /* type */ - fprintf(stderr, "XXX: ignored \"type\"\n"); break; + fprintf(stderr, "XXX: ignored \"type\"\n"); + break; case 'a': /* ansi */ conf->ansi = 1; break; case 'p': /* pnm */ conf->ansi = 0; break; - case ':': default: - fprintf(stderr, "Unknown option: \"%s\"\n", - argv[optind]); + case ':': + fprintf(stderr, + "Argument \"%s\" missing parameter\n", + argv[optind-1]); + exit(1); + break; + case '?': default: + fprintf(stderr, + "Invalid argument: \"%s\"\n" + "Try -h for help\n", + argv[optind-1]); exit(1); break; } @@ -180,7 +186,7 @@ void parse_options(int argc, char ** argv, struct config * conf) conf->input = argv[optind++]; if (!conf->input) { - fprintf(stderr, "No data (try -? for help)\n"); + fprintf(stderr, "No data (try -h for help)\n"); exit(1); } } -- cgit v1.2.3-70-g09d2 From 4eee8658be637fde410f429e69e86b034cd39185 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sun, 1 Nov 2009 22:54:33 +0900 Subject: support for multiple ec blocks --- lpg/libqr/Makefile | 3 +- lpg/libqr/capacity.c | 88 ++++++++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/code-create.c | 49 +++++++++++++++------------ lpg/libqr/qr-bitstream.c | 18 ++++++++-- lpg/libqr/qr-bitstream.h | 6 +++- 5 files changed, 138 insertions(+), 26 deletions(-) create mode 100644 lpg/libqr/capacity.c diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index 19e8791..3a6af6f 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -1,4 +1,5 @@ -OBJECTS := code-common.o \ +OBJECTS := capacity.o \ + code-common.o \ code-create.o \ code-layout.o \ code-parse.o \ diff --git a/lpg/libqr/capacity.c b/lpg/libqr/capacity.c new file mode 100644 index 0000000..4b513af --- /dev/null +++ b/lpg/libqr/capacity.c @@ -0,0 +1,88 @@ +/* FIXME: don't like big tables of data */ + +const int QR_DATA_WORD_COUNT[40][4] = { + 19, 16, 13, 9, + 34, 28, 22, 16, + 55, 44, 34, 26, + 80, 64, 48, 36, + 108, 86, 62, 46, + 136, 108, 76, 60, + 156, 124, 88, 66, + 194, 154, 110, 86, + 232, 182, 132, 100, + 274, 216, 154, 122, + 324, 254, 180, 140, + 370, 290, 206, 158, + 428, 334, 244, 180, + 461, 365, 261, 197, + 523, 415, 295, 223, + 589, 453, 325, 253, + 647, 507, 367, 283, + 721, 563, 397, 313, + 795, 627, 445, 341, + 861, 669, 485, 385, + 932, 714, 512, 406, + 1006, 782, 568, 442, + 1094, 860, 614, 464, + 1174, 914, 664, 514, + 1276, 1000, 718, 538, + 1370, 1062, 754, 596, + 1468, 1128, 808, 628, + 1531, 1193, 871, 661, + 1631, 1267, 911, 701, + 1735, 1373, 985, 745, + 1845, 1455, 1033, 793, + 1955, 1541, 1115, 845, + 2071, 1631, 1171, 901, + 2191, 1725, 1231, 961, + 2306, 1812, 1286, 986, + 2434, 1914, 1351, 1054, + 2566, 1992, 1426, 1096, + 2812, 2216, 1582, 1222, + 2956, 2334, 1666, 1276 +}; + +/* I'm sure we can calculate these values */ +const int QR_RS_BLOCK_COUNT[40][4][2] = { + 1, 0, 1, 0, 1, 0, 1, 0, /* 1 */ + 1, 0, 1, 0, 1, 0, 1, 0, /* 2 */ + 1, 0, 1, 0, 2, 0, 2, 0, /* 3 */ + 1, 0, 2, 0, 2, 0, 4, 0, /* 4 */ + 1, 0, 2, 0, 2, 0, 2, 0, + 2, 0, 4, 0, 4, 0, 4, 0, + 2, 0, 4, 0, 2, 4, 4, 1, + 2, 0, 2, 2, 4, 2, 4, 2, /* 8 */ + 2, 0, 3, 2, 4, 4, 4, 4, + 2, 2, 4, 1, 6, 2, 6, 2, + 4, 0, 1, 4, 4, 4, 3, 8, + 2, 2, 6, 2, 4, 6, 7, 4, + 4, 0, 8, 1, 8, 4, 12, 4, + 3, 1, 4, 5, 11, 5, 11, 5, /* 14 */ + 5, 1, 5, 5, 5, 7, 11, 7, + 5, 1, 7, 3, 15, 2, 3, 13, + 1, 5, 10, 1, 1, 15, 2, 17, + 5, 1, 9, 4, 17, 1, 2, 19, + 3, 4, 3, 11, 17, 4, 9, 16, /* 19 */ + 3, 5, 3, 13, 15, 5, 15, 10, + 4, 4, 17, 0, 17, 6, 19, 6, + 2, 7, 17, 0, 7, 16, 34, 0, + 4, 5, 4, 14, 11, 14, 16, 14, + 6, 4, 6, 14, 11, 16, 30, 2, + 8, 4, 8, 13, 7, 22, 22, 13, /* 25 */ + 10, 2, 19, 4, 28, 6, 33, 4, + 8, 4, 22, 3, 8, 26, 12, 28, + 3, 10, 3, 23, 4, 31, 11, 31, + 7, 7, 21, 7, 1, 37, 19, 26, + 5, 10, 19, 10, 15, 25, 23, 25, /* 30 */ + 13, 3, 2, 29, 42, 1, 23, 28, + 17, 0, 10, 23, 10, 35, 19, 35, + 17, 1, 14, 21, 29, 19, 11, 46, + 13, 6, 14, 23, 44, 7, 59, 1, + 12, 7, 12, 26, 39, 14, 22, 41, /* 35 */ + 6, 14, 6, 34, 46, 10, 2, 64, + 17, 4, 29, 14, 49, 10, 24, 46, + 4, 18, 13, 32, 48, 14, 42, 32, + 20, 4, 40, 7, 43, 22, 10, 67, + 19, 6, 18, 31, 34, 34, 20, 61 /* 40 */ +}; + diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 2e0a0b2..36ebb24 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -11,6 +11,9 @@ #define MIN(a, b) ((b) < (a) ? (b) : (a)) +extern const int QR_DATA_WORD_COUNT[40][4]; +extern const int QR_RS_BLOCK_COUNT[40][4][2]; + static int mask_data(struct qr_code * code); static int score_mask(const struct qr_bitmap * bmp); static int score_runs(const struct qr_bitmap * bmp, int base); @@ -153,7 +156,8 @@ static struct qr_bitstream * make_data(int version, { const size_t total_bits = code_total_capacity(version); const size_t total_words = total_bits / 8; - size_t block_count, data_words, rs_words; + const size_t total_data = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]; + size_t total_blocks, block_count[2], data_words, rs_words; size_t i; struct qr_bitstream * dcopy = 0; struct qr_bitstream * out = 0; @@ -167,38 +171,38 @@ static struct qr_bitstream * make_data(int version, if (qr_bitstream_resize(out, total_bits) != 0) goto fail; - /** - * XXX: For our test case (1-M) there is only one RS block. - * This is not the case for most other formats, so we'll - * have to deal with this eventually. - */ - block_count = 1; - data_words = 16; - rs_words = 10; - assert(data_words + rs_words == total_words); + /* XXX: 14-M will be incorrect */ + block_count[0] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][0]; + block_count[1] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][1]; + total_blocks = block_count[0] + block_count[1]; + data_words = total_data / total_blocks; + rs_words = total_words / total_blocks - data_words; + assert((data_words + rs_words) * block_count[0] + + (data_words + rs_words + 1) * block_count[1] == total_words); /* Make a copy of the data and pad it */ - dcopy = qr_bitstream_copy(data); + dcopy = qr_bitstream_dup(data); if (!dcopy) goto fail; - if (pad_data(dcopy, data_words * 8) != 0) + if (pad_data(dcopy, total_data * 8) != 0) goto fail; fputs("Pad data:\n", stderr); x_dump(dcopy); /* Make space for the RS blocks */ - blocks = calloc(block_count, sizeof(*blocks)); + blocks = calloc(total_blocks, sizeof(*blocks)); if (!blocks) goto fail; /* Generate RS codewords */ qr_bitstream_seek(dcopy, 0); fputs("Generate RS blocks:\n", stderr); - for (i = 0; i < block_count; ++i) { - /* XXX: some blocks may be longer */ - blocks[i] = rs_generate_words(dcopy, data_words, rs_words); + for (i = 0; i < total_blocks; ++i) { + size_t dw = data_words + (i >= block_count[0]); + + blocks[i] = rs_generate_words(dcopy, dw, rs_words); if (!blocks[i]) { while (i--) qr_bitstream_destroy(blocks[i]); @@ -210,17 +214,20 @@ static struct qr_bitstream * make_data(int version, } /* Finally, write everything out in the correct order */ - /* XXX: need to handle multiple blocks */ - qr_bitstream_cat(out, dcopy); - qr_bitstream_cat(out, blocks[0]); + qr_bitstream_seek(dcopy, 0); + for (i = 0; i < total_blocks; ++i) { + size_t dw = data_words + (i >= block_count[0]); + qr_bitstream_copy(out, dcopy, dw * 8); + qr_bitstream_cat(out, blocks[i]); + } qr_bitstream_write(out, 0, total_bits - total_words * 8); fputs("Final bitstream:\n", stderr); x_dump(out); exit: if (blocks) { - while (block_count--) - qr_bitstream_destroy(blocks[block_count]); + while (total_blocks--) + qr_bitstream_destroy(blocks[total_blocks]); free(blocks); } if (dcopy) diff --git a/lpg/libqr/qr-bitstream.c b/lpg/libqr/qr-bitstream.c index b223f4c..c752cde 100644 --- a/lpg/libqr/qr-bitstream.c +++ b/lpg/libqr/qr-bitstream.c @@ -80,7 +80,7 @@ void qr_bitstream_destroy(struct qr_bitstream * stream) free(stream); } -struct qr_bitstream * qr_bitstream_copy(const struct qr_bitstream * src) +struct qr_bitstream * qr_bitstream_dup(const struct qr_bitstream * src) { struct qr_bitstream * ret; @@ -210,6 +210,20 @@ int qr_bitstream_cat(struct qr_bitstream * dest, const struct qr_bitstream * src srcpos = qr_bitstream_tell(src); qr_bitstream_seek((struct qr_bitstream *)src, 0); + qr_bitstream_copy(dest, (struct qr_bitstream *)src, count); + qr_bitstream_seek((struct qr_bitstream *)src, srcpos); + + return 0; +} + +int qr_bitstream_copy(struct qr_bitstream * dest, + struct qr_bitstream * src, + size_t count) +{ + if (qr_bitstream_remaining(src) < count) + return -1; + if (ensure_available(dest, count) != 0) + return -1; /* uint must be at least 16 bits */ for (; count >= 16; count -= 16) @@ -224,8 +238,6 @@ int qr_bitstream_cat(struct qr_bitstream * dest, const struct qr_bitstream * src qr_bitstream_read((struct qr_bitstream *)src, count), count); - qr_bitstream_seek((struct qr_bitstream *)src, srcpos); - return 0; } diff --git a/lpg/libqr/qr-bitstream.h b/lpg/libqr/qr-bitstream.h index 298e53b..cf20694 100644 --- a/lpg/libqr/qr-bitstream.h +++ b/lpg/libqr/qr-bitstream.h @@ -15,7 +15,7 @@ struct qr_bitstream; struct qr_bitstream * qr_bitstream_create(void); int qr_bitstream_resize(struct qr_bitstream *, size_t bits); void qr_bitstream_destroy(struct qr_bitstream *); -struct qr_bitstream * qr_bitstream_copy(const struct qr_bitstream *); +struct qr_bitstream * qr_bitstream_dup(const struct qr_bitstream *); void qr_bitstream_seek(struct qr_bitstream *, size_t pos); size_t qr_bitstream_tell(const struct qr_bitstream *); @@ -40,5 +40,9 @@ int qr_bitstream_pack(struct qr_bitstream *, int qr_bitstream_cat(struct qr_bitstream *, const struct qr_bitstream * src); +int qr_bitstream_copy(struct qr_bitstream * dest, + struct qr_bitstream * src, + size_t count); + #endif -- cgit v1.2.3-70-g09d2 From 688c1b52ed356d024ba2e72ba52f7da64b7d74ed Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Tue, 3 Nov 2009 00:12:30 +0900 Subject: generate alignment pattern --- lpg/libqr/TODO | 2 -- lpg/libqr/code-common.c | 43 +++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/code-common.h | 2 ++ lpg/libqr/code-create.c | 23 ++++++++++++++++++++++- lpg/libqr/code-layout.c | 27 +++++++++++++++++++++++++-- 5 files changed, 92 insertions(+), 5 deletions(-) diff --git a/lpg/libqr/TODO b/lpg/libqr/TODO index 6efa259..eb35da8 100644 --- a/lpg/libqr/TODO +++ b/lpg/libqr/TODO @@ -1,5 +1,3 @@ -* Get sample generated OK -* Fix generation for all sizes (alignment pattern) * Auto-sizing for data * Sample app * Merge some files diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index 150dfc5..7c3c119 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -38,3 +38,46 @@ size_t code_total_capacity(int version) return side * side - function_bits; } +const int QR_ALIGNMENT_LOCATION[40][7] = { + { 0, 0, 0, 0, 0, 0, 0 }, /* 1 */ + { 6, 18, 0, 0, 0, 0, 0 }, /* 2 */ + { 6, 22, 0, 0, 0, 0, 0 }, /* 3 */ + { 6, 26, 0, 0, 0, 0, 0 }, /* 4 */ + { 6, 30, 0, 0, 0, 0, 0 }, /* 5 */ + { 6, 34, 0, 0, 0, 0, 0 }, /* 6 */ + { 6, 22, 38, 0, 0, 0, 0 }, /* 7 */ + { 6, 24, 42, 0, 0, 0, 0 }, /* 8 */ + { 6, 26, 46, 0, 0, 0, 0 }, /* 9 */ + { 6, 28, 50, 0, 0, 0, 0 }, /* 10 */ + { 6, 30, 54, 0, 0, 0, 0 }, /* 11 */ + { 6, 32, 58, 0, 0, 0, 0 }, /* 12 */ + { 6, 34, 62, 0, 0, 0, 0 }, /* 13 */ + { 6, 26, 46, 66, 0, 0, 0 }, /* 14 */ + { 6, 26, 48, 70, 0, 0, 0 }, /* 15 */ + { 6, 26, 50, 74, 0, 0, 0 }, /* 16 */ + { 6, 30, 54, 78, 0, 0, 0 }, /* 17 */ + { 6, 30, 56, 82, 0, 0, 0 }, /* 18 */ + { 6, 30, 58, 86, 0, 0, 0 }, /* 19 */ + { 6, 34, 62, 90, 0, 0, 0 }, /* 20 */ + { 6, 28, 50, 72, 94, 0, 0 }, /* 21 */ + { 6, 26, 50, 74, 98, 0, 0 }, /* 22 */ + { 6, 30, 54, 78,102, 0, 0 }, /* 23 */ + { 6, 28, 54, 80,106, 0, 0 }, /* 24 */ + { 6, 32, 58, 84,110, 0, 0 }, /* 25 */ + { 6, 30, 58, 86,114, 0, 0 }, /* 26 */ + { 6, 34, 62, 90,118, 0, 0 }, /* 27 */ + { 6, 26, 50, 74, 98,122, 0 }, /* 28 */ + { 6, 30, 54, 78,102,126, 0 }, /* 29 */ + { 6, 26, 52, 78,104,130, 0 }, /* 30 */ + { 6, 30, 56, 82,108,134, 0 }, /* 31 */ + { 6, 34, 60, 86,112,138, 0 }, /* 32 */ + { 6, 30, 58, 86,114,142, 0 }, /* 33 */ + { 6, 34, 62, 90,118,146, 0 }, /* 34 */ + { 6, 30, 54, 78,102,126,150 }, /* 35 */ + { 6, 24, 50, 76,102,128,154 }, /* 36 */ + { 6, 28, 54, 80,106,132,158 }, /* 37 */ + { 6, 32, 58, 84,110,136,162 }, /* 38 */ + { 6, 26, 54, 82,110,138,166 }, /* 39 */ + { 6, 30, 58, 86,114,142,170 }, /* 40 */ +}; + diff --git a/lpg/libqr/code-common.h b/lpg/libqr/code-common.h index 0459708..9900e4e 100644 --- a/lpg/libqr/code-common.h +++ b/lpg/libqr/code-common.h @@ -12,5 +12,7 @@ struct qr_code { size_t code_total_capacity(int version); +extern const int QR_ALIGNMENT_LOCATION[40][7]; + #endif diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 36ebb24..ae23acc 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -79,6 +79,8 @@ static int draw_functional(struct qr_code * code, struct qr_bitmap * bmp; int dim = qr_code_width(code); int i; + int x, y; + int am_side; bmp = qr_bitmap_create(dim, dim, 0); if (!bmp) @@ -95,7 +97,26 @@ static int draw_functional(struct qr_code * code, setpx(bmp, 6, i); } - /* XXX: alignment pattern */ + /* Alignment pattern */ + am_side = code->version > 1 ? (code->version / 7) + 2 : 0; + for (y = 0; y < am_side; ++y) { + const int * am_pos = QR_ALIGNMENT_LOCATION[code->version - 1]; + + for (x = 0; x < am_side; ++x) { + if ((x == 0 && y == 0) || + (x == 0 && y == am_side - 1) || + (x == am_side - 1 && y == 0)) + continue; + + for (i = -2; i < 2; ++i) { + setpx(bmp, am_pos[x] + i, am_pos[y] - 2); + setpx(bmp, am_pos[x] + 2, am_pos[y] + i); + setpx(bmp, am_pos[x] - i, am_pos[y] + 2); + setpx(bmp, am_pos[x] - 2, am_pos[y] - i); + } + setpx(bmp, am_pos[x], am_pos[y]); + } + } /* Format info */ setpx(bmp, 8, dim - 8); diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 54947d1..2a90124 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -21,6 +21,8 @@ void qr_layout_init_mask(struct qr_code * code) int x, y; int dim = qr_code_width(code); struct qr_bitmap * bmp = code->modules; + const int * am_pos = QR_ALIGNMENT_LOCATION[code->version - 1]; + int am_side; assert(bmp->mask); @@ -53,11 +55,32 @@ void qr_layout_init_mask(struct qr_code * code) continue; } - /* XXX: alignment pattern */ - row[off] |= bit; } } + + /* Alignment pattern */ + am_side = code->version > 1 ? (code->version / 7) + 2 : 0; + for (y = 0; y < am_side; ++y) { + for (x = 0; x < am_side; ++x) { + int i, j; + + if ((x == 0 && y == 0) || + (x == 0 && y == am_side - 1) || + (x == am_side - 1 && y == 0)) + continue; + + for (j = -2; j <= 2; ++j) { + unsigned char * row = bmp->mask + (am_pos[y]+j) * bmp->stride; + for (i = -2; i <= 2; ++i) { + unsigned char bit = 1 << ((am_pos[x]+i) % CHAR_BIT); + int off = (am_pos[x]+i) / CHAR_BIT; + + row[off] &= ~bit; + } + } + } + } } static int is_data_bit(const struct qr_iterator * i) -- cgit v1.2.3-70-g09d2 From cca340e1b1017f1f565c5c53920e450d75164d51 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Tue, 3 Nov 2009 15:29:45 +0900 Subject: Fix the output block order --- lpg/libqr/code-create.c | 24 ++++++++++++++++++------ lpg/libqr/rs-encode.c | 1 - 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index ae23acc..1a38967 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -179,7 +179,7 @@ static struct qr_bitstream * make_data(int version, const size_t total_words = total_bits / 8; const size_t total_data = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]; size_t total_blocks, block_count[2], data_words, rs_words; - size_t i; + size_t i, w; struct qr_bitstream * dcopy = 0; struct qr_bitstream * out = 0; struct qr_bitstream ** blocks = 0; @@ -235,12 +235,24 @@ static struct qr_bitstream * make_data(int version, } /* Finally, write everything out in the correct order */ - qr_bitstream_seek(dcopy, 0); - for (i = 0; i < total_blocks; ++i) { - size_t dw = data_words + (i >= block_count[0]); - qr_bitstream_copy(out, dcopy, dw * 8); - qr_bitstream_cat(out, blocks[i]); + for (w = 0; w < data_words + 1; ++w) { + for (i = (w == data_words ? block_count[0] : 0); i < total_blocks; ++i) { + size_t di = w + (i < block_count[0] ? + i * data_words : + i * (data_words + 1) - block_count[0]); + + qr_bitstream_seek(dcopy, di * 8); + qr_bitstream_write(out, + qr_bitstream_read(dcopy, 8), 8); + } } + for (i = 0; i < total_blocks; ++i) + qr_bitstream_seek(blocks[i], 0); + for (w = 0; w < rs_words; ++w) + for (i = 0; i < total_blocks; ++i) + qr_bitstream_write(out, + qr_bitstream_read(blocks[i], 8), 8); + qr_bitstream_write(out, 0, total_bits - total_words * 8); fputs("Final bitstream:\n", stderr); diff --git a/lpg/libqr/rs-encode.c b/lpg/libqr/rs-encode.c index 42b404f..a8ecc73 100644 --- a/lpg/libqr/rs-encode.c +++ b/lpg/libqr/rs-encode.c @@ -74,7 +74,6 @@ struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, goto fail; /* First, prepare the registers (b) with data bits */ - qr_bitstream_seek(data, 0); for (i = 0; i < data_words; ++i) { unsigned int x = b[n-1] ^ qr_bitstream_read(data, 8); for (r = n-1; r > 0; --r) -- cgit v1.2.3-70-g09d2 From 7ccc90b391c269ce3453275ff8725849ea52ccbe Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Tue, 3 Nov 2009 15:56:27 +0900 Subject: demo app: select ec type, help message --- lpg/libqr/qrgen.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index 8b9f1f0..aee6166 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -1,3 +1,4 @@ +#include #include #include #include @@ -120,7 +121,14 @@ void output_ansi(const struct qr_bitmap * bmp) } void show_help() { - fprintf(stderr, "(help message)\n"); + fprintf(stderr, + "Usage:\n\t%s [options] \n\n" + "\t-h Display this help message\n" + "\t-v Specify QR version (size) 1 <= n <= 40\n" + "\t-e Specify EC type: L, M, Q, H\n" + "\t-a Output as ANSI graphics (default)\n" + "\t-p Output as PBM\n\n", + "qrgen"); } void set_default_config(struct config * conf) @@ -129,7 +137,7 @@ void set_default_config(struct config * conf) conf->ec = QR_EC_LEVEL_M; conf->dtype = QR_DATA_NUMERIC; conf->ansi = 1; - conf->input = "01234567"; + conf->input = NULL; } void parse_options(int argc, char ** argv, struct config * conf) @@ -156,7 +164,16 @@ void parse_options(int argc, char ** argv, struct config * conf) } break; case 'e': /* ec */ - fprintf(stderr, "XXX: ignored \"ec\"\n"); + switch (tolower(optarg[0])) { + case 'l': conf->ec = QR_EC_LEVEL_L; break; + case 'm': conf->ec = QR_EC_LEVEL_M; break; + case 'q': conf->ec = QR_EC_LEVEL_Q; break; + case 'h': conf->ec = QR_EC_LEVEL_H; break; + default: + fprintf(stderr, + "Invalid EC type (%c). Choose from" + " L, M, Q or H.\n", optarg[0]); + } break; case 't': /* type */ fprintf(stderr, "XXX: ignored \"type\"\n"); -- cgit v1.2.3-70-g09d2 From 682c2c553b7083645dd5147cdf3ff8650f08a0fd Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 14 Nov 2009 18:13:58 +0900 Subject: Store ec level in qr_data struct --- lpg/libqr/code-create.c | 7 +++---- lpg/libqr/data-common.h | 1 + lpg/libqr/data-create.c | 3 ++- lpg/libqr/qr/code.h | 10 +--------- lpg/libqr/qr/data.h | 8 ++++++++ lpg/libqr/qrgen.c | 4 ++-- 6 files changed, 17 insertions(+), 16 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 1a38967..f8ef7b9 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -274,8 +274,7 @@ fail: goto exit; } -struct qr_code * qr_code_create(enum qr_ec_level ec, - const struct qr_data * data) +struct qr_code * qr_code_create(const struct qr_data * data) { struct qr_code * code; struct qr_bitstream * bits = 0; @@ -294,7 +293,7 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, if (!code->modules) goto fail; - bits = make_data(data->version, ec, data->bits); + bits = make_data(data->version, data->ec, data->bits); if (!bits) goto fail; @@ -313,7 +312,7 @@ struct qr_code * qr_code_create(enum qr_ec_level ec, if (mask < 0) goto fail; - if (draw_functional(code, ec, mask) != 0) + if (draw_functional(code, data->ec, mask) != 0) goto fail; exit: diff --git a/lpg/libqr/data-common.h b/lpg/libqr/data-common.h index bc2b381..420b3b2 100644 --- a/lpg/libqr/data-common.h +++ b/lpg/libqr/data-common.h @@ -7,6 +7,7 @@ struct qr_data { int version; /* 1 ~ 40 */ + enum qr_ec_level ec; struct qr_bitstream * bits; size_t offset; }; diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c index 2c2737f..27c6d4b 100644 --- a/lpg/libqr/data-create.c +++ b/lpg/libqr/data-create.c @@ -3,7 +3,6 @@ */ /** XXX: check that the data will fit! **/ -/** NOTE: should store ec type in qr_data **/ #include #include @@ -174,6 +173,7 @@ static struct qr_data * encode_kanji(struct qr_data * data, } struct qr_data * qr_create_data(int version, + enum qr_ec_level ec, enum qr_data_type type, const char * input, size_t length) @@ -188,6 +188,7 @@ struct qr_data * qr_create_data(int version, return 0; data->version = version; + data->ec = ec; data->bits = qr_bitstream_create(); data->offset = 0; diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h index dba0040..3c14c1f 100644 --- a/lpg/libqr/qr/code.h +++ b/lpg/libqr/qr/code.h @@ -4,15 +4,7 @@ #include #include "types.h" -enum qr_ec_level { - QR_EC_LEVEL_L = 0x1, - QR_EC_LEVEL_M = 0x0, - QR_EC_LEVEL_Q = 0x3, - QR_EC_LEVEL_H = 0x2 -}; - -struct qr_code * qr_code_create(enum qr_ec_level ec, - const struct qr_data * data); +struct qr_code * qr_code_create(const struct qr_data * data); void qr_code_destroy(struct qr_code *); diff --git a/lpg/libqr/qr/data.h b/lpg/libqr/qr/data.h index 5fbdded..39494f4 100644 --- a/lpg/libqr/qr/data.h +++ b/lpg/libqr/qr/data.h @@ -15,7 +15,15 @@ enum qr_data_type { QR_DATA_FNC1 = 9 }; +enum qr_ec_level { + QR_EC_LEVEL_L = 0x1, + QR_EC_LEVEL_M = 0x0, + QR_EC_LEVEL_Q = 0x3, + QR_EC_LEVEL_H = 0x2 +}; + struct qr_data * qr_create_data(int format, /* 1 ~ 40 */ + enum qr_ec_level ec, enum qr_data_type type, const char * input, size_t length); diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index aee6166..d1aae68 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -31,7 +31,7 @@ struct qr_code * create(int version, len = strlen(input); - data = qr_create_data(version, dtype, input, len); + data = qr_create_data(version, ec, dtype, input, len); if (!data) { /* BUG: this could also indicate OOM or @@ -41,7 +41,7 @@ struct qr_code * create(int version, exit(1); } - code = qr_code_create(ec, data); + code = qr_code_create(data); if (!code) { perror("Failed to create code"); -- cgit v1.2.3-70-g09d2 From c157f944cd6db591f5da47475200e5e16b0c2cac Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 14 Nov 2009 18:43:26 +0900 Subject: Auto-size --- lpg/libqr/TODO | 1 - lpg/libqr/data-common.h | 2 ++ lpg/libqr/data-create.c | 69 ++++++++++++++++++++++++++++++++++++++++++------- lpg/libqr/qr/data.h | 2 +- lpg/libqr/qrgen.c | 2 +- 5 files changed, 63 insertions(+), 13 deletions(-) diff --git a/lpg/libqr/TODO b/lpg/libqr/TODO index eb35da8..0511b22 100644 --- a/lpg/libqr/TODO +++ b/lpg/libqr/TODO @@ -1,4 +1,3 @@ -* Auto-sizing for data * Sample app * Merge some files * Fix XXX, TODO diff --git a/lpg/libqr/data-common.h b/lpg/libqr/data-common.h index 420b3b2..054d349 100644 --- a/lpg/libqr/data-common.h +++ b/lpg/libqr/data-common.h @@ -16,5 +16,7 @@ extern const enum qr_data_type QR_TYPE_CODES[16]; size_t get_size_field_length(int version, enum qr_data_type); +size_t qr_data_dpart_length(enum qr_data_type type, size_t nchars); + #endif diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c index 27c6d4b..37556c6 100644 --- a/lpg/libqr/data-create.c +++ b/lpg/libqr/data-create.c @@ -11,6 +11,8 @@ #include "qr-bitstream.h" #include "data-common.h" +extern const int QR_DATA_WORD_COUNT[40][4]; + static void write_type_and_length(struct qr_data * data, enum qr_data_type type, size_t length) @@ -28,12 +30,7 @@ static struct qr_data * encode_numeric(struct qr_data * data, size_t bits; bits = 4 + get_size_field_length(data->version, QR_DATA_NUMERIC) - + 10 * (length / 3); - - if (length % 3 == 1) - bits += 4; - else if (length % 3 == 2) - bits += 7; + + qr_data_dpart_length(QR_DATA_NUMERIC, length); stream = data->bits; if (qr_bitstream_resize(stream, @@ -106,8 +103,7 @@ static struct qr_data * encode_alpha(struct qr_data * data, size_t bits; bits = 4 + get_size_field_length(data->version, QR_DATA_ALPHA) - + 11 * (length / 2) - + 6 * (length % 2); + + qr_data_dpart_length(QR_DATA_ALPHA, length); stream = data->bits; if (qr_bitstream_resize(stream, @@ -150,7 +146,7 @@ static struct qr_data * encode_8bit(struct qr_data * data, size_t bits; bits = 4 + get_size_field_length(data->version, QR_DATA_8BIT) - + 8 * length; + + qr_data_dpart_length(QR_DATA_8BIT, length); stream = data->bits; if (qr_bitstream_resize(stream, @@ -172,6 +168,24 @@ static struct qr_data * encode_kanji(struct qr_data * data, return 0; } +static int calc_min_version(enum qr_data_type type, + enum qr_ec_level ec, + size_t length) +{ + size_t dbits; + int version; + + dbits = qr_data_dpart_length(type, length); + + for (version = 1; version <= 40; ++version) { + if (4 + dbits + get_size_field_length(version, type) + < 8 * QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]) + return version; + } + + return -1; +} + struct qr_data * qr_create_data(int version, enum qr_ec_level ec, enum qr_data_type type, @@ -179,8 +193,14 @@ struct qr_data * qr_create_data(int version, size_t length) { struct qr_data * data; + int minver; - if (version < 1 || version > 40) + minver = calc_min_version(type, ec, length); + + if (version == 0) + version = minver; + + if (minver < 0 || version < minver) return 0; data = malloc(sizeof(*data)); @@ -222,3 +242,32 @@ struct qr_data * qr_create_data(int version, } } +size_t qr_data_dpart_length(enum qr_data_type type, size_t length) +{ + size_t bits; + + switch (type) { + case QR_DATA_NUMERIC: + bits = 10 * (length / 3); + if (length % 3 == 1) + bits += 4; + else if (length % 3 == 2) + bits += 7; + break; + case QR_DATA_ALPHA: + bits = 11 * (length / 2) + + 6 * (length % 2); + break; + case QR_DATA_8BIT: + bits = 8 * length; + break; + case QR_DATA_KANJI: + /* unsupported */ + default: + /* unsupported; will be ignored */ + bits = 0; + } + + return bits; +} + diff --git a/lpg/libqr/qr/data.h b/lpg/libqr/qr/data.h index 39494f4..34b6968 100644 --- a/lpg/libqr/qr/data.h +++ b/lpg/libqr/qr/data.h @@ -22,7 +22,7 @@ enum qr_ec_level { QR_EC_LEVEL_H = 0x2 }; -struct qr_data * qr_create_data(int format, /* 1 ~ 40 */ +struct qr_data * qr_create_data(int format, /* 1 ~ 40; 0=auto */ enum qr_ec_level ec, enum qr_data_type type, const char * input, diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index d1aae68..cb6d33c 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -133,7 +133,7 @@ void show_help() { void set_default_config(struct config * conf) { - conf->version = 1; + conf->version = 0; conf->ec = QR_EC_LEVEL_M; conf->dtype = QR_DATA_NUMERIC; conf->ansi = 1; -- cgit v1.2.3-70-g09d2 From 2a5548351d9814a8a23eff1e43e14008ea4ae1d0 Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 14 Nov 2009 18:46:29 +0900 Subject: Default to 8-bit data --- lpg/libqr/TODO | 1 - lpg/libqr/qrgen.c | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/lpg/libqr/TODO b/lpg/libqr/TODO index 0511b22..219ca83 100644 --- a/lpg/libqr/TODO +++ b/lpg/libqr/TODO @@ -1,4 +1,3 @@ -* Sample app * Merge some files * Fix XXX, TODO * Tidy code diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index cb6d33c..1309596 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -135,7 +135,7 @@ void set_default_config(struct config * conf) { conf->version = 0; conf->ec = QR_EC_LEVEL_M; - conf->dtype = QR_DATA_NUMERIC; + conf->dtype = QR_DATA_8BIT; conf->ansi = 1; conf->input = NULL; } -- cgit v1.2.3-70-g09d2 From c2e4639d2ebefbeb7f8b7e1826ae2391c6876a5a Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 14 Nov 2009 20:24:57 +0900 Subject: Merge some files --- lpg/libqr/Makefile | 10 +- lpg/libqr/TODO | 1 - lpg/libqr/bitmap.c | 202 +++++++++++++++++++++++++++++++++++ lpg/libqr/bitstream.c | 243 +++++++++++++++++++++++++++++++++++++++++++ lpg/libqr/capacity.c | 88 ---------------- lpg/libqr/code-common.c | 89 ++++++++-------- lpg/libqr/code-common.h | 18 ---- lpg/libqr/code-create.c | 56 ++-------- lpg/libqr/code-layout.c | 6 +- lpg/libqr/code-layout.h | 14 --- lpg/libqr/code-parse.c | 2 - lpg/libqr/constants.c | 151 +++++++++++++++++++++++++++ lpg/libqr/constants.h | 12 +++ lpg/libqr/data-common.c | 26 +---- lpg/libqr/data-common.h | 22 ---- lpg/libqr/data-create.c | 20 ++-- lpg/libqr/data-parse.c | 16 +-- lpg/libqr/galois.c | 126 ++++++++++++++++++++++ lpg/libqr/galois.h | 12 +++ lpg/libqr/qr-bitmap-render.c | 118 --------------------- lpg/libqr/qr-bitmap.c | 89 ---------------- lpg/libqr/qr-bitstream.c | 243 ------------------------------------------- lpg/libqr/qr-bitstream.h | 48 --------- lpg/libqr/qr-mask.c | 46 -------- lpg/libqr/qr-mask.h | 10 -- lpg/libqr/qr/bitstream.h | 48 +++++++++ lpg/libqr/qr/code.h | 10 ++ lpg/libqr/qr/data.h | 13 ++- lpg/libqr/qr/layout.h | 14 +++ lpg/libqr/qrgen.c | 11 +- lpg/libqr/rs-encode.c | 96 ----------------- lpg/libqr/rs.h | 11 -- 32 files changed, 916 insertions(+), 955 deletions(-) create mode 100644 lpg/libqr/bitmap.c create mode 100644 lpg/libqr/bitstream.c delete mode 100644 lpg/libqr/capacity.c delete mode 100644 lpg/libqr/code-common.h delete mode 100644 lpg/libqr/code-layout.h create mode 100644 lpg/libqr/constants.c create mode 100644 lpg/libqr/constants.h delete mode 100644 lpg/libqr/data-common.h create mode 100644 lpg/libqr/galois.c create mode 100644 lpg/libqr/galois.h delete mode 100644 lpg/libqr/qr-bitmap-render.c delete mode 100644 lpg/libqr/qr-bitmap.c delete mode 100644 lpg/libqr/qr-bitstream.c delete mode 100644 lpg/libqr/qr-bitstream.h delete mode 100644 lpg/libqr/qr-mask.c delete mode 100644 lpg/libqr/qr-mask.h create mode 100644 lpg/libqr/qr/bitstream.h create mode 100644 lpg/libqr/qr/layout.h delete mode 100644 lpg/libqr/rs-encode.c delete mode 100644 lpg/libqr/rs.h diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index 3a6af6f..a82372f 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -1,4 +1,6 @@ -OBJECTS := capacity.o \ +OBJECTS := bitmap.o \ + bitstream.o \ + constants.o \ code-common.o \ code-create.o \ code-layout.o \ @@ -6,11 +8,7 @@ OBJECTS := capacity.o \ data-common.o \ data-create.o \ data-parse.o \ - qr-bitmap.o \ - qr-bitmap-render.o \ - qr-bitstream.o \ - qr-mask.o \ - rs-encode.o + galois.o CFLAGS := -std=c89 -pedantic -I. -Wall CFLAGS += -g diff --git a/lpg/libqr/TODO b/lpg/libqr/TODO index 219ca83..3cd0583 100644 --- a/lpg/libqr/TODO +++ b/lpg/libqr/TODO @@ -1,4 +1,3 @@ -* Merge some files * Fix XXX, TODO * Tidy code * RELEASE v0.1 diff --git a/lpg/libqr/bitmap.c b/lpg/libqr/bitmap.c new file mode 100644 index 0000000..3394784 --- /dev/null +++ b/lpg/libqr/bitmap.c @@ -0,0 +1,202 @@ +#include +#include +#include +#include + +#include + +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->mask, 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); + } +} + +struct qr_bitmap * qr_bitmap_clone(const struct qr_bitmap * src) +{ + struct qr_bitmap * bmp; + size_t size; + + bmp = qr_bitmap_create(src->width, src->height, !!src->mask); + if (!bmp) + return 0; + + assert(bmp->stride == src->stride); + + size = bmp->width * bmp->stride; + memcpy(bmp->bits, src->bits, size); + if (bmp->mask) + memcpy(bmp->mask, src->mask, size); + + return 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++; + } +} + +/* 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/bitstream.c b/lpg/libqr/bitstream.c new file mode 100644 index 0000000..cf5a9d4 --- /dev/null +++ b/lpg/libqr/bitstream.c @@ -0,0 +1,243 @@ +/** + * It would perhaps be more sensible just to store the bits + * as an array of char or similar, but this way is more fun. + * This is a pretty inefficient implementation, althought I + * suspect that won't be a problem. + */ + +#include +#include +#include +#include + +#include + +#define MAX(a, b) ((a) < (b) ? (b) : (a)) +#define MIN(a, b) ((a) > (b) ? (b) : (a)) + +struct qr_bitstream { + size_t pos; /* bits */ + size_t count; /* bits */ + size_t bufsiz; /* bytes */ + unsigned char * buffer; +}; + +static size_t bits_to_bytes(size_t bits) +{ + return (bits / CHAR_BIT) + (bits % CHAR_BIT != 0); +} + +static int ensure_available(struct qr_bitstream * stream, size_t bits) +{ + size_t need_bits = stream->pos + bits; + size_t newsize; + + if (stream->bufsiz * CHAR_BIT >= need_bits) + return 0; + + newsize = MAX(stream->bufsiz, 100) * CHAR_BIT; + while (newsize < need_bits) + newsize *= 2; + + return qr_bitstream_resize(stream, newsize); +} + +struct qr_bitstream * qr_bitstream_create(void) +{ + struct qr_bitstream * obj; + + obj = malloc(sizeof(*obj)); + + if (obj) { + obj->pos = 0; + obj->count = 0; + obj->bufsiz = 0; + obj->buffer = 0; + } + + return obj; +} + +int qr_bitstream_resize(struct qr_bitstream * stream, size_t bits) +{ + size_t newsize; + void * newbuf; + + newsize = bits_to_bytes(bits); + newbuf = realloc(stream->buffer, newsize); + + if (newbuf) { + stream->bufsiz = newsize; + stream->buffer = newbuf; + } + + return newbuf ? 0 : -1; +} + +void qr_bitstream_destroy(struct qr_bitstream * stream) +{ + free(stream->buffer); + free(stream); +} + +struct qr_bitstream * qr_bitstream_dup(const struct qr_bitstream * src) +{ + struct qr_bitstream * ret; + + ret = qr_bitstream_create(); + if (!ret) + return 0; + + if (qr_bitstream_resize(ret, src->count) != 0) { + free(ret); + return 0; + } + + ret->pos = src->pos; + ret->count = src->count; + memcpy(ret->buffer, src->buffer, src->bufsiz); + + return ret; +} + +void qr_bitstream_seek(struct qr_bitstream * stream, size_t pos) +{ + assert(pos <= stream->count); + stream->pos = pos; +} + +size_t qr_bitstream_tell(const struct qr_bitstream * stream) +{ + return stream->pos; +} + +size_t qr_bitstream_remaining(const struct qr_bitstream * stream) +{ + return stream->count - stream->pos; +} + +size_t qr_bitstream_size(const struct qr_bitstream * stream) +{ + return stream->count; +} + +unsigned int qr_bitstream_read(struct qr_bitstream * stream, size_t bits) +{ + unsigned int result = 0; + unsigned char * byte; + size_t bitnum; + + assert(qr_bitstream_remaining(stream) >= bits); + + byte = stream->buffer + (stream->pos / CHAR_BIT); + bitnum = stream->pos % CHAR_BIT; + + stream->pos += bits; + + while (bits-- > 0) { + int bit = (*byte >> bitnum++) & 0x1; + result = (result << 1) | bit; + if (bitnum == CHAR_BIT) { + bitnum = 0; + ++byte; + } + } + + return result; +} + +void qr_bitstream_unpack(struct qr_bitstream * stream, + unsigned int * result, + size_t count, + size_t bitsize) +{ + assert(qr_bitstream_remaining(stream) >= (count * bitsize)); + + while (count--) + *(result++) = qr_bitstream_read(stream, bitsize); +} + +int qr_bitstream_write(struct qr_bitstream * stream, + unsigned int value, + size_t bits) +{ + unsigned char * byte; + size_t bitnum; + + if (ensure_available(stream, bits) != 0) + return -1; + + byte = stream->buffer + (stream->pos / CHAR_BIT); + bitnum = stream->pos % CHAR_BIT; + + stream->pos += bits; + stream->count = stream->pos; /* truncate */ + + while (bits-- > 0) { + int bit = (value >> bits) & 0x1; + unsigned char mask = 1 << bitnum++; + *byte = (*byte & ~mask) | (bit ? mask : 0); + if (bitnum == CHAR_BIT) { + bitnum = 0; + ++byte; + } + } + + return 0; +} + +int qr_bitstream_pack(struct qr_bitstream * stream, + const unsigned int * values, + size_t count, + size_t bitsize) +{ + if (ensure_available(stream, count * bitsize) != 0) + return -1; + + while (count--) + qr_bitstream_write(stream, *(values++), bitsize); + + return 0; +} + +int qr_bitstream_cat(struct qr_bitstream * dest, const struct qr_bitstream * src) +{ + size_t count = qr_bitstream_size(src); + size_t srcpos; + + if (ensure_available(dest, count) != 0) + return -1; + + srcpos = qr_bitstream_tell(src); + qr_bitstream_seek((struct qr_bitstream *)src, 0); + qr_bitstream_copy(dest, (struct qr_bitstream *)src, count); + qr_bitstream_seek((struct qr_bitstream *)src, srcpos); + + return 0; +} + +int qr_bitstream_copy(struct qr_bitstream * dest, + struct qr_bitstream * src, + size_t count) +{ + if (qr_bitstream_remaining(src) < count) + return -1; + if (ensure_available(dest, count) != 0) + return -1; + + /* uint must be at least 16 bits */ + for (; count >= 16; count -= 16) + qr_bitstream_write( + dest, + qr_bitstream_read((struct qr_bitstream *)src, 16), + 16); + + if (count > 0) + qr_bitstream_write( + dest, + qr_bitstream_read((struct qr_bitstream *)src, count), + count); + + return 0; +} + diff --git a/lpg/libqr/capacity.c b/lpg/libqr/capacity.c deleted file mode 100644 index 4b513af..0000000 --- a/lpg/libqr/capacity.c +++ /dev/null @@ -1,88 +0,0 @@ -/* FIXME: don't like big tables of data */ - -const int QR_DATA_WORD_COUNT[40][4] = { - 19, 16, 13, 9, - 34, 28, 22, 16, - 55, 44, 34, 26, - 80, 64, 48, 36, - 108, 86, 62, 46, - 136, 108, 76, 60, - 156, 124, 88, 66, - 194, 154, 110, 86, - 232, 182, 132, 100, - 274, 216, 154, 122, - 324, 254, 180, 140, - 370, 290, 206, 158, - 428, 334, 244, 180, - 461, 365, 261, 197, - 523, 415, 295, 223, - 589, 453, 325, 253, - 647, 507, 367, 283, - 721, 563, 397, 313, - 795, 627, 445, 341, - 861, 669, 485, 385, - 932, 714, 512, 406, - 1006, 782, 568, 442, - 1094, 860, 614, 464, - 1174, 914, 664, 514, - 1276, 1000, 718, 538, - 1370, 1062, 754, 596, - 1468, 1128, 808, 628, - 1531, 1193, 871, 661, - 1631, 1267, 911, 701, - 1735, 1373, 985, 745, - 1845, 1455, 1033, 793, - 1955, 1541, 1115, 845, - 2071, 1631, 1171, 901, - 2191, 1725, 1231, 961, - 2306, 1812, 1286, 986, - 2434, 1914, 1351, 1054, - 2566, 1992, 1426, 1096, - 2812, 2216, 1582, 1222, - 2956, 2334, 1666, 1276 -}; - -/* I'm sure we can calculate these values */ -const int QR_RS_BLOCK_COUNT[40][4][2] = { - 1, 0, 1, 0, 1, 0, 1, 0, /* 1 */ - 1, 0, 1, 0, 1, 0, 1, 0, /* 2 */ - 1, 0, 1, 0, 2, 0, 2, 0, /* 3 */ - 1, 0, 2, 0, 2, 0, 4, 0, /* 4 */ - 1, 0, 2, 0, 2, 0, 2, 0, - 2, 0, 4, 0, 4, 0, 4, 0, - 2, 0, 4, 0, 2, 4, 4, 1, - 2, 0, 2, 2, 4, 2, 4, 2, /* 8 */ - 2, 0, 3, 2, 4, 4, 4, 4, - 2, 2, 4, 1, 6, 2, 6, 2, - 4, 0, 1, 4, 4, 4, 3, 8, - 2, 2, 6, 2, 4, 6, 7, 4, - 4, 0, 8, 1, 8, 4, 12, 4, - 3, 1, 4, 5, 11, 5, 11, 5, /* 14 */ - 5, 1, 5, 5, 5, 7, 11, 7, - 5, 1, 7, 3, 15, 2, 3, 13, - 1, 5, 10, 1, 1, 15, 2, 17, - 5, 1, 9, 4, 17, 1, 2, 19, - 3, 4, 3, 11, 17, 4, 9, 16, /* 19 */ - 3, 5, 3, 13, 15, 5, 15, 10, - 4, 4, 17, 0, 17, 6, 19, 6, - 2, 7, 17, 0, 7, 16, 34, 0, - 4, 5, 4, 14, 11, 14, 16, 14, - 6, 4, 6, 14, 11, 16, 30, 2, - 8, 4, 8, 13, 7, 22, 22, 13, /* 25 */ - 10, 2, 19, 4, 28, 6, 33, 4, - 8, 4, 22, 3, 8, 26, 12, 28, - 3, 10, 3, 23, 4, 31, 11, 31, - 7, 7, 21, 7, 1, 37, 19, 26, - 5, 10, 19, 10, 15, 25, 23, 25, /* 30 */ - 13, 3, 2, 29, 42, 1, 23, 28, - 17, 0, 10, 23, 10, 35, 19, 35, - 17, 1, 14, 21, 29, 19, 11, 46, - 13, 6, 14, 23, 44, 7, 59, 1, - 12, 7, 12, 26, 39, 14, 22, 41, /* 35 */ - 6, 14, 6, 34, 46, 10, 2, 64, - 17, 4, 29, 14, 49, 10, 24, 46, - 4, 18, 13, 32, 48, 14, 42, 32, - 20, 4, 40, 7, 43, 22, 10, 67, - 19, 6, 18, 31, 34, 34, 20, 61 /* 40 */ -}; - diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index 7c3c119..bc6621a 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -1,7 +1,10 @@ +#include +#include #include + #include #include -#include "code-common.h" +#include void qr_code_destroy(struct qr_code * code) { @@ -16,7 +19,7 @@ int qr_code_width(const struct qr_code * code) return code->version * 4 + 17; } -size_t code_total_capacity(int version) +size_t qr_code_total_capacity(int version) { int side = version * 4 + 17; @@ -38,46 +41,44 @@ size_t code_total_capacity(int version) return side * side - function_bits; } -const int QR_ALIGNMENT_LOCATION[40][7] = { - { 0, 0, 0, 0, 0, 0, 0 }, /* 1 */ - { 6, 18, 0, 0, 0, 0, 0 }, /* 2 */ - { 6, 22, 0, 0, 0, 0, 0 }, /* 3 */ - { 6, 26, 0, 0, 0, 0, 0 }, /* 4 */ - { 6, 30, 0, 0, 0, 0, 0 }, /* 5 */ - { 6, 34, 0, 0, 0, 0, 0 }, /* 6 */ - { 6, 22, 38, 0, 0, 0, 0 }, /* 7 */ - { 6, 24, 42, 0, 0, 0, 0 }, /* 8 */ - { 6, 26, 46, 0, 0, 0, 0 }, /* 9 */ - { 6, 28, 50, 0, 0, 0, 0 }, /* 10 */ - { 6, 30, 54, 0, 0, 0, 0 }, /* 11 */ - { 6, 32, 58, 0, 0, 0, 0 }, /* 12 */ - { 6, 34, 62, 0, 0, 0, 0 }, /* 13 */ - { 6, 26, 46, 66, 0, 0, 0 }, /* 14 */ - { 6, 26, 48, 70, 0, 0, 0 }, /* 15 */ - { 6, 26, 50, 74, 0, 0, 0 }, /* 16 */ - { 6, 30, 54, 78, 0, 0, 0 }, /* 17 */ - { 6, 30, 56, 82, 0, 0, 0 }, /* 18 */ - { 6, 30, 58, 86, 0, 0, 0 }, /* 19 */ - { 6, 34, 62, 90, 0, 0, 0 }, /* 20 */ - { 6, 28, 50, 72, 94, 0, 0 }, /* 21 */ - { 6, 26, 50, 74, 98, 0, 0 }, /* 22 */ - { 6, 30, 54, 78,102, 0, 0 }, /* 23 */ - { 6, 28, 54, 80,106, 0, 0 }, /* 24 */ - { 6, 32, 58, 84,110, 0, 0 }, /* 25 */ - { 6, 30, 58, 86,114, 0, 0 }, /* 26 */ - { 6, 34, 62, 90,118, 0, 0 }, /* 27 */ - { 6, 26, 50, 74, 98,122, 0 }, /* 28 */ - { 6, 30, 54, 78,102,126, 0 }, /* 29 */ - { 6, 26, 52, 78,104,130, 0 }, /* 30 */ - { 6, 30, 56, 82,108,134, 0 }, /* 31 */ - { 6, 34, 60, 86,112,138, 0 }, /* 32 */ - { 6, 30, 58, 86,114,142, 0 }, /* 33 */ - { 6, 34, 62, 90,118,146, 0 }, /* 34 */ - { 6, 30, 54, 78,102,126,150 }, /* 35 */ - { 6, 24, 50, 76,102,128,154 }, /* 36 */ - { 6, 28, 54, 80,106,132,158 }, /* 37 */ - { 6, 32, 58, 84,110,136,162 }, /* 38 */ - { 6, 26, 54, 82,110,138,166 }, /* 39 */ - { 6, 30, 58, 86,114,142,170 }, /* 40 */ -}; +struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, + unsigned int mask) +{ + struct qr_bitmap * bmp; + int i, j; + + if (mask & ~0x7) + return 0; + + bmp = qr_bitmap_clone(orig); + if (!bmp) + return 0; + + /* Slow version for now; we can optimize later */ + + for (i = 0; i < bmp->height; ++i) { + unsigned char * p = bmp->bits + i * bmp->stride; + + for (j = 0; j < bmp->width; ++j) { + int bit = j % CHAR_BIT; + size_t off = j / CHAR_BIT; + int t; + + switch (mask) { + case 0: t = (i + j) % 2; break; + case 1: t = i % 2; break; + case 2: t = j % 3; break; + case 3: t = (i + j) % 3; break; + case 4: t = (i/2 + j/3) % 2; break; + case 5: t = ((i*j) % 2) + ((i*j) % 3); break; + case 6: t = (((i*j) % 2) + ((i*j) % 3)) % 2; break; + case 7: t = (((i*j) % 3) + ((i+j) % 2)) % 2; break; + } + + p[off] ^= (t == 0) << bit; + } + } + + return bmp; +} diff --git a/lpg/libqr/code-common.h b/lpg/libqr/code-common.h deleted file mode 100644 index 9900e4e..0000000 --- a/lpg/libqr/code-common.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef CODE_COMMON_H -#define CODE_COMMON_H - -#include -#include -#include "qr-bitstream.h" - -struct qr_code { - int version; - struct qr_bitmap * modules; -}; - -size_t code_total_capacity(int version); - -extern const int QR_ALIGNMENT_LOCATION[40][7]; - -#endif - diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index f8ef7b9..0882b88 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -1,19 +1,17 @@ #include #include #include -#include -#include "code-common.h" -#include "code-layout.h" -#include "data-common.h" -#include "qr-mask.h" -#include "rs.h" +#include +#include +#include +#include +#include +#include "constants.h" +#include "galois.h" #define MIN(a, b) ((b) < (a) ? (b) : (a)) -extern const int QR_DATA_WORD_COUNT[40][4]; -extern const int QR_RS_BLOCK_COUNT[40][4][2]; - static int mask_data(struct qr_code * code); static int score_mask(const struct qr_bitmap * bmp); static int score_runs(const struct qr_bitmap * bmp, int base); @@ -28,11 +26,6 @@ static int draw_format(struct qr_bitmap * bmp, int mask); static int calc_format_bits(enum qr_ec_level ec, int mask); static long calc_version_bits(int version); -static unsigned long gal_residue(unsigned long a, unsigned long m); - -/* FIXME: the static functions should be in a better - * order, with prototypes. - */ #include static void x_dump(struct qr_bitstream * bits) @@ -175,7 +168,7 @@ static struct qr_bitstream * make_data(int version, enum qr_ec_level ec, struct qr_bitstream * data) { - const size_t total_bits = code_total_capacity(version); + const size_t total_bits = qr_code_total_capacity(version); const size_t total_words = total_bits / 8; const size_t total_data = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]; size_t total_blocks, block_count[2], data_words, rs_words; @@ -575,7 +568,7 @@ static int calc_format_bits(enum qr_ec_level ec, int mask) */ bits <<= 15 - 5; - bits |= (unsigned int)gal_residue(bits, 0x537); + bits |= (unsigned int)gf_residue(bits, 0x537); /* XOR mask: 101 0100 0001 0010 */ bits ^= 0x5412; @@ -593,37 +586,8 @@ static long calc_version_bits(int version) * G(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 */ bits <<= 18 - 6; - bits |= gal_residue(bits, 0x1F25); + bits |= gf_residue(bits, 0x1F25); return bits; } -/* Calculate the residue of a modulo m */ -static unsigned long gal_residue(unsigned long a, - unsigned long m) -{ - unsigned long o = 1; - int n = 1; - - /* Find one past the highest bit of the modulus */ - while (m & ~(o - 1)) - o <<= 1; - - /* Find the highest n such that O(m * x^n) <= O(a) */ - while (a & ~(o - 1)) { - o <<= 1; - ++n; - } - - /* For each n, try to reduce a by (m * x^n) */ - while (n--) { - o >>= 1; - - /* o is the highest bit of (m * x^n) */ - if (a & o) - a ^= m << n; - } - - return a; -} - diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 2a90124..68a1a0e 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -2,9 +2,11 @@ #include #include #include + #include -#include "code-common.h" -#include "code-layout.h" +#include +#include +#include "constants.h" struct qr_iterator { struct qr_code * code; diff --git a/lpg/libqr/code-layout.h b/lpg/libqr/code-layout.h deleted file mode 100644 index 3390548..0000000 --- a/lpg/libqr/code-layout.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifndef CODE_LAYOUT_H -#define CODE_LAYOUT_H - -struct qr_iterator; - -void qr_layout_init_mask(struct qr_code *); - -struct qr_iterator * qr_layout_begin(struct qr_code * code); -unsigned int qr_layout_read(struct qr_iterator *); -void qr_layout_write(struct qr_iterator *, unsigned int); -void qr_layout_end(struct qr_iterator *); - -#endif - diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index 0d3a71d..a794cdc 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -1,7 +1,5 @@ #include -#include "code-common.h" - struct qr_code * qr_code_parse(const void * buffer, size_t line_bits, size_t line_stride, diff --git a/lpg/libqr/constants.c b/lpg/libqr/constants.c new file mode 100644 index 0000000..86f08ff --- /dev/null +++ b/lpg/libqr/constants.c @@ -0,0 +1,151 @@ +#include "constants.h" + +/* FIXME: don't like big tables of data */ + +const int QR_ALIGNMENT_LOCATION[40][7] = { + { 0, 0, 0, 0, 0, 0, 0 }, /* 1 */ + { 6, 18, 0, 0, 0, 0, 0 }, /* 2 */ + { 6, 22, 0, 0, 0, 0, 0 }, /* 3 */ + { 6, 26, 0, 0, 0, 0, 0 }, /* 4 */ + { 6, 30, 0, 0, 0, 0, 0 }, /* 5 */ + { 6, 34, 0, 0, 0, 0, 0 }, /* 6 */ + { 6, 22, 38, 0, 0, 0, 0 }, /* 7 */ + { 6, 24, 42, 0, 0, 0, 0 }, /* 8 */ + { 6, 26, 46, 0, 0, 0, 0 }, /* 9 */ + { 6, 28, 50, 0, 0, 0, 0 }, /* 10 */ + { 6, 30, 54, 0, 0, 0, 0 }, /* 11 */ + { 6, 32, 58, 0, 0, 0, 0 }, /* 12 */ + { 6, 34, 62, 0, 0, 0, 0 }, /* 13 */ + { 6, 26, 46, 66, 0, 0, 0 }, /* 14 */ + { 6, 26, 48, 70, 0, 0, 0 }, /* 15 */ + { 6, 26, 50, 74, 0, 0, 0 }, /* 16 */ + { 6, 30, 54, 78, 0, 0, 0 }, /* 17 */ + { 6, 30, 56, 82, 0, 0, 0 }, /* 18 */ + { 6, 30, 58, 86, 0, 0, 0 }, /* 19 */ + { 6, 34, 62, 90, 0, 0, 0 }, /* 20 */ + { 6, 28, 50, 72, 94, 0, 0 }, /* 21 */ + { 6, 26, 50, 74, 98, 0, 0 }, /* 22 */ + { 6, 30, 54, 78,102, 0, 0 }, /* 23 */ + { 6, 28, 54, 80,106, 0, 0 }, /* 24 */ + { 6, 32, 58, 84,110, 0, 0 }, /* 25 */ + { 6, 30, 58, 86,114, 0, 0 }, /* 26 */ + { 6, 34, 62, 90,118, 0, 0 }, /* 27 */ + { 6, 26, 50, 74, 98,122, 0 }, /* 28 */ + { 6, 30, 54, 78,102,126, 0 }, /* 29 */ + { 6, 26, 52, 78,104,130, 0 }, /* 30 */ + { 6, 30, 56, 82,108,134, 0 }, /* 31 */ + { 6, 34, 60, 86,112,138, 0 }, /* 32 */ + { 6, 30, 58, 86,114,142, 0 }, /* 33 */ + { 6, 34, 62, 90,118,146, 0 }, /* 34 */ + { 6, 30, 54, 78,102,126,150 }, /* 35 */ + { 6, 24, 50, 76,102,128,154 }, /* 36 */ + { 6, 28, 54, 80,106,132,158 }, /* 37 */ + { 6, 32, 58, 84,110,136,162 }, /* 38 */ + { 6, 26, 54, 82,110,138,166 }, /* 39 */ + { 6, 30, 58, 86,114,142,170 }, /* 40 */ +}; + +const int QR_DATA_WORD_COUNT[40][4] = { + { 19, 16, 13, 9 }, + { 34, 28, 22, 16 }, + { 55, 44, 34, 26 }, + { 80, 64, 48, 36 }, + { 108, 86, 62, 46 }, + { 136, 108, 76, 60 }, + { 156, 124, 88, 66 }, + { 194, 154, 110, 86 }, + { 232, 182, 132, 100 }, + { 274, 216, 154, 122 }, + { 324, 254, 180, 140 }, + { 370, 290, 206, 158 }, + { 428, 334, 244, 180 }, + { 461, 365, 261, 197 }, + { 523, 415, 295, 223 }, + { 589, 453, 325, 253 }, + { 647, 507, 367, 283 }, + { 721, 563, 397, 313 }, + { 795, 627, 445, 341 }, + { 861, 669, 485, 385 }, + { 932, 714, 512, 406 }, + { 1006, 782, 568, 442 }, + { 1094, 860, 614, 464 }, + { 1174, 914, 664, 514 }, + { 1276, 1000, 718, 538 }, + { 1370, 1062, 754, 596 }, + { 1468, 1128, 808, 628 }, + { 1531, 1193, 871, 661 }, + { 1631, 1267, 911, 701 }, + { 1735, 1373, 985, 745 }, + { 1845, 1455, 1033, 793 }, + { 1955, 1541, 1115, 845 }, + { 2071, 1631, 1171, 901 }, + { 2191, 1725, 1231, 961 }, + { 2306, 1812, 1286, 986 }, + { 2434, 1914, 1351, 1054 }, + { 2566, 1992, 1426, 1096 }, + { 2812, 2216, 1582, 1222 }, + { 2956, 2334, 1666, 1276 } +}; + +const int QR_RS_BLOCK_COUNT[40][4][2] = { + { 1, 0, 1, 0, 1, 0, 1, 0 }, /* 1 */ + { 1, 0, 1, 0, 1, 0, 1, 0 }, /* 2 */ + { 1, 0, 1, 0, 2, 0, 2, 0 }, /* 3 */ + { 1, 0, 2, 0, 2, 0, 4, 0 }, /* 4 */ + { 1, 0, 2, 0, 2, 0, 2, 0 }, /* 5 */ + { 2, 0, 4, 0, 4, 0, 4, 0 }, /* 6 */ + { 2, 0, 4, 0, 2, 4, 4, 1 }, /* 7 */ + { 2, 0, 2, 2, 4, 2, 4, 2 }, /* 8 */ + { 2, 0, 3, 2, 4, 4, 4, 4 }, /* 9 */ + { 2, 2, 4, 1, 6, 2, 6, 2 }, /* 10 */ + { 4, 0, 1, 4, 4, 4, 3, 8 }, /* 11 */ + { 2, 2, 6, 2, 4, 6, 7, 4 }, /* 12 */ + { 4, 0, 8, 1, 8, 4, 12, 4 }, /* 13 */ + { 3, 1, 4, 5, 11, 5, 11, 5 }, /* 14 */ + { 5, 1, 5, 5, 5, 7, 11, 7 }, /* 15 */ + { 5, 1, 7, 3, 15, 2, 3, 13 }, /* 16 */ + { 1, 5, 10, 1, 1, 15, 2, 17 }, /* 17 */ + { 5, 1, 9, 4, 17, 1, 2, 19 }, /* 18 */ + { 3, 4, 3, 11, 17, 4, 9, 16 }, /* 19 */ + { 3, 5, 3, 13, 15, 5, 15, 10 }, /* 20 */ + { 4, 4, 17, 0, 17, 6, 19, 6 }, /* 21 */ + { 2, 7, 17, 0, 7, 16, 34, 0 }, /* 22 */ + { 4, 5, 4, 14, 11, 14, 16, 14 }, /* 23 */ + { 6, 4, 6, 14, 11, 16, 30, 2 }, /* 24 */ + { 8, 4, 8, 13, 7, 22, 22, 13 }, /* 25 */ + { 10, 2, 19, 4, 28, 6, 33, 4 }, /* 26 */ + { 8, 4, 22, 3, 8, 26, 12, 28 }, /* 27 */ + { 3, 10, 3, 23, 4, 31, 11, 31 }, /* 28 */ + { 7, 7, 21, 7, 1, 37, 19, 26 }, /* 29 */ + { 5, 10, 19, 10, 15, 25, 23, 25 }, /* 30 */ + { 13, 3, 2, 29, 42, 1, 23, 28 }, /* 31 */ + { 17, 0, 10, 23, 10, 35, 19, 35 }, /* 32 */ + { 17, 1, 14, 21, 29, 19, 11, 46 }, /* 33 */ + { 13, 6, 14, 23, 44, 7, 59, 1 }, /* 34 */ + { 12, 7, 12, 26, 39, 14, 22, 41 }, /* 35 */ + { 6, 14, 6, 34, 46, 10, 2, 64 }, /* 36 */ + { 17, 4, 29, 14, 49, 10, 24, 46 }, /* 37 */ + { 4, 18, 13, 32, 48, 14, 42, 32 }, /* 38 */ + { 20, 4, 40, 7, 43, 22, 10, 67 }, /* 39 */ + { 19, 6, 18, 31, 34, 34, 20, 61 } /* 40 */ +}; + +const enum qr_data_type QR_TYPE_CODES[16] = { + QR_DATA_INVALID, /* 0000 */ + QR_DATA_NUMERIC, /* 0001 */ + QR_DATA_ALPHA, /* 0010 */ + QR_DATA_MIXED, /* 0011 */ + QR_DATA_8BIT, /* 0100 */ + QR_DATA_FNC1, /* 0101 */ + QR_DATA_INVALID, /* 0110 */ + QR_DATA_ECI, /* 0111 */ + QR_DATA_KANJI, /* 1000 */ + QR_DATA_FNC1, /* 1001 */ + QR_DATA_INVALID, /* 1010 */ + QR_DATA_INVALID, /* 1011 */ + QR_DATA_INVALID, /* 1100 */ + QR_DATA_INVALID, /* 1101 */ + QR_DATA_INVALID, /* 1110 */ + QR_DATA_INVALID, /* 1111 */ +}; + diff --git a/lpg/libqr/constants.h b/lpg/libqr/constants.h new file mode 100644 index 0000000..15aa515 --- /dev/null +++ b/lpg/libqr/constants.h @@ -0,0 +1,12 @@ +#ifndef QR_CONSTANTS_H +#define QR_CONSTANTS_H + +#include + +extern const int QR_ALIGNMENT_LOCATION[40][7]; +extern const int QR_DATA_WORD_COUNT[40][4]; +extern const int QR_RS_BLOCK_COUNT[40][4][2]; +extern const enum qr_data_type QR_TYPE_CODES[16]; + +#endif + diff --git a/lpg/libqr/data-common.c b/lpg/libqr/data-common.c index ac2f198..8a05f4a 100644 --- a/lpg/libqr/data-common.c +++ b/lpg/libqr/data-common.c @@ -1,27 +1,7 @@ #include -#include - -#include "qr-bitstream.h" -#include "data-common.h" -const enum qr_data_type QR_TYPE_CODES[16] = { - QR_DATA_INVALID, /* 0000 */ - QR_DATA_NUMERIC, /* 0001 */ - QR_DATA_ALPHA, /* 0010 */ - QR_DATA_MIXED, /* 0011 */ - QR_DATA_8BIT, /* 0100 */ - QR_DATA_FNC1, /* 0101 */ - QR_DATA_INVALID, /* 0110 */ - QR_DATA_ECI, /* 0111 */ - QR_DATA_KANJI, /* 1000 */ - QR_DATA_FNC1, /* 1001 */ - QR_DATA_INVALID, /* 1010 */ - QR_DATA_INVALID, /* 1011 */ - QR_DATA_INVALID, /* 1100 */ - QR_DATA_INVALID, /* 1101 */ - QR_DATA_INVALID, /* 1110 */ - QR_DATA_INVALID, /* 1111 */ -}; +#include +#include void qr_free_data(struct qr_data * data) { @@ -29,7 +9,7 @@ void qr_free_data(struct qr_data * data) free(data); } -size_t get_size_field_length(int version, enum qr_data_type type) +size_t qr_data_size_field_length(int version, enum qr_data_type type) { static const size_t QR_SIZE_LENGTHS[3][4] = { { 10, 9, 8, 8 }, diff --git a/lpg/libqr/data-common.h b/lpg/libqr/data-common.h deleted file mode 100644 index 054d349..0000000 --- a/lpg/libqr/data-common.h +++ /dev/null @@ -1,22 +0,0 @@ -#ifndef DATA_COMMON_H -#define DATA_COMMON_H - -#include - -#include "qr-bitstream.h" - -struct qr_data { - int version; /* 1 ~ 40 */ - enum qr_ec_level ec; - struct qr_bitstream * bits; - size_t offset; -}; - -extern const enum qr_data_type QR_TYPE_CODES[16]; - -size_t get_size_field_length(int version, enum qr_data_type); - -size_t qr_data_dpart_length(enum qr_data_type type, size_t nchars); - -#endif - diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c index 37556c6..9d6c384 100644 --- a/lpg/libqr/data-create.c +++ b/lpg/libqr/data-create.c @@ -2,16 +2,12 @@ * Not "pure" C - only works with ASCII */ -/** XXX: check that the data will fit! **/ - #include #include -#include -#include "qr-bitstream.h" -#include "data-common.h" - -extern const int QR_DATA_WORD_COUNT[40][4]; +#include +#include +#include "constants.h" static void write_type_and_length(struct qr_data * data, enum qr_data_type type, @@ -19,7 +15,7 @@ static void write_type_and_length(struct qr_data * data, { (void)qr_bitstream_write(data->bits, QR_TYPE_CODES[type], 4); (void)qr_bitstream_write(data->bits, length, - get_size_field_length(data->version, type)); + qr_data_size_field_length(data->version, type)); } static struct qr_data * encode_numeric(struct qr_data * data, @@ -29,7 +25,7 @@ static struct qr_data * encode_numeric(struct qr_data * data, struct qr_bitstream * stream = data->bits; size_t bits; - bits = 4 + get_size_field_length(data->version, QR_DATA_NUMERIC) + bits = 4 + qr_data_size_field_length(data->version, QR_DATA_NUMERIC) + qr_data_dpart_length(QR_DATA_NUMERIC, length); stream = data->bits; @@ -102,7 +98,7 @@ static struct qr_data * encode_alpha(struct qr_data * data, struct qr_bitstream * stream = data->bits; size_t bits; - bits = 4 + get_size_field_length(data->version, QR_DATA_ALPHA) + bits = 4 + qr_data_size_field_length(data->version, QR_DATA_ALPHA) + qr_data_dpart_length(QR_DATA_ALPHA, length); stream = data->bits; @@ -145,7 +141,7 @@ static struct qr_data * encode_8bit(struct qr_data * data, struct qr_bitstream * stream = data->bits; size_t bits; - bits = 4 + get_size_field_length(data->version, QR_DATA_8BIT) + bits = 4 + qr_data_size_field_length(data->version, QR_DATA_8BIT) + qr_data_dpart_length(QR_DATA_8BIT, length); stream = data->bits; @@ -178,7 +174,7 @@ static int calc_min_version(enum qr_data_type type, dbits = qr_data_dpart_length(type, length); for (version = 1; version <= 40; ++version) { - if (4 + dbits + get_size_field_length(version, type) + if (4 + dbits + qr_data_size_field_length(version, type) < 8 * QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]) return version; } diff --git a/lpg/libqr/data-parse.c b/lpg/libqr/data-parse.c index 4868cd2..801aa66 100644 --- a/lpg/libqr/data-parse.c +++ b/lpg/libqr/data-parse.c @@ -1,10 +1,10 @@ #include #include #include -#include -#include "qr-bitstream.h" -#include "data-common.h" +#include +#include +#include "constants.h" static enum qr_data_type read_data_type(struct qr_bitstream * stream) { @@ -33,7 +33,7 @@ static enum qr_data_type parse_numeric(const struct qr_data * data, stream = data->bits; buffer = 0; - field_len = get_size_field_length(data->version, QR_DATA_NUMERIC); + field_len = qr_data_size_field_length(data->version, QR_DATA_NUMERIC); if (qr_bitstream_remaining(stream) < field_len) goto invalid; @@ -93,7 +93,7 @@ static enum qr_data_type parse_alpha(const struct qr_data * data, stream = data->bits; buffer = 0; - field_len = get_size_field_length(data->version, QR_DATA_ALPHA); + field_len = qr_data_size_field_length(data->version, QR_DATA_ALPHA); if (qr_bitstream_remaining(stream) < field_len) goto invalid; @@ -150,7 +150,7 @@ static enum qr_data_type parse_8bit(const struct qr_data * data, stream = data->bits; - field_len = get_size_field_length(data->version, QR_DATA_8BIT); + field_len = qr_data_size_field_length(data->version, QR_DATA_8BIT); if (qr_bitstream_remaining(stream) < field_len) return QR_DATA_INVALID; @@ -181,7 +181,7 @@ static enum qr_data_type parse_kanji(const struct qr_data * data, return QR_DATA_INVALID; } -enum qr_data_type qr_get_data_type(const struct qr_data * data) +enum qr_data_type qr_data_type(const struct qr_data * data) { qr_bitstream_seek(data->bits, data->offset); return read_data_type(data->bits); @@ -201,7 +201,7 @@ int qr_get_data_length(const struct qr_data * data) case QR_DATA_ALPHA: case QR_DATA_8BIT: case QR_DATA_KANJI: - field_len = get_size_field_length(data->version, type); + field_len = qr_data_size_field_length(data->version, type); break; default: /* unsupported / invalid */ diff --git a/lpg/libqr/galois.c b/lpg/libqr/galois.c new file mode 100644 index 0000000..e21ce22 --- /dev/null +++ b/lpg/libqr/galois.c @@ -0,0 +1,126 @@ +#include +#include + +#include +#include "galois.h" + +/* Calculate the residue of a modulo m */ +unsigned long gf_residue(unsigned long a, + unsigned long m) +{ + unsigned long o = 1; + int n = 1; + + /* Find one past the highest bit of the modulus */ + while (m & ~(o - 1)) + o <<= 1; + + /* Find the highest n such that O(m * x^n) <= O(a) */ + while (a & ~(o - 1)) { + o <<= 1; + ++n; + } + + /* For each n, try to reduce a by (m * x^n) */ + while (n--) { + o >>= 1; + + /* o is the highest bit of (m * x^n) */ + if (a & o) + a ^= m << n; + } + + return a; +} + +static unsigned int gf_mult(unsigned int a, unsigned int b) +{ + /* Reduce modulo x^8 + x^4 + x^3 + x^2 + 1 + * using the peasant's algorithm + */ + const unsigned int m = 0x11D; + unsigned int x = 0; + int i; + + for (i = 0; i < 8; ++i) { + x ^= (b & 0x1) ? a : 0; + a = (a << 1) ^ ((a & 0x80) ? m : 0); + b >>= 1; + } + + return x & 0xFF; +} + +static unsigned int * make_generator(int k) +{ + unsigned int * g; + unsigned int a; + int i, j; + + g = calloc(k, sizeof(*g)); + if (!g) + return 0; + + g[0] = 1; /* Start with g(x) = 1 */ + a = 1; /* 2^0 = 1 */ + + for (i = 0; i < k; ++i) { + /* Multiply our poly g(x) by (x + 2^i) */ + for (j = k - 1; j > 0; --j) + g[j] = gf_mult(g[j], a) ^ g[j-1]; + g[0] = gf_mult(g[0], a); + + a = gf_mult(a, 2); + } + + return g; +} + +struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, + size_t data_words, + size_t rs_words) +{ + struct qr_bitstream * ec = 0; + unsigned int * b = 0; + unsigned int * g; + size_t n = rs_words; + int i, r; + + assert(qr_bitstream_remaining(data) >= data_words * 8); + + ec = qr_bitstream_create(); + if (!ec) + return 0; + + if (qr_bitstream_resize(ec, n * 8) != 0) + goto fail; + + b = calloc(n, sizeof(*b)); + if (!b) + goto fail; + + g = make_generator(n); + if (!g) + goto fail; + + /* First, prepare the registers (b) with data bits */ + for (i = 0; i < data_words; ++i) { + unsigned int x = b[n-1] ^ qr_bitstream_read(data, 8); + for (r = n-1; r > 0; --r) + b[r] = b[r-1] ^ gf_mult(g[r], x); + b[0] = gf_mult(g[0], x); + } + + /* Read off the registers */ + for (r = 0; r < n; ++r) + qr_bitstream_write(ec, b[(n-1)-r], 8); + + free(g); + free(b); + return ec; +fail: + free(b); + qr_bitstream_destroy(ec); + return 0; +} + diff --git a/lpg/libqr/galois.h b/lpg/libqr/galois.h new file mode 100644 index 0000000..1adeb88 --- /dev/null +++ b/lpg/libqr/galois.h @@ -0,0 +1,12 @@ +#ifndef QR_GALOIS_H +#define QR_GALOIS_H + +unsigned long gf_residue(unsigned long a, + unsigned long m); + +struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, + size_t data_words, + size_t rs_words); + +#endif + diff --git a/lpg/libqr/qr-bitmap-render.c b/lpg/libqr/qr-bitmap-render.c deleted file mode 100644 index 197e947..0000000 --- a/lpg/libqr/qr-bitmap-render.c +++ /dev/null @@ -1,118 +0,0 @@ -#include -#include -#include - -#include - -/* 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 deleted file mode 100644 index 7d2d900..0000000 --- a/lpg/libqr/qr-bitmap.c +++ /dev/null @@ -1,89 +0,0 @@ -#include -#include -#include -#include -#include - -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->mask, 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); - } -} - -struct qr_bitmap * qr_bitmap_clone(const struct qr_bitmap * src) -{ - struct qr_bitmap * bmp; - size_t size; - - bmp = qr_bitmap_create(src->width, src->height, !!src->mask); - if (!bmp) - return 0; - - assert(bmp->stride == src->stride); - - size = bmp->width * bmp->stride; - memcpy(bmp->bits, src->bits, size); - if (bmp->mask) - memcpy(bmp->mask, src->mask, size); - - return 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-bitstream.c b/lpg/libqr/qr-bitstream.c deleted file mode 100644 index c752cde..0000000 --- a/lpg/libqr/qr-bitstream.c +++ /dev/null @@ -1,243 +0,0 @@ -/** - * It would perhaps be more sensible just to store the bits - * as an array of char or similar, but this way is more fun. - * This is a pretty inefficient implementation, althought I - * suspect that won't be a problem. - */ - -#include -#include -#include -#include - -#include "qr-bitstream.h" - -#define MAX(a, b) ((a) < (b) ? (b) : (a)) -#define MIN(a, b) ((a) > (b) ? (b) : (a)) - -struct qr_bitstream { - size_t pos; /* bits */ - size_t count; /* bits */ - size_t bufsiz; /* bytes */ - unsigned char * buffer; -}; - -static size_t bits_to_bytes(size_t bits) -{ - return (bits / CHAR_BIT) + (bits % CHAR_BIT != 0); -} - -static int ensure_available(struct qr_bitstream * stream, size_t bits) -{ - size_t need_bits = stream->pos + bits; - size_t newsize; - - if (stream->bufsiz * CHAR_BIT >= need_bits) - return 0; - - newsize = MAX(stream->bufsiz, 100) * CHAR_BIT; - while (newsize < need_bits) - newsize *= 2; - - return qr_bitstream_resize(stream, newsize); -} - -struct qr_bitstream * qr_bitstream_create(void) -{ - struct qr_bitstream * obj; - - obj = malloc(sizeof(*obj)); - - if (obj) { - obj->pos = 0; - obj->count = 0; - obj->bufsiz = 0; - obj->buffer = 0; - } - - return obj; -} - -int qr_bitstream_resize(struct qr_bitstream * stream, size_t bits) -{ - size_t newsize; - void * newbuf; - - newsize = bits_to_bytes(bits); - newbuf = realloc(stream->buffer, newsize); - - if (newbuf) { - stream->bufsiz = newsize; - stream->buffer = newbuf; - } - - return newbuf ? 0 : -1; -} - -void qr_bitstream_destroy(struct qr_bitstream * stream) -{ - free(stream->buffer); - free(stream); -} - -struct qr_bitstream * qr_bitstream_dup(const struct qr_bitstream * src) -{ - struct qr_bitstream * ret; - - ret = qr_bitstream_create(); - if (!ret) - return 0; - - if (qr_bitstream_resize(ret, src->count) != 0) { - free(ret); - return 0; - } - - ret->pos = src->pos; - ret->count = src->count; - memcpy(ret->buffer, src->buffer, src->bufsiz); - - return ret; -} - -void qr_bitstream_seek(struct qr_bitstream * stream, size_t pos) -{ - assert(pos <= stream->count); - stream->pos = pos; -} - -size_t qr_bitstream_tell(const struct qr_bitstream * stream) -{ - return stream->pos; -} - -size_t qr_bitstream_remaining(const struct qr_bitstream * stream) -{ - return stream->count - stream->pos; -} - -size_t qr_bitstream_size(const struct qr_bitstream * stream) -{ - return stream->count; -} - -unsigned int qr_bitstream_read(struct qr_bitstream * stream, size_t bits) -{ - unsigned int result = 0; - unsigned char * byte; - size_t bitnum; - - assert(qr_bitstream_remaining(stream) >= bits); - - byte = stream->buffer + (stream->pos / CHAR_BIT); - bitnum = stream->pos % CHAR_BIT; - - stream->pos += bits; - - while (bits-- > 0) { - int bit = (*byte >> bitnum++) & 0x1; - result = (result << 1) | bit; - if (bitnum == CHAR_BIT) { - bitnum = 0; - ++byte; - } - } - - return result; -} - -void qr_bitstream_unpack(struct qr_bitstream * stream, - unsigned int * result, - size_t count, - size_t bitsize) -{ - assert(qr_bitstream_remaining(stream) >= (count * bitsize)); - - while (count--) - *(result++) = qr_bitstream_read(stream, bitsize); -} - -int qr_bitstream_write(struct qr_bitstream * stream, - unsigned int value, - size_t bits) -{ - unsigned char * byte; - size_t bitnum; - - if (ensure_available(stream, bits) != 0) - return -1; - - byte = stream->buffer + (stream->pos / CHAR_BIT); - bitnum = stream->pos % CHAR_BIT; - - stream->pos += bits; - stream->count = stream->pos; /* truncate */ - - while (bits-- > 0) { - int bit = (value >> bits) & 0x1; - unsigned char mask = 1 << bitnum++; - *byte = (*byte & ~mask) | (bit ? mask : 0); - if (bitnum == CHAR_BIT) { - bitnum = 0; - ++byte; - } - } - - return 0; -} - -int qr_bitstream_pack(struct qr_bitstream * stream, - const unsigned int * values, - size_t count, - size_t bitsize) -{ - if (ensure_available(stream, count * bitsize) != 0) - return -1; - - while (count--) - qr_bitstream_write(stream, *(values++), bitsize); - - return 0; -} - -int qr_bitstream_cat(struct qr_bitstream * dest, const struct qr_bitstream * src) -{ - size_t count = qr_bitstream_size(src); - size_t srcpos; - - if (ensure_available(dest, count) != 0) - return -1; - - srcpos = qr_bitstream_tell(src); - qr_bitstream_seek((struct qr_bitstream *)src, 0); - qr_bitstream_copy(dest, (struct qr_bitstream *)src, count); - qr_bitstream_seek((struct qr_bitstream *)src, srcpos); - - return 0; -} - -int qr_bitstream_copy(struct qr_bitstream * dest, - struct qr_bitstream * src, - size_t count) -{ - if (qr_bitstream_remaining(src) < count) - return -1; - if (ensure_available(dest, count) != 0) - return -1; - - /* uint must be at least 16 bits */ - for (; count >= 16; count -= 16) - qr_bitstream_write( - dest, - qr_bitstream_read((struct qr_bitstream *)src, 16), - 16); - - if (count > 0) - qr_bitstream_write( - dest, - qr_bitstream_read((struct qr_bitstream *)src, count), - count); - - return 0; -} - diff --git a/lpg/libqr/qr-bitstream.h b/lpg/libqr/qr-bitstream.h deleted file mode 100644 index cf20694..0000000 --- a/lpg/libqr/qr-bitstream.h +++ /dev/null @@ -1,48 +0,0 @@ -#ifndef QR_BITSTREAM_H -#define QR_BITSTREAM_H - -#include - -/** - * Note: when writing / reading multiple bits, the - * _most_ significant bits come first in the stream. - * (That is, the order you would naturally write the - * number in binary) - */ - -struct qr_bitstream; - -struct qr_bitstream * qr_bitstream_create(void); -int qr_bitstream_resize(struct qr_bitstream *, size_t bits); -void qr_bitstream_destroy(struct qr_bitstream *); -struct qr_bitstream * qr_bitstream_dup(const struct qr_bitstream *); - -void qr_bitstream_seek(struct qr_bitstream *, size_t pos); -size_t qr_bitstream_tell(const struct qr_bitstream *); -size_t qr_bitstream_remaining(const struct qr_bitstream *); -size_t qr_bitstream_size(const struct qr_bitstream *); - -unsigned int qr_bitstream_read(struct qr_bitstream *, size_t bits); - -void qr_bitstream_unpack(struct qr_bitstream *, - unsigned int * result, - size_t count, - size_t bitsize); - -int qr_bitstream_write(struct qr_bitstream *, - unsigned int value, - size_t bits); - -int qr_bitstream_pack(struct qr_bitstream *, - const unsigned int * values, - size_t count, - size_t bitsize); - -int qr_bitstream_cat(struct qr_bitstream *, const struct qr_bitstream * src); - -int qr_bitstream_copy(struct qr_bitstream * dest, - struct qr_bitstream * src, - size_t count); - -#endif - diff --git a/lpg/libqr/qr-mask.c b/lpg/libqr/qr-mask.c deleted file mode 100644 index 7ff78a4..0000000 --- a/lpg/libqr/qr-mask.c +++ /dev/null @@ -1,46 +0,0 @@ -#include -#include -#include -#include "qr-mask.h" - -struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, - unsigned int mask) -{ - struct qr_bitmap * bmp; - int i, j; - - if (mask & ~0x7) - return 0; - - bmp = qr_bitmap_clone(orig); - if (!bmp) - return 0; - - /* Slow version for now; we can optimize later */ - - for (i = 0; i < bmp->height; ++i) { - unsigned char * p = bmp->bits + i * bmp->stride; - - for (j = 0; j < bmp->width; ++j) { - int bit = j % CHAR_BIT; - size_t off = j / CHAR_BIT; - int t; - - switch (mask) { - case 0: t = (i + j) % 2; break; - case 1: t = i % 2; break; - case 2: t = j % 3; break; - case 3: t = (i + j) % 3; break; - case 4: t = (i/2 + j/3) % 2; break; - case 5: t = ((i*j) % 2) + ((i*j) % 3); break; - case 6: t = (((i*j) % 2) + ((i*j) % 3)) % 2; break; - case 7: t = (((i*j) % 3) + ((i+j) % 2)) % 2; break; - } - - p[off] ^= (t == 0) << bit; - } - } - - return bmp; -} - diff --git a/lpg/libqr/qr-mask.h b/lpg/libqr/qr-mask.h deleted file mode 100644 index eb254af..0000000 --- a/lpg/libqr/qr-mask.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef QR_MASK_H -#define QR_MASK_H - -#include - -struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, - unsigned int mask); - -#endif - diff --git a/lpg/libqr/qr/bitstream.h b/lpg/libqr/qr/bitstream.h new file mode 100644 index 0000000..cf20694 --- /dev/null +++ b/lpg/libqr/qr/bitstream.h @@ -0,0 +1,48 @@ +#ifndef QR_BITSTREAM_H +#define QR_BITSTREAM_H + +#include + +/** + * Note: when writing / reading multiple bits, the + * _most_ significant bits come first in the stream. + * (That is, the order you would naturally write the + * number in binary) + */ + +struct qr_bitstream; + +struct qr_bitstream * qr_bitstream_create(void); +int qr_bitstream_resize(struct qr_bitstream *, size_t bits); +void qr_bitstream_destroy(struct qr_bitstream *); +struct qr_bitstream * qr_bitstream_dup(const struct qr_bitstream *); + +void qr_bitstream_seek(struct qr_bitstream *, size_t pos); +size_t qr_bitstream_tell(const struct qr_bitstream *); +size_t qr_bitstream_remaining(const struct qr_bitstream *); +size_t qr_bitstream_size(const struct qr_bitstream *); + +unsigned int qr_bitstream_read(struct qr_bitstream *, size_t bits); + +void qr_bitstream_unpack(struct qr_bitstream *, + unsigned int * result, + size_t count, + size_t bitsize); + +int qr_bitstream_write(struct qr_bitstream *, + unsigned int value, + size_t bits); + +int qr_bitstream_pack(struct qr_bitstream *, + const unsigned int * values, + size_t count, + size_t bitsize); + +int qr_bitstream_cat(struct qr_bitstream *, const struct qr_bitstream * src); + +int qr_bitstream_copy(struct qr_bitstream * dest, + struct qr_bitstream * src, + size_t count); + +#endif + diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h index 3c14c1f..ac3c363 100644 --- a/lpg/libqr/qr/code.h +++ b/lpg/libqr/qr/code.h @@ -4,16 +4,26 @@ #include #include "types.h" +struct qr_code { + int version; + struct qr_bitmap * modules; +}; + struct qr_code * qr_code_create(const struct qr_data * data); void qr_code_destroy(struct qr_code *); int qr_code_width(const struct qr_code *); +size_t qr_code_total_capacity(int version); + struct qr_code * qr_code_parse(const void * buffer, size_t line_bits, size_t line_stride, size_t line_count); +struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, + unsigned int mask); + #endif diff --git a/lpg/libqr/qr/data.h b/lpg/libqr/qr/data.h index 34b6968..a3bb309 100644 --- a/lpg/libqr/qr/data.h +++ b/lpg/libqr/qr/data.h @@ -22,6 +22,13 @@ enum qr_ec_level { QR_EC_LEVEL_H = 0x2 }; +struct qr_data { + int version; /* 1 ~ 40 */ + enum qr_ec_level ec; + struct qr_bitstream * bits; + size_t offset; +}; + struct qr_data * qr_create_data(int format, /* 1 ~ 40; 0=auto */ enum qr_ec_level ec, enum qr_data_type type, @@ -30,9 +37,11 @@ struct qr_data * qr_create_data(int format, /* 1 ~ 40; 0=auto */ void qr_free_data(struct qr_data *); -enum qr_data_type qr_get_data_type(const struct qr_data *); +enum qr_data_type qr_data_type(const struct qr_data *); -int qr_get_data_length(const struct qr_data *); +size_t qr_data_length(const struct qr_data *); +size_t qr_data_size_field_length(int version, enum qr_data_type); +size_t qr_data_dpart_length(enum qr_data_type type, size_t nchars); enum qr_data_type qr_parse_data(const struct qr_data * input, char ** output, diff --git a/lpg/libqr/qr/layout.h b/lpg/libqr/qr/layout.h new file mode 100644 index 0000000..49bebf6 --- /dev/null +++ b/lpg/libqr/qr/layout.h @@ -0,0 +1,14 @@ +#ifndef QR_CODE_LAYOUT_H +#define QR_CODE_LAYOUT_H + +struct qr_iterator; + +void qr_layout_init_mask(struct qr_code *); + +struct qr_iterator * qr_layout_begin(struct qr_code * code); +unsigned int qr_layout_read(struct qr_iterator *); +void qr_layout_write(struct qr_iterator *, unsigned int); +void qr_layout_end(struct qr_iterator *); + +#endif + diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index 1309596..ad53125 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -1,17 +1,16 @@ +#include #include +#include +#include #include #include #include -#include -#include -#include + #include +#include #include #include -#include "qr-bitstream.h" -#include "code-common.h" - struct config { int version; enum qr_ec_level ec; diff --git a/lpg/libqr/rs-encode.c b/lpg/libqr/rs-encode.c deleted file mode 100644 index a8ecc73..0000000 --- a/lpg/libqr/rs-encode.c +++ /dev/null @@ -1,96 +0,0 @@ -#include -#include -#include "qr-bitstream.h" -#include "rs.h" - -static unsigned int gf_mult(unsigned int a, unsigned int b) -{ - /* Reduce modulo x^8 + x^4 + x^3 + x^2 + 1 - * using the peasant's algorithm - */ - const unsigned int m = 0x11D; - unsigned int x = 0; - int i; - - for (i = 0; i < 8; ++i) { - x ^= (b & 0x1) ? a : 0; - a = (a << 1) ^ ((a & 0x80) ? m : 0); - b >>= 1; - } - - return x & 0xFF; -} - -static unsigned int * make_generator(int k) -{ - unsigned int * g; - unsigned int a; - int i, j; - - g = calloc(k, sizeof(*g)); - if (!g) - return 0; - - g[0] = 1; /* Start with g(x) = 1 */ - a = 1; /* 2^0 = 1 */ - - for (i = 0; i < k; ++i) { - /* Multiply our poly g(x) by (x + 2^i) */ - for (j = k - 1; j > 0; --j) - g[j] = gf_mult(g[j], a) ^ g[j-1]; - g[0] = gf_mult(g[0], a); - - a = gf_mult(a, 2); - } - - return g; -} - -struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, - size_t data_words, - size_t rs_words) -{ - struct qr_bitstream * ec = 0; - unsigned int * b = 0; - unsigned int * g; - size_t n = rs_words; - int i, r; - - assert(qr_bitstream_remaining(data) >= data_words * 8); - - ec = qr_bitstream_create(); - if (!ec) - return 0; - - if (qr_bitstream_resize(ec, n * 8) != 0) - goto fail; - - b = calloc(n, sizeof(*b)); - if (!b) - goto fail; - - g = make_generator(n); - if (!g) - goto fail; - - /* First, prepare the registers (b) with data bits */ - for (i = 0; i < data_words; ++i) { - unsigned int x = b[n-1] ^ qr_bitstream_read(data, 8); - for (r = n-1; r > 0; --r) - b[r] = b[r-1] ^ gf_mult(g[r], x); - b[0] = gf_mult(g[0], x); - } - - /* Read off the registers */ - for (r = 0; r < n; ++r) - qr_bitstream_write(ec, b[(n-1)-r], 8); - - free(g); - free(b); - return ec; -fail: - free(b); - qr_bitstream_destroy(ec); - return 0; -} - diff --git a/lpg/libqr/rs.h b/lpg/libqr/rs.h deleted file mode 100644 index c87d852..0000000 --- a/lpg/libqr/rs.h +++ /dev/null @@ -1,11 +0,0 @@ -#ifndef RS_H -#define RS_H - -#include "qr-bitstream.h" - -struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, - size_t data_words, - size_t rs_words); - -#endif - -- cgit v1.2.3-70-g09d2 From 5d91255e986b6f1fb6205cc759ff5d43ccb3c96f Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sat, 14 Nov 2009 20:31:08 +0900 Subject: Final tidy for 0.1 --- lpg/libqr/COPYING | 16 +++++++--------- lpg/libqr/TODO | 9 --------- lpg/libqr/code-common.c | 2 +- lpg/libqr/galois.c | 7 +++---- lpg/libqr/galois.h | 7 +++---- lpg/libqr/qr/bitstream.h | 23 ++++++++++++----------- 6 files changed, 26 insertions(+), 38 deletions(-) diff --git a/lpg/libqr/COPYING b/lpg/libqr/COPYING index 10a9711..ff2f585 100644 --- a/lpg/libqr/COPYING +++ b/lpg/libqr/COPYING @@ -1,16 +1,14 @@ -I, the author, hereby release this work into the public -domain. +I, the author, hereby release this work into the public domain. -Where the above is not possible, I release this work as -"Copyright-Free", or (at your option) under the terms of -the Creative Commons CC0 license: +Where the above is not possible, I release this work as "Copyright +Free", or (at your option) under the terms of the Creative Commons CC0 +license: http://creativecommons.org/publicdomain/zero/1.0/ -The author waives all rights concerning the modification, -reproduction and/or distribution of this work, or -derivatives thereof, in whole or part, and in any form. -Attribution is not required. +The author waives all rights concerning the modification, reproduction +and/or distribution of this work, or derivatives thereof, in whole or +in part, and in any form. Attribution is not required. Leo Howell, September 2009 diff --git a/lpg/libqr/TODO b/lpg/libqr/TODO index 3cd0583..1b9671b 100644 --- a/lpg/libqr/TODO +++ b/lpg/libqr/TODO @@ -1,20 +1,11 @@ -* Fix XXX, TODO -* Tidy code -* RELEASE v0.1 - * Parsing -* RELEASE v0.2 * Detection -* RELEASE v0.3 * Test suite * No-malloc * Optimize * Documentation -* RELEASE v0.4 (BETA) - -* RELEASE v1.0 * Other data types diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index bc6621a..a0b8fcc 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -47,7 +47,7 @@ struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, struct qr_bitmap * bmp; int i, j; - if (mask & ~0x7) + if (mask > 7) return 0; bmp = qr_bitmap_clone(orig); diff --git a/lpg/libqr/galois.c b/lpg/libqr/galois.c index e21ce22..f0aadfd 100644 --- a/lpg/libqr/galois.c +++ b/lpg/libqr/galois.c @@ -5,8 +5,7 @@ #include "galois.h" /* Calculate the residue of a modulo m */ -unsigned long gf_residue(unsigned long a, - unsigned long m) +unsigned long gf_residue(unsigned long a, unsigned long m) { unsigned long o = 1; int n = 1; @@ -77,8 +76,8 @@ static unsigned int * make_generator(int k) } struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, - size_t data_words, - size_t rs_words) + size_t data_words, + size_t rs_words) { struct qr_bitstream * ec = 0; unsigned int * b = 0; diff --git a/lpg/libqr/galois.h b/lpg/libqr/galois.h index 1adeb88..4ca0c93 100644 --- a/lpg/libqr/galois.h +++ b/lpg/libqr/galois.h @@ -1,12 +1,11 @@ #ifndef QR_GALOIS_H #define QR_GALOIS_H -unsigned long gf_residue(unsigned long a, - unsigned long m); +unsigned long gf_residue(unsigned long a, unsigned long m); struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, - size_t data_words, - size_t rs_words); + size_t data_words, + size_t rs_words); #endif diff --git a/lpg/libqr/qr/bitstream.h b/lpg/libqr/qr/bitstream.h index cf20694..5ca6b41 100644 --- a/lpg/libqr/qr/bitstream.h +++ b/lpg/libqr/qr/bitstream.h @@ -13,8 +13,8 @@ struct qr_bitstream; struct qr_bitstream * qr_bitstream_create(void); -int qr_bitstream_resize(struct qr_bitstream *, size_t bits); -void qr_bitstream_destroy(struct qr_bitstream *); +int qr_bitstream_resize(struct qr_bitstream *, size_t bits); +void qr_bitstream_destroy(struct qr_bitstream *); struct qr_bitstream * qr_bitstream_dup(const struct qr_bitstream *); void qr_bitstream_seek(struct qr_bitstream *, size_t pos); @@ -25,20 +25,21 @@ size_t qr_bitstream_size(const struct qr_bitstream *); unsigned int qr_bitstream_read(struct qr_bitstream *, size_t bits); void qr_bitstream_unpack(struct qr_bitstream *, - unsigned int * result, - size_t count, - size_t bitsize); + unsigned int * result, + size_t count, + size_t bitsize); int qr_bitstream_write(struct qr_bitstream *, - unsigned int value, - size_t bits); + unsigned int value, + size_t bits); int qr_bitstream_pack(struct qr_bitstream *, - const unsigned int * values, - size_t count, - size_t bitsize); + const unsigned int * values, + size_t count, + size_t bitsize); -int qr_bitstream_cat(struct qr_bitstream *, const struct qr_bitstream * src); +int qr_bitstream_cat(struct qr_bitstream *, + const struct qr_bitstream * src); int qr_bitstream_copy(struct qr_bitstream * dest, struct qr_bitstream * src, -- cgit v1.2.3-70-g09d2 From c02f534047b35e3db4b300264a0abb790e9121af Mon Sep 17 00:00:00 2001 From: Leo Howell Date: Sun, 15 Nov 2009 10:37:45 +0900 Subject: Fix memory leak in qrgen --- lpg/libqr/qrgen.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index ad53125..b95db0a 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -41,10 +41,10 @@ struct qr_code * create(int version, } code = qr_code_create(data); + qr_free_data(data); if (!code) { perror("Failed to create code"); - qr_free_data(data); exit(2); } -- cgit v1.2.3-70-g09d2 From 2280c632f390b6e6a682a38d9abee9f08e41db02 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Wed, 13 Jul 2011 17:39:25 +0900 Subject: Fix incorrect layout of format info --- lpg/libqr/code-create.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 0882b88..b0db1c9 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -527,7 +527,7 @@ static int draw_format(struct qr_bitmap * bmp, for (i = 0; i < 8; ++i) { if (bits & 0x1) { - setpx(bmp, 8, i); + setpx(bmp, 8, i + (i > 5)); setpx(bmp, dim - 1 - i, 8); } bits >>= 1; -- cgit v1.2.3-70-g09d2 From 44fc0ba93934ea9915fcd4f1902f49de57f2a949 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Wed, 13 Jul 2011 22:41:27 +0900 Subject: Fix evil table of constants --- lpg/libqr/constants.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lpg/libqr/constants.c b/lpg/libqr/constants.c index 86f08ff..797d853 100644 --- a/lpg/libqr/constants.c +++ b/lpg/libqr/constants.c @@ -92,7 +92,7 @@ const int QR_RS_BLOCK_COUNT[40][4][2] = { { 1, 0, 1, 0, 1, 0, 1, 0 }, /* 2 */ { 1, 0, 1, 0, 2, 0, 2, 0 }, /* 3 */ { 1, 0, 2, 0, 2, 0, 4, 0 }, /* 4 */ - { 1, 0, 2, 0, 2, 0, 2, 0 }, /* 5 */ + { 1, 0, 2, 0, 2, 2, 2, 2 }, /* 5 */ { 2, 0, 4, 0, 4, 0, 4, 0 }, /* 6 */ { 2, 0, 4, 0, 2, 4, 4, 1 }, /* 7 */ { 2, 0, 2, 2, 4, 2, 4, 2 }, /* 8 */ -- cgit v1.2.3-70-g09d2 From 35baea42d794bec1fd5f2200f1f6f48877c5c26c Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Thu, 14 Jul 2011 11:06:47 +0900 Subject: First attempt at parsing --- lpg/libqr/Makefile | 5 +- lpg/libqr/bitmap.c | 10 ++ lpg/libqr/code-create.c | 1 + lpg/libqr/code-layout.c | 6 +- lpg/libqr/code-parse.c | 312 +++++++++++++++++++++++++++++++++++++++++++++++- lpg/libqr/constants.h | 1 + lpg/libqr/data-parse.c | 3 + lpg/libqr/qr/bitmap.h | 2 + lpg/libqr/qr/code.h | 5 - lpg/libqr/qr/parse.h | 16 +++ lpg/libqr/qrparse.c | 59 +++++++++ lpg/libqr/testqr.xbm | 19 +++ 12 files changed, 427 insertions(+), 12 deletions(-) create mode 100644 lpg/libqr/qr/parse.h create mode 100644 lpg/libqr/qrparse.c create mode 100644 lpg/libqr/testqr.xbm diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index a82372f..fa6cf04 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -14,7 +14,7 @@ CFLAGS := -std=c89 -pedantic -I. -Wall CFLAGS += -g #CFLAGS += -O3 -DNDEBUG -all : libqr qrgen +all : libqr qrgen qrparse $(OBJECTS) : $(wildcard *.h qr/*.h) @@ -23,6 +23,9 @@ libqr : libqr.a($(OBJECTS)) qrgen : libqr qrgen.c $(CC) $(CFLAGS) -o qrgen qrgen.c libqr.a +qrparse : libqr qrparse.c + $(CC) $(CFLAGS) -o qrparse qrparse.c libqr.a + .PHONY : clean clean: $(RM) qr/*~ *~ *.o *.a *.so qrgen diff --git a/lpg/libqr/bitmap.c b/lpg/libqr/bitmap.c index 3394784..759aeca 100644 --- a/lpg/libqr/bitmap.c +++ b/lpg/libqr/bitmap.c @@ -49,6 +49,16 @@ void qr_bitmap_destroy(struct qr_bitmap * bmp) } } +int qr_bitmap_add_mask(struct qr_bitmap * bmp) +{ + size_t size = bmp->stride * bmp->width; + bmp->mask = malloc(size); + if (!bmp->mask) + return -1; + memset(bmp->mask, 0xFF, size); + return 0; +} + struct qr_bitmap * qr_bitmap_clone(const struct qr_bitmap * src) { struct qr_bitmap * bmp; diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index b0db1c9..155ffa3 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -588,6 +588,7 @@ static long calc_version_bits(int version) bits <<= 18 - 6; bits |= gf_residue(bits, 0x1F25); +fprintf(stderr, "version bits: %lx\n", bits); return bits; } diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 68a1a0e..04b6ca6 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -26,6 +26,9 @@ void qr_layout_init_mask(struct qr_code * code) const int * am_pos = QR_ALIGNMENT_LOCATION[code->version - 1]; int am_side; + if (!bmp->mask) + qr_bitmap_add_mask(bmp); + assert(bmp->mask); memset(bmp->mask, 0, bmp->height * bmp->stride); @@ -164,9 +167,8 @@ unsigned int qr_layout_read(struct qr_iterator * i) int b; for (b = 0; b < 8; ++b) { - x |= (*i->p & i->mask) ? 1 : 0; + x = (x << 1) | ((*i->p & i->mask) ? 1 : 0); advance(i); - x <<= 1; } return x; diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index a794cdc..50d621c 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -1,10 +1,314 @@ +#include +#include +#include +#include +#include + +#include +#include #include +#include +#include +#include + +#include "constants.h" +#include "galois.h" + +/* XXX: duplicated */ +static int get_px(const struct qr_bitmap * bmp, int x, int y) +{ + size_t off = y * bmp->stride + x / CHAR_BIT; + unsigned char bit = 1 << (x % CHAR_BIT); + + return bmp->bits[off] & bit; +} + +static int unpack_bits(int version, + enum qr_ec_level ec, + struct qr_bitstream * raw_bits, + struct qr_bitstream * bits_out) +{ + /* FIXME: less math here (get the values from a common helper fn) */ + /* FIXME: more comments to explain the algorithm */ + + const size_t total_bits = qr_code_total_capacity(version); + const size_t total_words = total_bits / 8; + const size_t total_data = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]; + int total_blocks, block_count[2], row_length[2], data_words, rs_words; + int i, w, block; + struct qr_bitstream ** blocks = 0; + + /* copied from make_data */ + block_count[0] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][0]; + block_count[1] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][1]; + total_blocks = block_count[0] + block_count[1]; + data_words = total_data / total_blocks; + rs_words = total_words / total_blocks - data_words; + assert((data_words + rs_words) * block_count[0] + + (data_words + rs_words + 1) * block_count[1] == total_words); + + blocks = calloc(total_blocks, sizeof(*blocks)); + /* XXX: check return (and below) */ + + for (i = 0; i < total_blocks; ++i) + blocks[i] = qr_bitstream_create(); + + /* Read in the data & EC (see spec table 19) */ + + qr_bitstream_seek(raw_bits, 0); + + /* XXX: 14-M will be incorrect */ + row_length[0] = data_words; + row_length[1] = block_count[1] > 0 ? (total_data - row_length[0] * block_count[0]) / block_count[1] : 0; + + fprintf(stderr, "block counts %d and %d\n", block_count[0], block_count[1]); + fprintf(stderr, "row lengths %d and %d\n", row_length[0], row_length[1]); + + block = 0; + for (w = 0; w < total_words; ++w) { + if (block == 0 && w / total_blocks == row_length[0] && block_count[1] != 0) { + /* Skip the short blocks, if there are any */ + block += block_count[0]; + } + qr_bitstream_write(blocks[block], qr_bitstream_read(raw_bits, 8), 8); + block = (block + 1) % total_blocks; + } + + /* XXX: apply ec */ + + for (block = 0; block < total_blocks; ++block) { + struct qr_bitstream * stream = blocks[block]; + qr_bitstream_seek(stream, 0); + for (w = 0; w < row_length[block >= block_count[0]]; ++w) + qr_bitstream_write(bits_out, + qr_bitstream_read(stream, 8), + 8); + qr_bitstream_destroy(stream); + } + free(blocks); + + return 0; +} -struct qr_code * qr_code_parse(const void * buffer, - size_t line_bits, - size_t line_stride, - size_t line_count) +static int read_bits(const struct qr_code * code, + enum qr_ec_level ec, + struct qr_bitstream * data_bits) { + const size_t total_bits = qr_code_total_capacity(code->version); + const size_t total_words = total_bits / 8; + struct qr_bitstream * raw_bits; + struct qr_iterator * layout; + int w; + int ret; + + raw_bits = qr_bitstream_create(); + layout = qr_layout_begin((struct qr_code *) code); /* dropping const! */ + for (w = 0; w < total_words; ++w) + qr_bitstream_write(raw_bits, qr_layout_read(layout), 8); + qr_layout_end(layout); + + ret = unpack_bits(code->version, ec, raw_bits, data_bits); + qr_bitstream_destroy(raw_bits); + + return ret; +} + +static int read_format(const struct qr_bitmap * bmp, enum qr_ec_level * ec, int * mask) +{ + int dim; + int i; + unsigned bits1, bits2; + enum qr_ec_level ec1, ec2; + int mask1, mask2; + int err1, err2; + + dim = bmp->width; + bits1 = bits2 = 0; + + for (i = 14; i >= 8; --i) { + bits1 = (bits1 << 1) | !!get_px(bmp, 14 - i + (i <= 8), 8); + bits2 = (bits2 << 1) | !!get_px(bmp, 8, dim - 1 - (14 - i)); + } + + for (; i >= 0; --i) { + bits1 = (bits1 << 1) | !!get_px(bmp, 8, i + (i >= 6)); + bits2 = (bits2 << 1) | !!get_px(bmp, dim - 1 - i, 8); + } + + fprintf(stderr, "read format bits %x / %x\n", bits1, bits2); + + err1 = qr_decode_format(bits1, &ec1, &mask1); + err2 = qr_decode_format(bits2, &ec2, &mask2); + + if (err1 < 0 && err2 < 0) + return -1; + + if (err1 < err2) + *ec = ec1, *mask = mask1; + else + *ec = ec2, *mask = mask2; + return 0; } +static int read_version(const struct qr_bitmap * bmp) +{ + int dim; + int i; + unsigned long bits1, bits2; + int ver1, ver2; + int err1, err2; + + dim = bmp->width; + bits1 = bits2 = 0; + + for (i = 17; i >= 0; --i) { + bits1 = (bits1 << 1) | !!get_px(bmp, i / 3, dim - 11 + (i % 3)); + bits2 = (bits2 << 1) | !!get_px(bmp, dim - 11 + (i % 3), i / 3); + } + + fprintf(stderr, "read version bits %lx / %lx\n", bits1, bits2); + + err1 = qr_decode_version(bits1, &ver1); + err2 = qr_decode_version(bits2, &ver2); + + fprintf(stderr, "got versions %d[%d] / %d[%d]\n", ver1, err1, ver2, err2); + + if (err1 < 0 && err2 < 0) + return -1; + + return err1 < err2 ? ver1 : ver2; +} + +int qr_code_parse(const void * buffer, + size_t line_bits, + size_t line_stride, + size_t line_count, + struct qr_data ** data) +{ + struct qr_bitmap src_bmp; + struct qr_code code; + enum qr_ec_level ec; + int mask; + struct qr_bitstream * data_bits; + + fprintf(stderr, "parsing code bitmap %lux%lu\n", line_bits, line_count); + + if (line_bits != line_count + || line_bits < 21 + || (line_bits - 17) % 4 != 0) { + /* Invalid size */ + fprintf(stderr, "Invalid size\n"); + return -1; + } + + code.version = (line_bits - 17) / 4; + fprintf(stderr, "assuming version %d\n", code.version); + + src_bmp.bits = (unsigned char *) buffer; /* dropping const! */ + src_bmp.mask = NULL; + src_bmp.stride = line_stride; + src_bmp.width = line_bits; + src_bmp.height = line_count; + + if (code.version >= 7 && read_version(&src_bmp) != code.version) { + fprintf(stderr, "Invalid version info\n"); + return -1; + } + + if (read_format(&src_bmp, &ec, &mask) != 0) { + fprintf(stderr, "Failed to read format\n"); + return -1; + } + + fprintf(stderr, "detected ec type %d; mask %d\n", ec, mask); + + code.modules = qr_mask_apply(&src_bmp, mask); + if (code.modules == NULL) { + fprintf(stderr, "failed to apply mask\n"); + return -1; + } + + qr_layout_init_mask(&code); + + data_bits = qr_bitstream_create(); + /* XXX: check return */ + + read_bits(&code, ec, data_bits); + /* XXX: check return */ + + /* + { + fprintf(stderr, "decoding failed\n"); + qr_bitmap_destroy(code.modules); + qr_bitstream_destroy(bits); + *data = NULL; + return -1; + } + */ + + *data = malloc(sizeof(*data)); + /* XXX: check return */ + + (*data)->version = code.version; + (*data)->ec = ec; + (*data)->bits = data_bits; + (*data)->offset = 0; + + return 0; +} + +int qr_decode_format(unsigned bits, enum qr_ec_level * ec, int * mask) +{ + bits ^= 0x5412; + + /* TODO: check and fix errors */ + + bits >>= 10; + *mask = bits & 7; + *ec = bits >> 3; + + return 0; +} + +int qr_decode_version(unsigned long bits, int * version) +{ + int v, errors; + unsigned long version_bits; + int best_err, best_version; + + if (bits != (bits & 0x3FFFF)) + fprintf(stderr, "WARNING: excess version bits"); + + best_err = 18; + + for (v = 7; v <= 40; ++v) { + /* FIXME: cache these values */ + /* see calc_version_bits() */ + version_bits = v; + version_bits <<= 12; + version_bits |= gf_residue(version_bits, 0x1F25); + + /* count errors */ + errors = 0; + version_bits ^= bits; + while (version_bits != 0) { + if ((version_bits & 1) == 1) + ++errors; + version_bits >>= 1; + } + + if (errors < best_err) { + best_version = v; + best_err = errors; + } + + if (errors == 0) /* can we do better than this? */ + break; + } + + *version = best_version; + + return best_err; +} + diff --git a/lpg/libqr/constants.h b/lpg/libqr/constants.h index 15aa515..2c19e97 100644 --- a/lpg/libqr/constants.h +++ b/lpg/libqr/constants.h @@ -5,6 +5,7 @@ extern const int QR_ALIGNMENT_LOCATION[40][7]; extern const int QR_DATA_WORD_COUNT[40][4]; +/* See spec table 18 (also table 19 for application) */ extern const int QR_RS_BLOCK_COUNT[40][4][2]; extern const enum qr_data_type QR_TYPE_CODES[16]; diff --git a/lpg/libqr/data-parse.c b/lpg/libqr/data-parse.c index 801aa66..d641c47 100644 --- a/lpg/libqr/data-parse.c +++ b/lpg/libqr/data-parse.c @@ -220,6 +220,9 @@ enum qr_data_type qr_parse_data(const struct qr_data * input, { qr_bitstream_seek(input->bits, input->offset); + *output = NULL; + *length = 0; + switch (read_data_type(input->bits)) { case QR_DATA_NUMERIC: return parse_numeric(input, output, length); diff --git a/lpg/libqr/qr/bitmap.h b/lpg/libqr/qr/bitmap.h index 83e82ab..36c56b3 100644 --- a/lpg/libqr/qr/bitmap.h +++ b/lpg/libqr/qr/bitmap.h @@ -11,6 +11,8 @@ struct qr_bitmap { struct qr_bitmap * qr_bitmap_create(int width, int height, int masked); void qr_bitmap_destroy(struct qr_bitmap *); +int qr_bitmap_add_mask(struct qr_bitmap *); + struct qr_bitmap * qr_bitmap_clone(const struct qr_bitmap *); void qr_bitmap_merge(struct qr_bitmap * dest, const struct qr_bitmap * src); diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h index ac3c363..2392467 100644 --- a/lpg/libqr/qr/code.h +++ b/lpg/libqr/qr/code.h @@ -17,11 +17,6 @@ int qr_code_width(const struct qr_code *); size_t qr_code_total_capacity(int version); -struct qr_code * qr_code_parse(const void * buffer, - size_t line_bits, - size_t line_stride, - size_t line_count); - struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, unsigned int mask); diff --git a/lpg/libqr/qr/parse.h b/lpg/libqr/qr/parse.h new file mode 100644 index 0000000..d7b8c4e --- /dev/null +++ b/lpg/libqr/qr/parse.h @@ -0,0 +1,16 @@ +#ifndef QR_PARSE_H +#define QR_PARSE_H + +#include "data.h" + +int qr_code_parse(const void * buffer, + size_t line_bits, + size_t line_stride, + size_t line_count, + struct qr_data ** data); + +int qr_decode_format(unsigned bits, enum qr_ec_level * ec, int * mask); +int qr_decode_version(unsigned long bits, int * version); + +#endif + diff --git a/lpg/libqr/qrparse.c b/lpg/libqr/qrparse.c new file mode 100644 index 0000000..4a9312f --- /dev/null +++ b/lpg/libqr/qrparse.c @@ -0,0 +1,59 @@ +#include +#include +#include + +#include +#include +#include + +#include "testqr.xbm" + +int main(int argc, char ** argv) +{ + struct qr_data * data; + int ret; + + ret = qr_code_parse(testqr_bits, + testqr_width, + (testqr_width + CHAR_BIT - 1) / CHAR_BIT, + testqr_height, + &data); + + fprintf(stderr, "qr_code_parse returned %d\n", ret); + + if (ret == 0) { + const char * ec_str, * type_str; + char * data_str; + size_t data_len; + enum qr_data_type data_type; + + fprintf(stderr, "version = %d\n", data->version); + switch (data->ec) { + case QR_EC_LEVEL_L: ec_str = "L"; break; + case QR_EC_LEVEL_M: ec_str = "M"; break; + case QR_EC_LEVEL_Q: ec_str = "Q"; break; + case QR_EC_LEVEL_H: ec_str = "H"; break; + default: ec_str = "(unknown)"; break; + } + fprintf(stderr, "EC level %s\n", ec_str); + + data_type = qr_parse_data(data, &data_str, &data_len); + switch (data_type) { + case QR_DATA_INVALID: type_str = "(invalid)"; break; + case QR_DATA_ECI: type_str = "ECI"; break; + case QR_DATA_NUMERIC: type_str = "numeric"; break; + case QR_DATA_ALPHA: type_str = "alpha"; break; + case QR_DATA_8BIT: type_str = "8-bit"; break; + case QR_DATA_KANJI: type_str = "kanji"; break; + case QR_DATA_MIXED: type_str = "mixed"; break; + case QR_DATA_FNC1: type_str = "FNC1"; break; + default: type_str = "(unknown)"; break; + } + fprintf(stderr, "Data type: %s; %lu bytes\nContent: %s\n", type_str, data_len, data_str); + free(data_str); + qr_free_data(data); + } + + return 0; +} + diff --git a/lpg/libqr/testqr.xbm b/lpg/libqr/testqr.xbm new file mode 100644 index 0000000..ca2966f --- /dev/null +++ b/lpg/libqr/testqr.xbm @@ -0,0 +1,19 @@ +#define testqr_width 37 +#define testqr_height 37 +static unsigned char testqr_bits[] = { + 0x7F, 0x63, 0xFB, 0xDA, 0x1F, 0x41, 0xD7, 0xAD, 0x55, 0x10, 0x5D, 0x3D, + 0xE9, 0x5E, 0x17, 0x5D, 0xC6, 0xB5, 0x43, 0x17, 0x5D, 0x41, 0x61, 0x52, + 0x17, 0x41, 0x76, 0xC9, 0x46, 0x10, 0x7F, 0x55, 0x55, 0xD5, 0x1F, 0x00, + 0x98, 0x47, 0x05, 0x00, 0xF9, 0x99, 0xE0, 0x36, 0x1D, 0x24, 0x01, 0x07, + 0xC7, 0x0A, 0x60, 0xBC, 0xB9, 0x44, 0x16, 0x81, 0x21, 0x9D, 0x8D, 0x1B, + 0xCF, 0x8E, 0x83, 0x51, 0x16, 0xA2, 0x1B, 0xFD, 0x3A, 0x1B, 0xEB, 0x3B, + 0x1D, 0x5B, 0x17, 0xA9, 0xF6, 0x70, 0xF8, 0x1F, 0xC1, 0x68, 0x66, 0xFD, + 0x1D, 0xB3, 0x07, 0xC2, 0x54, 0x04, 0xD8, 0x0C, 0x4F, 0x4D, 0x15, 0x11, + 0xA1, 0x99, 0xA2, 0x11, 0x60, 0x65, 0xCC, 0x49, 0x05, 0x1D, 0x1F, 0xC3, + 0x8E, 0x15, 0x64, 0xED, 0xB9, 0x9A, 0x02, 0x90, 0x03, 0x1D, 0xAA, 0x0D, + 0x45, 0xD8, 0x72, 0x92, 0x01, 0x83, 0x53, 0x6E, 0x55, 0x06, 0xC7, 0xC4, + 0x02, 0xB4, 0x1B, 0x19, 0x24, 0x0F, 0x8D, 0x12, 0xE5, 0xAA, 0xAA, 0xF3, + 0x03, 0x00, 0x5F, 0x66, 0x11, 0x11, 0x7F, 0x73, 0x8F, 0x57, 0x1B, 0x41, + 0x8D, 0x39, 0x1B, 0x19, 0x5D, 0x3B, 0x3D, 0xFB, 0x13, 0x5D, 0x03, 0x70, + 0x62, 0x1C, 0x5D, 0x6A, 0x46, 0x37, 0x19, 0x41, 0xDA, 0x62, 0xF8, 0x1D, + 0x7F, 0x7B, 0x3E, 0x58, 0x14, }; -- cgit v1.2.3-70-g09d2 From 3af4ffd175dcaf8aaf735f3f9564da54c4f29403 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Thu, 14 Jul 2011 11:36:58 +0900 Subject: Create common header --- lpg/libqr/code-create.c | 1 + lpg/libqr/code-layout.c | 1 + lpg/libqr/code-parse.c | 2 +- lpg/libqr/constants.h | 2 +- lpg/libqr/qr/code.h | 7 ------- lpg/libqr/qr/common.h | 14 ++++++++++++++ lpg/libqr/qr/data.h | 18 ------------------ lpg/libqr/qr/types.h | 18 ++++++++++++++++++ 8 files changed, 36 insertions(+), 27 deletions(-) create mode 100644 lpg/libqr/qr/common.h diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 155ffa3..1da7845 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -5,6 +5,7 @@ #include #include #include +#include #include #include #include "constants.h" diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 04b6ca6..97cf3af 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -5,6 +5,7 @@ #include #include +#include #include #include "constants.h" diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index 50d621c..f84dcfe 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -7,7 +7,7 @@ #include #include #include -#include +#include #include #include diff --git a/lpg/libqr/constants.h b/lpg/libqr/constants.h index 2c19e97..5ae9256 100644 --- a/lpg/libqr/constants.h +++ b/lpg/libqr/constants.h @@ -1,7 +1,7 @@ #ifndef QR_CONSTANTS_H #define QR_CONSTANTS_H -#include +#include extern const int QR_ALIGNMENT_LOCATION[40][7]; extern const int QR_DATA_WORD_COUNT[40][4]; diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h index 2392467..e6eb47c 100644 --- a/lpg/libqr/qr/code.h +++ b/lpg/libqr/qr/code.h @@ -13,12 +13,5 @@ struct qr_code * qr_code_create(const struct qr_data * data); void qr_code_destroy(struct qr_code *); -int qr_code_width(const struct qr_code *); - -size_t qr_code_total_capacity(int version); - -struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, - unsigned int mask); - #endif diff --git a/lpg/libqr/qr/common.h b/lpg/libqr/qr/common.h new file mode 100644 index 0000000..9caf3e0 --- /dev/null +++ b/lpg/libqr/qr/common.h @@ -0,0 +1,14 @@ +#ifndef QR_COMMON_H +#define QR_COMMON_H + +#include + +struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, + unsigned int mask); + +size_t qr_code_total_capacity(int version); + +int qr_code_width(const struct qr_code *); + +#endif + diff --git a/lpg/libqr/qr/data.h b/lpg/libqr/qr/data.h index a3bb309..3cc665a 100644 --- a/lpg/libqr/qr/data.h +++ b/lpg/libqr/qr/data.h @@ -4,24 +4,6 @@ #include #include "types.h" -enum qr_data_type { - QR_DATA_INVALID = -1, - QR_DATA_ECI = 7, - QR_DATA_NUMERIC = 1, - QR_DATA_ALPHA = 2, - QR_DATA_8BIT = 4, - QR_DATA_KANJI = 8, /* JIS X 0208 */ - QR_DATA_MIXED = 3, - QR_DATA_FNC1 = 9 -}; - -enum qr_ec_level { - QR_EC_LEVEL_L = 0x1, - QR_EC_LEVEL_M = 0x0, - QR_EC_LEVEL_Q = 0x3, - QR_EC_LEVEL_H = 0x2 -}; - struct qr_data { int version; /* 1 ~ 40 */ enum qr_ec_level ec; diff --git a/lpg/libqr/qr/types.h b/lpg/libqr/qr/types.h index bb44cde..3615e3e 100644 --- a/lpg/libqr/qr/types.h +++ b/lpg/libqr/qr/types.h @@ -4,5 +4,23 @@ struct qr_data; struct qr_code; +enum qr_data_type { + QR_DATA_INVALID = -1, + QR_DATA_ECI = 7, + QR_DATA_NUMERIC = 1, + QR_DATA_ALPHA = 2, + QR_DATA_8BIT = 4, + QR_DATA_KANJI = 8, /* JIS X 0208 */ + QR_DATA_MIXED = 3, + QR_DATA_FNC1 = 9 +}; + +enum qr_ec_level { + QR_EC_LEVEL_L = 0x1, + QR_EC_LEVEL_M = 0x0, + QR_EC_LEVEL_Q = 0x3, + QR_EC_LEVEL_H = 0x2 +}; + #endif -- cgit v1.2.3-70-g09d2 From 9f4843d686bca0d75bee174d8249fbf72527b94a Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Thu, 14 Jul 2011 14:31:07 +0900 Subject: Move RS block size calculation to a separate function --- lpg/libqr/code-common.c | 35 ++++++++++++++++++++++++++++++++++- lpg/libqr/code-create.c | 37 +++++++++++++++++++------------------ lpg/libqr/code-parse.c | 33 +++++++++++---------------------- lpg/libqr/constants.h | 2 +- lpg/libqr/qr/common.h | 11 +++++++++++ 5 files changed, 76 insertions(+), 42 deletions(-) diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index a0b8fcc..422f2ac 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -2,9 +2,11 @@ #include #include -#include #include #include +#include +#include +#include "constants.h" void qr_code_destroy(struct qr_code * code) { @@ -41,6 +43,37 @@ size_t qr_code_total_capacity(int version) return side * side - function_bits; } +void qr_get_rs_block_sizes(int version, + enum qr_ec_level ec, + int block_count[2], + int data_length[2], + int ec_length[2]) +{ + /* FIXME: rather than using a big static table, better to + * calculate these values. + */ + int total_words = qr_code_total_capacity(version) / 8; + int data_words = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]; + int ec_words = total_words - data_words; + int total_blocks; + + block_count[0] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][0]; + block_count[1] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][1]; + total_blocks = block_count[0] + block_count[1]; + + data_length[0] = data_words / total_blocks; + data_length[1] = data_length[0] + 1; + + assert(data_length[0] * block_count[0] + + data_length[1] * block_count[1] == data_words); + + ec_length[0] = ec_length[1] = ec_words / total_blocks; + + assert(ec_length[0] * block_count[0] + + ec_length[1] * block_count[1] == ec_words); + assert(data_words + ec_words == total_words); +} + struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, unsigned int mask) { diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 1da7845..680b405 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -172,7 +172,8 @@ static struct qr_bitstream * make_data(int version, const size_t total_bits = qr_code_total_capacity(version); const size_t total_words = total_bits / 8; const size_t total_data = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]; - size_t total_blocks, block_count[2], data_words, rs_words; + int block_count[2], data_length[2], ec_length[2]; + int total_blocks; size_t i, w; struct qr_bitstream * dcopy = 0; struct qr_bitstream * out = 0; @@ -186,14 +187,8 @@ static struct qr_bitstream * make_data(int version, if (qr_bitstream_resize(out, total_bits) != 0) goto fail; - /* XXX: 14-M will be incorrect */ - block_count[0] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][0]; - block_count[1] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][1]; + qr_get_rs_block_sizes(version, ec, block_count, data_length, ec_length); total_blocks = block_count[0] + block_count[1]; - data_words = total_data / total_blocks; - rs_words = total_words / total_blocks - data_words; - assert((data_words + rs_words) * block_count[0] + - (data_words + rs_words + 1) * block_count[1] == total_words); /* Make a copy of the data and pad it */ dcopy = qr_bitstream_dup(data); @@ -207,17 +202,20 @@ static struct qr_bitstream * make_data(int version, x_dump(dcopy); /* Make space for the RS blocks */ - blocks = calloc(total_blocks, sizeof(*blocks)); + blocks = malloc(total_blocks * sizeof(*blocks)); if (!blocks) goto fail; + for (i = 0; i < total_blocks; ++i) + blocks[i] = NULL; /* Generate RS codewords */ qr_bitstream_seek(dcopy, 0); fputs("Generate RS blocks:\n", stderr); for (i = 0; i < total_blocks; ++i) { - size_t dw = data_words + (i >= block_count[0]); - - blocks[i] = rs_generate_words(dcopy, dw, rs_words); + int type = (i >= block_count[0]); + blocks[i] = rs_generate_words(dcopy, + data_length[type], + ec_length[type]); if (!blocks[i]) { while (i--) qr_bitstream_destroy(blocks[i]); @@ -229,11 +227,13 @@ static struct qr_bitstream * make_data(int version, } /* Finally, write everything out in the correct order */ - for (w = 0; w < data_words + 1; ++w) { - for (i = (w == data_words ? block_count[0] : 0); i < total_blocks; ++i) { - size_t di = w + (i < block_count[0] ? - i * data_words : - i * (data_words + 1) - block_count[0]); + assert(block_count[1] == 0 || data_length[1] >= data_length[0]); + for (w = 0; w < data_length[block_count[1] ? 1 : 0]; ++w) { + for (i = (w >= data_length[0] ? block_count[0] : 0); i < total_blocks; ++i) { + long di = w + i * data_length[0] + + (i > block_count[0] ? + (i - block_count[0]) * (data_length[1] - data_length[0]) + : 0); qr_bitstream_seek(dcopy, di * 8); qr_bitstream_write(out, @@ -242,7 +242,8 @@ static struct qr_bitstream * make_data(int version, } for (i = 0; i < total_blocks; ++i) qr_bitstream_seek(blocks[i], 0); - for (w = 0; w < rs_words; ++w) + assert(block_count[1] == 0 || ec_length[1] == ec_length[0]); + for (w = 0; w < ec_length[0]; ++w) for (i = 0; i < total_blocks; ++i) qr_bitstream_write(out, qr_bitstream_read(blocks[i], 8), 8); diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index f84dcfe..29d96bb 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -31,24 +31,19 @@ static int unpack_bits(int version, /* FIXME: less math here (get the values from a common helper fn) */ /* FIXME: more comments to explain the algorithm */ - const size_t total_bits = qr_code_total_capacity(version); - const size_t total_words = total_bits / 8; - const size_t total_data = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]; - int total_blocks, block_count[2], row_length[2], data_words, rs_words; + int total_words = qr_code_total_capacity(version) / 8; + int block_count[2], data_length[2], ec_length[2]; + int total_blocks; int i, w, block; struct qr_bitstream ** blocks = 0; - /* copied from make_data */ - block_count[0] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][0]; - block_count[1] = QR_RS_BLOCK_COUNT[version - 1][ec ^ 0x1][1]; + qr_get_rs_block_sizes(version, ec, block_count, data_length, ec_length); total_blocks = block_count[0] + block_count[1]; - data_words = total_data / total_blocks; - rs_words = total_words / total_blocks - data_words; - assert((data_words + rs_words) * block_count[0] + - (data_words + rs_words + 1) * block_count[1] == total_words); - blocks = calloc(total_blocks, sizeof(*blocks)); + blocks = malloc(total_blocks * sizeof(*blocks)); /* XXX: check return (and below) */ + for (i = 0; i < total_blocks; ++i) + blocks[i] = NULL; for (i = 0; i < total_blocks; ++i) blocks[i] = qr_bitstream_create(); @@ -57,16 +52,12 @@ static int unpack_bits(int version, qr_bitstream_seek(raw_bits, 0); - /* XXX: 14-M will be incorrect */ - row_length[0] = data_words; - row_length[1] = block_count[1] > 0 ? (total_data - row_length[0] * block_count[0]) / block_count[1] : 0; - fprintf(stderr, "block counts %d and %d\n", block_count[0], block_count[1]); - fprintf(stderr, "row lengths %d and %d\n", row_length[0], row_length[1]); + fprintf(stderr, "row lengths %d and %d\n", data_length[0], data_length[1]); block = 0; for (w = 0; w < total_words; ++w) { - if (block == 0 && w / total_blocks == row_length[0] && block_count[1] != 0) { + if (block == 0 && w / total_blocks >= data_length[0] && block_count[1] != 0) { /* Skip the short blocks, if there are any */ block += block_count[0]; } @@ -77,12 +68,10 @@ static int unpack_bits(int version, /* XXX: apply ec */ for (block = 0; block < total_blocks; ++block) { + int type = (block >= block_count[0]); struct qr_bitstream * stream = blocks[block]; qr_bitstream_seek(stream, 0); - for (w = 0; w < row_length[block >= block_count[0]]; ++w) - qr_bitstream_write(bits_out, - qr_bitstream_read(stream, 8), - 8); + qr_bitstream_copy(bits_out, stream, data_length[type] * 8); qr_bitstream_destroy(stream); } free(blocks); diff --git a/lpg/libqr/constants.h b/lpg/libqr/constants.h index 5ae9256..fbfadc8 100644 --- a/lpg/libqr/constants.h +++ b/lpg/libqr/constants.h @@ -5,7 +5,7 @@ extern const int QR_ALIGNMENT_LOCATION[40][7]; extern const int QR_DATA_WORD_COUNT[40][4]; -/* See spec table 18 (also table 19 for application) */ +/* See qr_get_rs_block_sizes() */ extern const int QR_RS_BLOCK_COUNT[40][4][2]; extern const enum qr_data_type QR_TYPE_CODES[16]; diff --git a/lpg/libqr/qr/common.h b/lpg/libqr/qr/common.h index 9caf3e0..f2bd127 100644 --- a/lpg/libqr/qr/common.h +++ b/lpg/libqr/qr/common.h @@ -10,5 +10,16 @@ size_t qr_code_total_capacity(int version); int qr_code_width(const struct qr_code *); +/* See table 19 of the spec for the layout of EC data. There are at + * most two different block lengths, so the total number of data+ec + * blocks is the sum of block_count[]. The total number of 8-bit + * words in each kind of block is data_length + ec_length. + */ +void qr_get_rs_block_sizes(int version, + enum qr_ec_level ec, + int block_count[2], + int data_length[2], + int ec_length[2]); + #endif -- cgit v1.2.3-70-g09d2 From 4670274ec303082e0fb86ff3be1ea4170a17662f Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Fri, 15 Jul 2011 14:20:41 +0900 Subject: qr_mask_apply() works in-place --- lpg/libqr/code-common.c | 14 +++----------- lpg/libqr/code-create.c | 3 ++- lpg/libqr/code-parse.c | 8 +++----- lpg/libqr/qr/common.h | 3 +-- 4 files changed, 9 insertions(+), 19 deletions(-) diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index 422f2ac..1cb1745 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -74,18 +74,12 @@ void qr_get_rs_block_sizes(int version, assert(data_words + ec_words == total_words); } -struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, - unsigned int mask) +void qr_mask_apply(struct qr_bitmap * bmp, int mask) { - struct qr_bitmap * bmp; int i, j; - if (mask > 7) - return 0; - - bmp = qr_bitmap_clone(orig); - if (!bmp) - return 0; + assert((mask & 0x7) == mask); + mask &= 0x7; /* Slow version for now; we can optimize later */ @@ -111,7 +105,5 @@ struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, p[off] ^= (t == 0) << bit; } } - - return bmp; } diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index 680b405..f29778f 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -332,11 +332,12 @@ static int mask_data(struct qr_code * code) /* Generate bitmap for each mask and evaluate */ for (i = 0; i < 8; ++i) { - test = qr_mask_apply(code->modules, i); + test = qr_bitmap_clone(code->modules); if (!test) { qr_bitmap_destroy(mask); return -1; } + qr_mask_apply(test, i); score = score_mask(test); fprintf(stderr, "mask %d scored %d\n", i, score); if (!mask || score < best) { diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index 29d96bb..7a98280 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -212,11 +212,9 @@ int qr_code_parse(const void * buffer, fprintf(stderr, "detected ec type %d; mask %d\n", ec, mask); - code.modules = qr_mask_apply(&src_bmp, mask); - if (code.modules == NULL) { - fprintf(stderr, "failed to apply mask\n"); - return -1; - } + code.modules = qr_bitmap_clone(&src_bmp); + /* XXX: check return */ + qr_mask_apply(code.modules, mask); qr_layout_init_mask(&code); diff --git a/lpg/libqr/qr/common.h b/lpg/libqr/qr/common.h index f2bd127..640696a 100644 --- a/lpg/libqr/qr/common.h +++ b/lpg/libqr/qr/common.h @@ -3,8 +3,7 @@ #include -struct qr_bitmap * qr_mask_apply(const struct qr_bitmap * orig, - unsigned int mask); +void qr_mask_apply(struct qr_bitmap * bmp, int mask); size_t qr_code_total_capacity(int version); -- cgit v1.2.3-70-g09d2 From a5c8627f3152e9604bb65fef2e71015a66c82421 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Fri, 15 Jul 2011 14:47:28 +0900 Subject: Check return values in code-parse.c --- lpg/libqr/code-parse.c | 95 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 71 insertions(+), 24 deletions(-) diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index 7a98280..690734b 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -28,7 +28,6 @@ static int unpack_bits(int version, struct qr_bitstream * raw_bits, struct qr_bitstream * bits_out) { - /* FIXME: less math here (get the values from a common helper fn) */ /* FIXME: more comments to explain the algorithm */ int total_words = qr_code_total_capacity(version) / 8; @@ -36,17 +35,35 @@ static int unpack_bits(int version, int total_blocks; int i, w, block; struct qr_bitstream ** blocks = 0; + int status = -1; qr_get_rs_block_sizes(version, ec, block_count, data_length, ec_length); total_blocks = block_count[0] + block_count[1]; + status = qr_bitstream_resize(bits_out, + (block_count[0] * data_length[0] + + block_count[1] * data_length[1]) * 8); + if (status != 0) + goto cleanup; + blocks = malloc(total_blocks * sizeof(*blocks)); - /* XXX: check return (and below) */ + if (blocks == NULL) + goto cleanup; + for (i = 0; i < total_blocks; ++i) blocks[i] = NULL; - for (i = 0; i < total_blocks; ++i) + /* Allocate temporary space for the blocks */ + for (i = 0; i < total_blocks; ++i) { + int type = (i >= block_count[0]); blocks[i] = qr_bitstream_create(); + if (blocks[i] == NULL) + goto cleanup; + status = qr_bitstream_resize(blocks[i], + (data_length[type] + ec_length[type]) * 8); + if (status != 0) + goto cleanup; + } /* Read in the data & EC (see spec table 19) */ @@ -72,11 +89,18 @@ static int unpack_bits(int version, struct qr_bitstream * stream = blocks[block]; qr_bitstream_seek(stream, 0); qr_bitstream_copy(bits_out, stream, data_length[type] * 8); - qr_bitstream_destroy(stream); } - free(blocks); + status = 0; + +cleanup: + if (blocks != NULL) { + for (block = 0; block < total_blocks; ++block) + if (blocks[block] != NULL) + qr_bitstream_destroy(blocks[block]); + free(blocks); + } - return 0; + return status; } static int read_bits(const struct qr_code * code, @@ -88,16 +112,28 @@ static int read_bits(const struct qr_code * code, struct qr_bitstream * raw_bits; struct qr_iterator * layout; int w; - int ret; + int ret = -1; raw_bits = qr_bitstream_create(); + if (raw_bits == NULL) + goto cleanup; + + ret = qr_bitstream_resize(raw_bits, total_words * 8); + if (ret != 0) + goto cleanup; + layout = qr_layout_begin((struct qr_code *) code); /* dropping const! */ + if (layout == NULL) + goto cleanup; for (w = 0; w < total_words; ++w) qr_bitstream_write(raw_bits, qr_layout_read(layout), 8); qr_layout_end(layout); ret = unpack_bits(code->version, ec, raw_bits, data_bits); - qr_bitstream_destroy(raw_bits); + +cleanup: + if (raw_bits != NULL) + qr_bitstream_destroy(raw_bits); return ret; } @@ -175,11 +211,13 @@ int qr_code_parse(const void * buffer, size_t line_count, struct qr_data ** data) { + /* TODO: more informative return values for errors */ struct qr_bitmap src_bmp; struct qr_code code; enum qr_ec_level ec; int mask; struct qr_bitstream * data_bits; + int status; fprintf(stderr, "parsing code bitmap %lux%lu\n", line_bits, line_count); @@ -213,36 +251,45 @@ int qr_code_parse(const void * buffer, fprintf(stderr, "detected ec type %d; mask %d\n", ec, mask); code.modules = qr_bitmap_clone(&src_bmp); - /* XXX: check return */ + if (code.modules == NULL) { + status = -1; + goto cleanup; + } qr_mask_apply(code.modules, mask); qr_layout_init_mask(&code); data_bits = qr_bitstream_create(); - /* XXX: check return */ - - read_bits(&code, ec, data_bits); - /* XXX: check return */ - - /* - { - fprintf(stderr, "decoding failed\n"); - qr_bitmap_destroy(code.modules); - qr_bitstream_destroy(bits); - *data = NULL; - return -1; + if (data_bits == NULL) { + status = -1; + goto cleanup; } - */ + + status = read_bits(&code, ec, data_bits); + if (status != 0) + goto cleanup; *data = malloc(sizeof(*data)); - /* XXX: check return */ + if (*data == NULL) { + status = -1; + goto cleanup; + } (*data)->version = code.version; (*data)->ec = ec; (*data)->bits = data_bits; (*data)->offset = 0; - return 0; + data_bits = 0; + status = 0; + +cleanup: + if (data_bits) + qr_bitstream_destroy(data_bits); + if (code.modules) + qr_bitmap_destroy(code.modules); + + return status; } int qr_decode_format(unsigned bits, enum qr_ec_level * ec, int * mask) -- cgit v1.2.3-70-g09d2 From f7133a8a56650a2e5cefc66b6d9b87809a890b2e Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Fri, 15 Jul 2011 14:57:03 +0900 Subject: Remove (a few) magic numbers --- lpg/libqr/code-create.c | 33 +++++++++++++-------------------- lpg/libqr/code-layout.c | 4 ++-- lpg/libqr/code-parse.c | 20 ++++++++++---------- lpg/libqr/constants.h | 16 ++++++++++++++++ 4 files changed, 41 insertions(+), 32 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index f29778f..d00a41f 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -170,7 +170,6 @@ static struct qr_bitstream * make_data(int version, struct qr_bitstream * data) { const size_t total_bits = qr_code_total_capacity(version); - const size_t total_words = total_bits / 8; const size_t total_data = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]; int block_count[2], data_length[2], ec_length[2]; int total_blocks; @@ -195,7 +194,7 @@ static struct qr_bitstream * make_data(int version, if (!dcopy) goto fail; - if (pad_data(dcopy, total_data * 8) != 0) + if (pad_data(dcopy, total_data * QR_WORD_BITS) != 0) goto fail; fputs("Pad data:\n", stderr); @@ -235,9 +234,8 @@ static struct qr_bitstream * make_data(int version, (i - block_count[0]) * (data_length[1] - data_length[0]) : 0); - qr_bitstream_seek(dcopy, di * 8); - qr_bitstream_write(out, - qr_bitstream_read(dcopy, 8), 8); + qr_bitstream_seek(dcopy, di * QR_WORD_BITS); + qr_bitstream_copy(out, dcopy, QR_WORD_BITS); } } for (i = 0; i < total_blocks; ++i) @@ -245,10 +243,9 @@ static struct qr_bitstream * make_data(int version, assert(block_count[1] == 0 || ec_length[1] == ec_length[0]); for (w = 0; w < ec_length[0]; ++w) for (i = 0; i < total_blocks; ++i) - qr_bitstream_write(out, - qr_bitstream_read(blocks[i], 8), 8); + qr_bitstream_copy(out, blocks[i], QR_WORD_BITS); - qr_bitstream_write(out, 0, total_bits - total_words * 8); + qr_bitstream_write(out, 0, total_bits % QR_WORD_BITS); fputs("Final bitstream:\n", stderr); x_dump(out); @@ -299,8 +296,8 @@ struct qr_code * qr_code_create(const struct qr_data * data) goto fail; qr_bitstream_seek(bits, 0); - while (qr_bitstream_remaining(bits) >= 8) - qr_layout_write(layout, qr_bitstream_read(bits, 8)); + while (qr_bitstream_remaining(bits) >= QR_WORD_BITS) + qr_layout_write(layout, qr_bitstream_read(bits, QR_WORD_BITS)); qr_layout_end(layout); mask = mask_data(code); @@ -566,15 +563,12 @@ static int calc_format_bits(enum qr_ec_level ec, int mask) bits = (ec & 0x3) << 3 | (mask & 0x7); - /* Compute (15, 5) BCH code with - * G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1 - */ + /* Compute (15, 5) BCH code */ bits <<= 15 - 5; - bits |= (unsigned int)gf_residue(bits, 0x537); + bits |= (unsigned int)gf_residue(bits, QR_FORMAT_POLY); - /* XOR mask: 101 0100 0001 0010 */ - bits ^= 0x5412; + bits ^= QR_FORMAT_MASK; return bits; } @@ -585,11 +579,10 @@ static long calc_version_bits(int version) bits = version & 0x3F; - /* (18, 6) BCH code - * G(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 - */ + /* (18, 6) BCH code */ + bits <<= 18 - 6; - bits |= gf_residue(bits, 0x1F25); + bits |= gf_residue(bits, QR_VERSION_POLY); fprintf(stderr, "version bits: %lx\n", bits); return bits; diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 97cf3af..8b4522d 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -167,7 +167,7 @@ unsigned int qr_layout_read(struct qr_iterator * i) unsigned int x = 0; int b; - for (b = 0; b < 8; ++b) { + for (b = 0; b < QR_WORD_BITS; ++b) { x = (x << 1) | ((*i->p & i->mask) ? 1 : 0); advance(i); } @@ -179,7 +179,7 @@ void qr_layout_write(struct qr_iterator * i, unsigned int x) { int b; - for (b = 0; b < 8; ++b) { + for (b = 0; b < QR_WORD_BITS; ++b) { *i->p |= (x & 0x80) ? i->mask : 0; advance(i); x <<= 1; diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index 690734b..8e36a15 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -30,7 +30,7 @@ static int unpack_bits(int version, { /* FIXME: more comments to explain the algorithm */ - int total_words = qr_code_total_capacity(version) / 8; + int total_words = qr_code_total_capacity(version) / QR_WORD_BITS; int block_count[2], data_length[2], ec_length[2]; int total_blocks; int i, w, block; @@ -42,7 +42,7 @@ static int unpack_bits(int version, status = qr_bitstream_resize(bits_out, (block_count[0] * data_length[0] + - block_count[1] * data_length[1]) * 8); + block_count[1] * data_length[1]) * QR_WORD_BITS); if (status != 0) goto cleanup; @@ -60,7 +60,7 @@ static int unpack_bits(int version, if (blocks[i] == NULL) goto cleanup; status = qr_bitstream_resize(blocks[i], - (data_length[type] + ec_length[type]) * 8); + (data_length[type] + ec_length[type]) * QR_WORD_BITS); if (status != 0) goto cleanup; } @@ -78,7 +78,7 @@ static int unpack_bits(int version, /* Skip the short blocks, if there are any */ block += block_count[0]; } - qr_bitstream_write(blocks[block], qr_bitstream_read(raw_bits, 8), 8); + qr_bitstream_copy(blocks[block], raw_bits, QR_WORD_BITS); block = (block + 1) % total_blocks; } @@ -88,7 +88,7 @@ static int unpack_bits(int version, int type = (block >= block_count[0]); struct qr_bitstream * stream = blocks[block]; qr_bitstream_seek(stream, 0); - qr_bitstream_copy(bits_out, stream, data_length[type] * 8); + qr_bitstream_copy(bits_out, stream, data_length[type] * QR_WORD_BITS); } status = 0; @@ -108,7 +108,7 @@ static int read_bits(const struct qr_code * code, struct qr_bitstream * data_bits) { const size_t total_bits = qr_code_total_capacity(code->version); - const size_t total_words = total_bits / 8; + const size_t total_words = total_bits / QR_WORD_BITS; struct qr_bitstream * raw_bits; struct qr_iterator * layout; int w; @@ -118,7 +118,7 @@ static int read_bits(const struct qr_code * code, if (raw_bits == NULL) goto cleanup; - ret = qr_bitstream_resize(raw_bits, total_words * 8); + ret = qr_bitstream_resize(raw_bits, total_words * QR_WORD_BITS); if (ret != 0) goto cleanup; @@ -126,7 +126,7 @@ static int read_bits(const struct qr_code * code, if (layout == NULL) goto cleanup; for (w = 0; w < total_words; ++w) - qr_bitstream_write(raw_bits, qr_layout_read(layout), 8); + qr_bitstream_write(raw_bits, qr_layout_read(layout), QR_WORD_BITS); qr_layout_end(layout); ret = unpack_bits(code->version, ec, raw_bits, data_bits); @@ -294,7 +294,7 @@ cleanup: int qr_decode_format(unsigned bits, enum qr_ec_level * ec, int * mask) { - bits ^= 0x5412; + bits ^= QR_FORMAT_MASK; /* TODO: check and fix errors */ @@ -321,7 +321,7 @@ int qr_decode_version(unsigned long bits, int * version) /* see calc_version_bits() */ version_bits = v; version_bits <<= 12; - version_bits |= gf_residue(version_bits, 0x1F25); + version_bits |= gf_residue(version_bits, QR_VERSION_POLY); /* count errors */ errors = 0; diff --git a/lpg/libqr/constants.h b/lpg/libqr/constants.h index fbfadc8..e6cfa3c 100644 --- a/lpg/libqr/constants.h +++ b/lpg/libqr/constants.h @@ -3,6 +3,22 @@ #include +/* XOR mask for format data: 101 0100 0001 0010 */ +#define QR_FORMAT_MASK (0x5412) + +/* Format info EC polynomial + * G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1 + */ +#define QR_FORMAT_POLY (0x537) + +/* Version info EC polynomial + * G(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 + */ +#define QR_VERSION_POLY (0x1F25) + +/* A QR-code word is always 8 bits, but CHAR_BIT might not be */ +#define QR_WORD_BITS (8) + extern const int QR_ALIGNMENT_LOCATION[40][7]; extern const int QR_DATA_WORD_COUNT[40][4]; /* See qr_get_rs_block_sizes() */ -- cgit v1.2.3-70-g09d2 From bea5cbf43b7074fe59c400edaa294153d18fb325 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Fri, 15 Jul 2011 15:12:53 +0900 Subject: Fix incorrect allocation size --- lpg/libqr/code-parse.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index 8e36a15..d4a2538 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -269,7 +269,7 @@ int qr_code_parse(const void * buffer, if (status != 0) goto cleanup; - *data = malloc(sizeof(*data)); + *data = malloc(sizeof(**data)); if (*data == NULL) { status = -1; goto cleanup; -- cgit v1.2.3-70-g09d2 From 27e4017efca48bf053c8e0e6bb083898e7f9833b Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Fri, 15 Jul 2011 15:26:11 +0900 Subject: Add version.h --- lpg/libqr/qr/version.h | 10 ++++++++++ lpg/libqr/qrgen.c | 3 ++- 2 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 lpg/libqr/qr/version.h diff --git a/lpg/libqr/qr/version.h b/lpg/libqr/qr/version.h new file mode 100644 index 0000000..cd263c0 --- /dev/null +++ b/lpg/libqr/qr/version.h @@ -0,0 +1,10 @@ +#ifndef QR_VERSION_H +#define QR_VERSION_H + +#define QR_VERSION_MAJOR 0 +#define QR_VERSION_MINOR 3 + +#define QR_VERSION "0.3" + +#endif + diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index b95db0a..6098231 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -10,6 +10,7 @@ #include #include #include +#include struct config { int version; @@ -223,7 +224,7 @@ int main(int argc, char ** argv) { if (conf.ansi) output_ansi(code->modules); else - output_pbm(code->modules, "qrgen v0.1"); + output_pbm(code->modules, "libqr v" QR_VERSION); qr_code_destroy(code); -- cgit v1.2.3-70-g09d2 From fed32fca55210ce26e103a7f941a71694945311c Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Fri, 15 Jul 2011 15:26:27 +0900 Subject: Update gitignore --- lpg/libqr/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/lpg/libqr/.gitignore b/lpg/libqr/.gitignore index 41c2dbc..33bcf18 100644 --- a/lpg/libqr/.gitignore +++ b/lpg/libqr/.gitignore @@ -3,3 +3,4 @@ *.a *.so qrgen +qrparse -- cgit v1.2.3-70-g09d2 From a3234f7d7e36ad7d1bad6a85b868b05addf40e9b Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Sun, 17 Jul 2011 09:45:26 +0900 Subject: Tweak some types --- lpg/libqr/code-create.c | 13 ++++++------- lpg/libqr/constants.h | 8 ++++---- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index d00a41f..cf04eb7 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -25,8 +25,8 @@ static int draw_format(struct qr_bitmap * bmp, struct qr_code * code, enum qr_ec_level ec, int mask); -static int calc_format_bits(enum qr_ec_level ec, int mask); -static long calc_version_bits(int version); +static unsigned int calc_format_bits(enum qr_ec_level ec, int mask); +static unsigned long calc_version_bits(int version); #include static void x_dump(struct qr_bitstream * bits) @@ -557,9 +557,9 @@ static int draw_format(struct qr_bitmap * bmp, return 0; } -static int calc_format_bits(enum qr_ec_level ec, int mask) +static unsigned int calc_format_bits(enum qr_ec_level ec, int mask) { - int bits; + unsigned int bits; bits = (ec & 0x3) << 3 | (mask & 0x7); @@ -573,9 +573,9 @@ static int calc_format_bits(enum qr_ec_level ec, int mask) return bits; } -static long calc_version_bits(int version) +static unsigned long calc_version_bits(int version) { - long bits; + unsigned long bits; bits = version & 0x3F; @@ -584,7 +584,6 @@ static long calc_version_bits(int version) bits <<= 18 - 6; bits |= gf_residue(bits, QR_VERSION_POLY); -fprintf(stderr, "version bits: %lx\n", bits); return bits; } diff --git a/lpg/libqr/constants.h b/lpg/libqr/constants.h index e6cfa3c..c13ae5a 100644 --- a/lpg/libqr/constants.h +++ b/lpg/libqr/constants.h @@ -4,20 +4,20 @@ #include /* XOR mask for format data: 101 0100 0001 0010 */ -#define QR_FORMAT_MASK (0x5412) +static const unsigned int QR_FORMAT_MASK = 0x5412; /* Format info EC polynomial * G(x) = x^10 + x^8 + x^5 + x^4 + x^2 + x + 1 */ -#define QR_FORMAT_POLY (0x537) +static const unsigned int QR_FORMAT_POLY = 0x537; /* Version info EC polynomial * G(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 */ -#define QR_VERSION_POLY (0x1F25) +static const unsigned int QR_VERSION_POLY = 0x1F25; /* A QR-code word is always 8 bits, but CHAR_BIT might not be */ -#define QR_WORD_BITS (8) +static const unsigned int QR_WORD_BITS = 8; extern const int QR_ALIGNMENT_LOCATION[40][7]; extern const int QR_DATA_WORD_COUNT[40][4]; -- cgit v1.2.3-70-g09d2 From d4abb878df167875bb66d1e0debe853cb6b88b1b Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Tue, 19 Jul 2011 12:04:15 +0900 Subject: Fix some types --- lpg/libqr/bitmap.c | 6 +++--- lpg/libqr/bitstream.c | 14 +++++++------- lpg/libqr/code-common.c | 2 +- lpg/libqr/code-create.c | 16 +++++++++------- lpg/libqr/code-layout.c | 6 +++--- lpg/libqr/code-parse.c | 4 ++-- lpg/libqr/constants.h | 2 +- lpg/libqr/data-create.c | 2 +- lpg/libqr/galois.c | 2 +- lpg/libqr/qr/bitmap.h | 6 +++--- lpg/libqr/qr/bitstream.h | 10 +++++----- lpg/libqr/qr/parse.h | 2 +- lpg/libqr/qrgen.c | 2 +- 13 files changed, 38 insertions(+), 36 deletions(-) diff --git a/lpg/libqr/bitmap.c b/lpg/libqr/bitmap.c index 759aeca..b9d3763 100644 --- a/lpg/libqr/bitmap.c +++ b/lpg/libqr/bitmap.c @@ -5,7 +5,7 @@ #include -struct qr_bitmap * qr_bitmap_create(int width, int height, int masked) +struct qr_bitmap * qr_bitmap_create(size_t width, size_t height, int masked) { struct qr_bitmap * out; size_t size; @@ -169,9 +169,9 @@ static void render_line_2(unsigned char * out, void qr_bitmap_render(const struct qr_bitmap * bmp, void * buffer, - size_t mod_bits, + int mod_bits, size_t line_stride, - size_t line_repeat, + int line_repeat, unsigned long mark, unsigned long space) { diff --git a/lpg/libqr/bitstream.c b/lpg/libqr/bitstream.c index cf5a9d4..cc8a1ae 100644 --- a/lpg/libqr/bitstream.c +++ b/lpg/libqr/bitstream.c @@ -121,13 +121,13 @@ size_t qr_bitstream_size(const struct qr_bitstream * stream) return stream->count; } -unsigned int qr_bitstream_read(struct qr_bitstream * stream, size_t bits) +unsigned long qr_bitstream_read(struct qr_bitstream * stream, int bits) { - unsigned int result = 0; + unsigned long result = 0; unsigned char * byte; size_t bitnum; - assert(qr_bitstream_remaining(stream) >= bits); + assert(qr_bitstream_remaining(stream) >= (size_t) bits); byte = stream->buffer + (stream->pos / CHAR_BIT); bitnum = stream->pos % CHAR_BIT; @@ -149,7 +149,7 @@ unsigned int qr_bitstream_read(struct qr_bitstream * stream, size_t bits) void qr_bitstream_unpack(struct qr_bitstream * stream, unsigned int * result, size_t count, - size_t bitsize) + int bitsize) { assert(qr_bitstream_remaining(stream) >= (count * bitsize)); @@ -158,8 +158,8 @@ void qr_bitstream_unpack(struct qr_bitstream * stream, } int qr_bitstream_write(struct qr_bitstream * stream, - unsigned int value, - size_t bits) + unsigned long value, + int bits) { unsigned char * byte; size_t bitnum; @@ -189,7 +189,7 @@ int qr_bitstream_write(struct qr_bitstream * stream, int qr_bitstream_pack(struct qr_bitstream * stream, const unsigned int * values, size_t count, - size_t bitsize) + int bitsize) { if (ensure_available(stream, count * bitsize) != 0) return -1; diff --git a/lpg/libqr/code-common.c b/lpg/libqr/code-common.c index 1cb1745..babaf86 100644 --- a/lpg/libqr/code-common.c +++ b/lpg/libqr/code-common.c @@ -76,7 +76,7 @@ void qr_get_rs_block_sizes(int version, void qr_mask_apply(struct qr_bitmap * bmp, int mask) { - int i, j; + size_t i, j; assert((mask & 0x7) == mask); mask &= 0x7; diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index cf04eb7..f9d86a7 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -36,7 +36,7 @@ static void x_dump(struct qr_bitstream * bits) qr_bitstream_seek(bits, 0); n = qr_bitstream_size(bits); for (i = 0; i < n; ++i) { - fprintf(stderr, "%d", qr_bitstream_read(bits, 1)); + fprintf(stderr, "%d", (int) qr_bitstream_read(bits, 1)); if (i % 8 == 7) fputc(' ', stderr); if ((i+1) % (7 * 8) == 0) @@ -173,7 +173,7 @@ static struct qr_bitstream * make_data(int version, const size_t total_data = QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]; int block_count[2], data_length[2], ec_length[2]; int total_blocks; - size_t i, w; + int i, w; struct qr_bitstream * dcopy = 0; struct qr_bitstream * out = 0; struct qr_bitstream ** blocks = 0; @@ -296,7 +296,7 @@ struct qr_code * qr_code_create(const struct qr_data * data) goto fail; qr_bitstream_seek(bits, 0); - while (qr_bitstream_remaining(bits) >= QR_WORD_BITS) + while (qr_bitstream_remaining(bits) >= (size_t) QR_WORD_BITS) qr_layout_write(layout, qr_bitstream_read(bits, QR_WORD_BITS)); qr_layout_end(layout); @@ -370,7 +370,8 @@ static int score_mask(const struct qr_bitmap * bmp) static int score_runs(const struct qr_bitmap * bmp, int base) { /* Runs of 5+n bits -> N[0] + i */ - int x, y, flip; + size_t x, y; + int flip; int score = 0; int count, last; @@ -406,7 +407,7 @@ static int score_runs(const struct qr_bitmap * bmp, int base) static int count_2blocks(const struct qr_bitmap * bmp) { /* Count the number of 2x2 blocks (on or off) */ - int x, y; + size_t x, y; int count = 0; /* Slow and stupid */ @@ -435,7 +436,8 @@ static int count_2blocks(const struct qr_bitmap * bmp) static int count_locators(const struct qr_bitmap * bmp) { /* 1:1:3:1:1 patterns -> N[2] */ - int x, y, flip; + size_t x, y; + int flip; int count = 0; for (flip = 0; flip <= 1; ++flip) { @@ -469,7 +471,7 @@ static int count_locators(const struct qr_bitmap * bmp) static int calc_bw_balance(const struct qr_bitmap * bmp) { /* Calculate the proportion (in percent) of "on" bits */ - int x, y; + size_t x, y; unsigned char bit; long on, total; diff --git a/lpg/libqr/code-layout.c b/lpg/libqr/code-layout.c index 8b4522d..fe8caa7 100644 --- a/lpg/libqr/code-layout.c +++ b/lpg/libqr/code-layout.c @@ -21,11 +21,11 @@ struct qr_iterator { void qr_layout_init_mask(struct qr_code * code) { - int x, y; - int dim = qr_code_width(code); + size_t x, y; + size_t dim = qr_code_width(code); struct qr_bitmap * bmp = code->modules; const int * am_pos = QR_ALIGNMENT_LOCATION[code->version - 1]; - int am_side; + size_t am_side; if (!bmp->mask) qr_bitmap_add_mask(bmp); diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index d4a2538..3fca4b2 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -111,7 +111,7 @@ static int read_bits(const struct qr_code * code, const size_t total_words = total_bits / QR_WORD_BITS; struct qr_bitstream * raw_bits; struct qr_iterator * layout; - int w; + size_t w; int ret = -1; raw_bits = qr_bitstream_create(); @@ -292,7 +292,7 @@ cleanup: return status; } -int qr_decode_format(unsigned bits, enum qr_ec_level * ec, int * mask) +int qr_decode_format(unsigned long bits, enum qr_ec_level * ec, int * mask) { bits ^= QR_FORMAT_MASK; diff --git a/lpg/libqr/constants.h b/lpg/libqr/constants.h index c13ae5a..b1f7493 100644 --- a/lpg/libqr/constants.h +++ b/lpg/libqr/constants.h @@ -17,7 +17,7 @@ static const unsigned int QR_FORMAT_POLY = 0x537; static const unsigned int QR_VERSION_POLY = 0x1F25; /* A QR-code word is always 8 bits, but CHAR_BIT might not be */ -static const unsigned int QR_WORD_BITS = 8; +static const int QR_WORD_BITS = 8; extern const int QR_ALIGNMENT_LOCATION[40][7]; extern const int QR_DATA_WORD_COUNT[40][4]; diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c index 9d6c384..6437bc1 100644 --- a/lpg/libqr/data-create.c +++ b/lpg/libqr/data-create.c @@ -175,7 +175,7 @@ static int calc_min_version(enum qr_data_type type, for (version = 1; version <= 40; ++version) { if (4 + dbits + qr_data_size_field_length(version, type) - < 8 * QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]) + < 8 * (size_t) QR_DATA_WORD_COUNT[version - 1][ec ^ 0x1]) return version; } diff --git a/lpg/libqr/galois.c b/lpg/libqr/galois.c index f0aadfd..decefb0 100644 --- a/lpg/libqr/galois.c +++ b/lpg/libqr/galois.c @@ -83,7 +83,7 @@ struct qr_bitstream * rs_generate_words(struct qr_bitstream * data, unsigned int * b = 0; unsigned int * g; size_t n = rs_words; - int i, r; + size_t i, r; assert(qr_bitstream_remaining(data) >= data_words * 8); diff --git a/lpg/libqr/qr/bitmap.h b/lpg/libqr/qr/bitmap.h index 36c56b3..d4af471 100644 --- a/lpg/libqr/qr/bitmap.h +++ b/lpg/libqr/qr/bitmap.h @@ -8,7 +8,7 @@ struct qr_bitmap { size_t width, height; }; -struct qr_bitmap * qr_bitmap_create(int width, int height, int masked); +struct qr_bitmap * qr_bitmap_create(size_t width, size_t height, int masked); void qr_bitmap_destroy(struct qr_bitmap *); int qr_bitmap_add_mask(struct qr_bitmap *); @@ -19,9 +19,9 @@ 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, + int mod_bits, size_t line_stride, - size_t line_repeat, + int line_repeat, unsigned long mark, unsigned long space); diff --git a/lpg/libqr/qr/bitstream.h b/lpg/libqr/qr/bitstream.h index 5ca6b41..9bd8261 100644 --- a/lpg/libqr/qr/bitstream.h +++ b/lpg/libqr/qr/bitstream.h @@ -22,21 +22,21 @@ size_t qr_bitstream_tell(const struct qr_bitstream *); size_t qr_bitstream_remaining(const struct qr_bitstream *); size_t qr_bitstream_size(const struct qr_bitstream *); -unsigned int qr_bitstream_read(struct qr_bitstream *, size_t bits); +unsigned long qr_bitstream_read(struct qr_bitstream *, int bits); void qr_bitstream_unpack(struct qr_bitstream *, unsigned int * result, size_t count, - size_t bitsize); + int bitsize); int qr_bitstream_write(struct qr_bitstream *, - unsigned int value, - size_t bits); + unsigned long value, + int bits); int qr_bitstream_pack(struct qr_bitstream *, const unsigned int * values, size_t count, - size_t bitsize); + int bitsize); int qr_bitstream_cat(struct qr_bitstream *, const struct qr_bitstream * src); diff --git a/lpg/libqr/qr/parse.h b/lpg/libqr/qr/parse.h index d7b8c4e..07a0424 100644 --- a/lpg/libqr/qr/parse.h +++ b/lpg/libqr/qr/parse.h @@ -9,7 +9,7 @@ int qr_code_parse(const void * buffer, size_t line_count, struct qr_data ** data); -int qr_decode_format(unsigned bits, enum qr_ec_level * ec, int * mask); +int qr_decode_format(unsigned long bits, enum qr_ec_level * ec, int * mask); int qr_decode_version(unsigned long bits, int * version); #endif diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index 6098231..3007011 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -100,7 +100,7 @@ void output_ansi(const struct qr_bitmap * bmp) }; unsigned char * line; - int x, y; + size_t x, y; line = bmp->bits; -- cgit v1.2.3-70-g09d2 From 1ea62d837531c4d5795381da5a2566606e03ac4b Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Tue, 19 Jul 2011 12:06:08 +0900 Subject: Consistent function names --- lpg/libqr/data-common.c | 2 +- lpg/libqr/data-create.c | 2 +- lpg/libqr/qr/data.h | 4 ++-- lpg/libqr/qrgen.c | 4 ++-- lpg/libqr/qrparse.c | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lpg/libqr/data-common.c b/lpg/libqr/data-common.c index 8a05f4a..af3a766 100644 --- a/lpg/libqr/data-common.c +++ b/lpg/libqr/data-common.c @@ -3,7 +3,7 @@ #include #include -void qr_free_data(struct qr_data * data) +void qr_data_destroy(struct qr_data * data) { qr_bitstream_destroy(data->bits); free(data); diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c index 6437bc1..8ab127d 100644 --- a/lpg/libqr/data-create.c +++ b/lpg/libqr/data-create.c @@ -182,7 +182,7 @@ static int calc_min_version(enum qr_data_type type, return -1; } -struct qr_data * qr_create_data(int version, +struct qr_data * qr_data_create(int version, enum qr_ec_level ec, enum qr_data_type type, const char * input, diff --git a/lpg/libqr/qr/data.h b/lpg/libqr/qr/data.h index 3cc665a..f2b4b45 100644 --- a/lpg/libqr/qr/data.h +++ b/lpg/libqr/qr/data.h @@ -11,13 +11,13 @@ struct qr_data { size_t offset; }; -struct qr_data * qr_create_data(int format, /* 1 ~ 40; 0=auto */ +struct qr_data * qr_data_create(int format, /* 1 ~ 40; 0=auto */ enum qr_ec_level ec, enum qr_data_type type, const char * input, size_t length); -void qr_free_data(struct qr_data *); +void qr_data_destroy(struct qr_data *); enum qr_data_type qr_data_type(const struct qr_data *); diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index 3007011..d59954d 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -31,7 +31,7 @@ struct qr_code * create(int version, len = strlen(input); - data = qr_create_data(version, ec, dtype, input, len); + data = qr_data_create(version, ec, dtype, input, len); if (!data) { /* BUG: this could also indicate OOM or @@ -42,7 +42,7 @@ struct qr_code * create(int version, } code = qr_code_create(data); - qr_free_data(data); + qr_data_destroy(data); if (!code) { perror("Failed to create code"); diff --git a/lpg/libqr/qrparse.c b/lpg/libqr/qrparse.c index 4a9312f..013066b 100644 --- a/lpg/libqr/qrparse.c +++ b/lpg/libqr/qrparse.c @@ -51,7 +51,7 @@ int main(int argc, char ** argv) } fprintf(stderr, "Data type: %s; %lu bytes\nContent: %s\n", type_str, data_len, data_str); free(data_str); - qr_free_data(data); + qr_data_destroy(data); } return 0; -- cgit v1.2.3-70-g09d2 From 779e729ad887c1cc967731a9634a11438d56b017 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Tue, 19 Jul 2011 12:08:33 +0900 Subject: Add C++ header protectors --- lpg/libqr/qr/bitmap.h | 8 ++++++++ lpg/libqr/qr/bitstream.h | 8 ++++++++ lpg/libqr/qr/code.h | 8 ++++++++ lpg/libqr/qr/common.h | 8 ++++++++ lpg/libqr/qr/data.h | 8 ++++++++ lpg/libqr/qr/layout.h | 8 ++++++++ lpg/libqr/qr/parse.h | 8 ++++++++ lpg/libqr/qr/types.h | 8 ++++++++ lpg/libqr/qr/version.h | 8 ++++++++ 9 files changed, 72 insertions(+) diff --git a/lpg/libqr/qr/bitmap.h b/lpg/libqr/qr/bitmap.h index d4af471..72da07f 100644 --- a/lpg/libqr/qr/bitmap.h +++ b/lpg/libqr/qr/bitmap.h @@ -1,6 +1,10 @@ #ifndef QR_BITMAP_H #define QR_BITMAP_H +#ifdef __cplusplus +extern "C" { +#endif + struct qr_bitmap { unsigned char * bits; unsigned char * mask; @@ -25,5 +29,9 @@ void qr_bitmap_render(const struct qr_bitmap * bmp, unsigned long mark, unsigned long space); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lpg/libqr/qr/bitstream.h b/lpg/libqr/qr/bitstream.h index 9bd8261..aa431e8 100644 --- a/lpg/libqr/qr/bitstream.h +++ b/lpg/libqr/qr/bitstream.h @@ -3,6 +3,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + /** * Note: when writing / reading multiple bits, the * _most_ significant bits come first in the stream. @@ -45,5 +49,9 @@ int qr_bitstream_copy(struct qr_bitstream * dest, struct qr_bitstream * src, size_t count); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lpg/libqr/qr/code.h b/lpg/libqr/qr/code.h index e6eb47c..0f5d49c 100644 --- a/lpg/libqr/qr/code.h +++ b/lpg/libqr/qr/code.h @@ -4,6 +4,10 @@ #include #include "types.h" +#ifdef __cplusplus +extern "C" { +#endif + struct qr_code { int version; struct qr_bitmap * modules; @@ -13,5 +17,9 @@ struct qr_code * qr_code_create(const struct qr_data * data); void qr_code_destroy(struct qr_code *); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lpg/libqr/qr/common.h b/lpg/libqr/qr/common.h index 640696a..b7052ad 100644 --- a/lpg/libqr/qr/common.h +++ b/lpg/libqr/qr/common.h @@ -3,6 +3,10 @@ #include +#ifdef __cplusplus +extern "C" { +#endif + void qr_mask_apply(struct qr_bitmap * bmp, int mask); size_t qr_code_total_capacity(int version); @@ -20,5 +24,9 @@ void qr_get_rs_block_sizes(int version, int data_length[2], int ec_length[2]); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lpg/libqr/qr/data.h b/lpg/libqr/qr/data.h index f2b4b45..06600ab 100644 --- a/lpg/libqr/qr/data.h +++ b/lpg/libqr/qr/data.h @@ -4,6 +4,10 @@ #include #include "types.h" +#ifdef __cplusplus +extern "C" { +#endif + struct qr_data { int version; /* 1 ~ 40 */ enum qr_ec_level ec; @@ -29,5 +33,9 @@ enum qr_data_type qr_parse_data(const struct qr_data * input, char ** output, size_t * length); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lpg/libqr/qr/layout.h b/lpg/libqr/qr/layout.h index 49bebf6..e691bdb 100644 --- a/lpg/libqr/qr/layout.h +++ b/lpg/libqr/qr/layout.h @@ -1,6 +1,10 @@ #ifndef QR_CODE_LAYOUT_H #define QR_CODE_LAYOUT_H +#ifdef __cplusplus +extern "C" { +#endif + struct qr_iterator; void qr_layout_init_mask(struct qr_code *); @@ -10,5 +14,9 @@ unsigned int qr_layout_read(struct qr_iterator *); void qr_layout_write(struct qr_iterator *, unsigned int); void qr_layout_end(struct qr_iterator *); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lpg/libqr/qr/parse.h b/lpg/libqr/qr/parse.h index 07a0424..0e08354 100644 --- a/lpg/libqr/qr/parse.h +++ b/lpg/libqr/qr/parse.h @@ -3,6 +3,10 @@ #include "data.h" +#ifdef __cplusplus +extern "C" { +#endif + int qr_code_parse(const void * buffer, size_t line_bits, size_t line_stride, @@ -12,5 +16,9 @@ int qr_code_parse(const void * buffer, int qr_decode_format(unsigned long bits, enum qr_ec_level * ec, int * mask); int qr_decode_version(unsigned long bits, int * version); +#ifdef __cplusplus +} +#endif + #endif diff --git a/lpg/libqr/qr/types.h b/lpg/libqr/qr/types.h index 3615e3e..ae760ab 100644 --- a/lpg/libqr/qr/types.h +++ b/lpg/libqr/qr/types.h @@ -1,6 +1,10 @@ #ifndef QR_TYPES_H #define QR_TYPES_H +#ifdef __cplusplus +extern "C" { +#endif + struct qr_data; struct qr_code; @@ -22,5 +26,9 @@ enum qr_ec_level { QR_EC_LEVEL_H = 0x2 }; +#ifdef __cplusplus +} +#endif + #endif diff --git a/lpg/libqr/qr/version.h b/lpg/libqr/qr/version.h index cd263c0..ce540f4 100644 --- a/lpg/libqr/qr/version.h +++ b/lpg/libqr/qr/version.h @@ -1,10 +1,18 @@ #ifndef QR_VERSION_H #define QR_VERSION_H +#ifdef __cplusplus +extern "C" { +#endif + #define QR_VERSION_MAJOR 0 #define QR_VERSION_MINOR 3 #define QR_VERSION "0.3" +#ifdef __cplusplus +} +#endif + #endif -- cgit v1.2.3-70-g09d2 From a2683d2ecbd9dadf115fe2143c17ef8a14b86eda Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Tue, 19 Jul 2011 13:04:24 +0900 Subject: Remove debug noise --- lpg/libqr/code-create.c | 26 -------------------------- 1 file changed, 26 deletions(-) diff --git a/lpg/libqr/code-create.c b/lpg/libqr/code-create.c index f9d86a7..f64e42d 100644 --- a/lpg/libqr/code-create.c +++ b/lpg/libqr/code-create.c @@ -28,23 +28,6 @@ static int draw_format(struct qr_bitmap * bmp, static unsigned int calc_format_bits(enum qr_ec_level ec, int mask); static unsigned long calc_version_bits(int version); -#include -static void x_dump(struct qr_bitstream * bits) -{ - size_t i, n; - - qr_bitstream_seek(bits, 0); - n = qr_bitstream_size(bits); - for (i = 0; i < n; ++i) { - fprintf(stderr, "%d", (int) qr_bitstream_read(bits, 1)); - if (i % 8 == 7) - fputc(' ', stderr); - if ((i+1) % (7 * 8) == 0) - fputc('\n', stderr); - } - fputc('\n', stderr); -} - static void setpx(struct qr_bitmap * bmp, int x, int y) { size_t off = y * bmp->stride + x / CHAR_BIT; @@ -197,9 +180,6 @@ static struct qr_bitstream * make_data(int version, if (pad_data(dcopy, total_data * QR_WORD_BITS) != 0) goto fail; - fputs("Pad data:\n", stderr); - x_dump(dcopy); - /* Make space for the RS blocks */ blocks = malloc(total_blocks * sizeof(*blocks)); if (!blocks) @@ -209,7 +189,6 @@ static struct qr_bitstream * make_data(int version, /* Generate RS codewords */ qr_bitstream_seek(dcopy, 0); - fputs("Generate RS blocks:\n", stderr); for (i = 0; i < total_blocks; ++i) { int type = (i >= block_count[0]); blocks[i] = rs_generate_words(dcopy, @@ -222,7 +201,6 @@ static struct qr_bitstream * make_data(int version, blocks = 0; goto fail; } - x_dump(blocks[i]); } /* Finally, write everything out in the correct order */ @@ -247,8 +225,6 @@ static struct qr_bitstream * make_data(int version, qr_bitstream_write(out, 0, total_bits % QR_WORD_BITS); - fputs("Final bitstream:\n", stderr); - x_dump(out); exit: if (blocks) { while (total_blocks--) @@ -336,7 +312,6 @@ static int mask_data(struct qr_code * code) } qr_mask_apply(test, i); score = score_mask(test); - fprintf(stderr, "mask %d scored %d\n", i, score); if (!mask || score < best) { best = score; selected = i; @@ -346,7 +321,6 @@ static int mask_data(struct qr_code * code) qr_bitmap_destroy(test); } } - fprintf(stderr, "Selected mask %d (%d)\n", selected, best); qr_bitmap_destroy(code->modules); code->modules = mask; -- cgit v1.2.3-70-g09d2 From eaec8202df88999e3d2fbc2755113dc03172e021 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Tue, 19 Jul 2011 15:32:19 +0900 Subject: Fix bitmap renderer --- lpg/libqr/bitmap.c | 20 +++++++++++--------- lpg/libqr/qr/bitmap.h | 2 +- 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/lpg/libqr/bitmap.c b/lpg/libqr/bitmap.c index b9d3763..1c4e38b 100644 --- a/lpg/libqr/bitmap.c +++ b/lpg/libqr/bitmap.c @@ -137,11 +137,10 @@ static void render_line_2(unsigned char * out, unsigned long space) { unsigned char in_mask; - size_t n, b, step, shift; + size_t n, b, step; in_mask = 1; step = CHAR_BIT / mod_bits; - shift = CHAR_BIT - mod_bits; n = dim; while (n > 0) { @@ -156,11 +155,9 @@ static void render_line_2(unsigned char * out, ++in; } - tmp = (tmp >> mod_bits) | (v << shift); - if (--n == 0) { - tmp >>= b * mod_bits; + tmp |= v << (b * mod_bits); + if (--n == 0) break; - } }; *out++ = tmp; @@ -170,7 +167,7 @@ static void render_line_2(unsigned char * out, void qr_bitmap_render(const struct qr_bitmap * bmp, void * buffer, int mod_bits, - size_t line_stride, + ptrdiff_t line_stride, int line_repeat, unsigned long mark, unsigned long space) @@ -188,6 +185,9 @@ void qr_bitmap_render(const struct qr_bitmap * bmp, out = buffer; dim = bmp->width; + mark &= (1 << mod_bits) - 1; + space &= (1 << mod_bits) - 1; + n = dim; while (n-- > 0) { size_t rpt; @@ -200,8 +200,10 @@ void qr_bitmap_render(const struct qr_bitmap * bmp, rpt = line_repeat; next = out + line_stride; - while (rpt-- > 0) { - memcpy(next, out, line_stride); + while (--rpt > 0) { + size_t bits = dim * mod_bits; + size_t bytes = bits / CHAR_BIT + !!(bits % CHAR_BIT); + memcpy(next, out, bytes); next += line_stride; } diff --git a/lpg/libqr/qr/bitmap.h b/lpg/libqr/qr/bitmap.h index 72da07f..57b33e0 100644 --- a/lpg/libqr/qr/bitmap.h +++ b/lpg/libqr/qr/bitmap.h @@ -24,7 +24,7 @@ void qr_bitmap_merge(struct qr_bitmap * dest, const struct qr_bitmap * src); void qr_bitmap_render(const struct qr_bitmap * bmp, void * buffer, int mod_bits, - size_t line_stride, + ptrdiff_t line_stride, int line_repeat, unsigned long mark, unsigned long space); -- cgit v1.2.3-70-g09d2 From 5d4815f09b8c0caf4e152bf737036eef22aaa399 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Sat, 6 Aug 2011 11:13:19 +0900 Subject: Further bitmap fixes --- lpg/libqr/bitmap.c | 8 +++++--- lpg/libqr/qr/bitmap.h | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/lpg/libqr/bitmap.c b/lpg/libqr/bitmap.c index 1c4e38b..246b9bd 100644 --- a/lpg/libqr/bitmap.c +++ b/lpg/libqr/bitmap.c @@ -167,7 +167,7 @@ static void render_line_2(unsigned char * out, void qr_bitmap_render(const struct qr_bitmap * bmp, void * buffer, int mod_bits, - ptrdiff_t line_stride, + long line_stride, int line_repeat, unsigned long mark, unsigned long space) @@ -185,8 +185,10 @@ void qr_bitmap_render(const struct qr_bitmap * bmp, out = buffer; dim = bmp->width; - mark &= (1 << mod_bits) - 1; - space &= (1 << mod_bits) - 1; + if (pack) { + mark &= (1 << mod_bits) - 1; + space &= (1 << mod_bits) - 1; + } n = dim; while (n-- > 0) { diff --git a/lpg/libqr/qr/bitmap.h b/lpg/libqr/qr/bitmap.h index 57b33e0..098d9c3 100644 --- a/lpg/libqr/qr/bitmap.h +++ b/lpg/libqr/qr/bitmap.h @@ -24,7 +24,7 @@ void qr_bitmap_merge(struct qr_bitmap * dest, const struct qr_bitmap * src); void qr_bitmap_render(const struct qr_bitmap * bmp, void * buffer, int mod_bits, - ptrdiff_t line_stride, + long line_stride, int line_repeat, unsigned long mark, unsigned long space); -- cgit v1.2.3-70-g09d2 From 96433dc8cbc6242adc11f78590068f37f88cfc30 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Mon, 24 Dec 2012 21:47:33 +0900 Subject: Fixes thanks to Roland Illig --- lpg/libqr/code-parse.c | 4 ++-- lpg/libqr/data-create.c | 20 ++++++++++++-------- lpg/libqr/qrparse.c | 2 +- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/lpg/libqr/code-parse.c b/lpg/libqr/code-parse.c index 3fca4b2..a84df72 100644 --- a/lpg/libqr/code-parse.c +++ b/lpg/libqr/code-parse.c @@ -216,10 +216,10 @@ int qr_code_parse(const void * buffer, struct qr_code code; enum qr_ec_level ec; int mask; - struct qr_bitstream * data_bits; + struct qr_bitstream * data_bits = NULL; int status; - fprintf(stderr, "parsing code bitmap %lux%lu\n", line_bits, line_count); + fprintf(stderr, "parsing code bitmap %lux%lu\n", (unsigned long) line_bits, (unsigned long) line_count); if (line_bits != line_count || line_bits < 21 diff --git a/lpg/libqr/data-create.c b/lpg/libqr/data-create.c index 8ab127d..09d6653 100644 --- a/lpg/libqr/data-create.c +++ b/lpg/libqr/data-create.c @@ -19,7 +19,7 @@ static void write_type_and_length(struct qr_data * data, } static struct qr_data * encode_numeric(struct qr_data * data, - const char * input, + const unsigned char * input, size_t length) { struct qr_bitstream * stream = data->bits; @@ -92,7 +92,7 @@ static int get_alpha_code(char c) } static struct qr_data * encode_alpha(struct qr_data * data, - const char * input, + const unsigned char * input, size_t length) { struct qr_bitstream * stream = data->bits; @@ -135,7 +135,7 @@ static struct qr_data * encode_alpha(struct qr_data * data, } static struct qr_data * encode_8bit(struct qr_data * data, - const char * input, + const unsigned char * input, size_t length) { struct qr_bitstream * stream = data->bits; @@ -158,7 +158,7 @@ static struct qr_data * encode_8bit(struct qr_data * data, } static struct qr_data * encode_kanji(struct qr_data * data, - const char * input, + const unsigned char * input, size_t length) { return 0; @@ -213,13 +213,17 @@ struct qr_data * qr_data_create(int version, switch (type) { case QR_DATA_NUMERIC: - ret = encode_numeric(data, input, length); break; + ret = encode_numeric(data, (const unsigned char *) input, length); + break; case QR_DATA_ALPHA: - ret = encode_alpha(data, input, length); break; + ret = encode_alpha(data, (const unsigned char *) input, length); + break; case QR_DATA_8BIT: - ret = encode_8bit(data, input, length); break; + ret = encode_8bit(data, (const unsigned char *) input, length); + break; case QR_DATA_KANJI: - ret = encode_kanji(data, input, length); break; + ret = encode_kanji(data, (const unsigned char *) input, length); + break; default: /* unsupported / invalid */ ret = 0; diff --git a/lpg/libqr/qrparse.c b/lpg/libqr/qrparse.c index 013066b..1b5c80e 100644 --- a/lpg/libqr/qrparse.c +++ b/lpg/libqr/qrparse.c @@ -49,7 +49,7 @@ int main(int argc, char ** argv) case QR_DATA_FNC1: type_str = "FNC1"; break; default: type_str = "(unknown)"; break; } - fprintf(stderr, "Data type: %s; %lu bytes\nContent: %s\n", type_str, data_len, data_str); + fprintf(stderr, "Data type: %s; %lu bytes\nContent: %s\n", type_str, (unsigned long) data_len, data_str); free(data_str); qr_data_destroy(data); } -- cgit v1.2.3-70-g09d2 From dc2db0639bec07ed06b90f5232aa437548ef760c Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Mon, 14 Jan 2013 21:11:28 +0900 Subject: qrgen: read data from file --- lpg/libqr/qrgen.c | 68 +++++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 61 insertions(+), 7 deletions(-) diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index d59954d..77fdeb2 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -17,19 +17,18 @@ struct config { enum qr_ec_level ec; enum qr_data_type dtype; int ansi; + const char * file; const char * input; }; struct qr_code * create(int version, enum qr_ec_level ec, enum qr_data_type dtype, - const char * input) + const char * input, + size_t len) { struct qr_data * data; struct qr_code * code; - size_t len; - - len = strlen(input); data = qr_data_create(version, ec, dtype, input, len); @@ -124,6 +123,7 @@ void show_help() { fprintf(stderr, "Usage:\n\t%s [options] \n\n" "\t-h Display this help message\n" + "\t-f File containing data to encode (- for stdin)\n" "\t-v Specify QR version (size) 1 <= n <= 40\n" "\t-e Specify EC type: L, M, Q, H\n" "\t-a Output as ANSI graphics (default)\n" @@ -137,6 +137,7 @@ void set_default_config(struct config * conf) conf->ec = QR_EC_LEVEL_M; conf->dtype = QR_DATA_8BIT; conf->ansi = 1; + conf->file = NULL; conf->input = NULL; } @@ -145,7 +146,7 @@ void parse_options(int argc, char ** argv, struct config * conf) int c; for (;;) { - c = getopt(argc, argv, ":hv:e:t:ap"); + c = getopt(argc, argv, ":hf:v:e:t:ap"); if (c == -1) /* no more options */ break; @@ -155,6 +156,9 @@ void parse_options(int argc, char ** argv, struct config * conf) show_help(); exit(0); break; + case 'f': /* file */ + conf->file = optarg; + break; case 'v': /* version */ conf->version = atoi(optarg); if (conf->version < 1 || conf->version > 40) { @@ -202,24 +206,74 @@ void parse_options(int argc, char ** argv, struct config * conf) if (optind < argc) conf->input = argv[optind++]; - if (!conf->input) { + if (!conf->file && !conf->input) { fprintf(stderr, "No data (try -h for help)\n"); exit(1); } } +void slurp_file(const char * path, char ** data, size_t * len) +{ + const size_t chunk_size = 65536; + FILE * file; + char * tmpbuf; + size_t count; + + if (strcmp(path, "-") == 0) + file = stdin; + else + file = fopen(path, "rb"); + + if (!file) { + fprintf(stderr, "Failed to open %s\n", path); + exit(2); + } + + *data = NULL; + *len = 0; + + do { + tmpbuf = realloc(*data, *len + chunk_size); + if (!tmpbuf) { + perror("realloc"); + exit(2); + } + *data = tmpbuf; + count = fread(*data + *len, 1, chunk_size, file); + if (count == 0 && !feof(file)) { + perror("fread"); + exit(2); + } + *len += count; + } while (*len == chunk_size); + + fclose(file); +} + int main(int argc, char ** argv) { struct config conf; struct qr_code * code; + char * file_data; + size_t len; set_default_config(&conf); parse_options(argc, argv, &conf); + if (conf.file) + slurp_file(conf.file, &file_data, &len); + else + len = strlen(conf.input); + + code = create(conf.version, conf.ec, conf.dtype, - conf.input); + conf.file ? file_data : conf.input, + len); + + if (conf.file) + free(file_data); if (conf.ansi) output_ansi(code->modules); -- cgit v1.2.3-70-g09d2 From 082fc1b97f2297fee6b2bba222c0c2e87f931493 Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Mon, 14 Jan 2013 21:51:34 +0900 Subject: qrgen: output to file --- lpg/libqr/qrgen.c | 52 ++++++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 16 deletions(-) diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index 77fdeb2..80e8ac2 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -18,6 +18,7 @@ struct config { enum qr_data_type dtype; int ansi; const char * file; + const char * outfile; const char * input; }; @@ -51,17 +52,17 @@ struct qr_code * create(int version, return code; } -void output_pbm(const struct qr_bitmap * bmp, const char * comment) +void output_pbm(FILE * file, const struct qr_bitmap * bmp, const char * comment) { unsigned char * row; int x, y; - puts("P1"); + fputs("P1\n", file); if (comment) - printf("# %s\n", comment); + fprintf(file, "# %s\n", comment); - printf("%u %u\n", + fprintf(file, "%u %u\n", (unsigned)bmp->width + 8, (unsigned)bmp->height + 8); @@ -71,27 +72,27 @@ void output_pbm(const struct qr_bitmap * bmp, const char * comment) if (y < 0 || y >= (int)bmp->height) { for (x = 0; x < (int)bmp->width + 8; ++x) - printf("0 "); - putchar('\n'); + fputs("0 ", file); + fputc('\n', file); continue; } - printf("0 0 0 0 "); + fputs("0 0 0 0 ", file); for (x = 0; x < (int)bmp->width; ++x) { int mask = 1 << x % CHAR_BIT; int byte = row[x / CHAR_BIT]; - printf("%c ", (byte & mask) ? '1' : '0'); + fprintf(file, "%c ", (byte & mask) ? '1' : '0'); } - puts("0 0 0 0"); + fputs("0 0 0 0\n", file); row += bmp->stride; } } -void output_ansi(const struct qr_bitmap * bmp) +void output_ansi(FILE * file, const struct qr_bitmap * bmp) { const char * out[2] = { " ", @@ -110,10 +111,10 @@ void output_ansi(const struct qr_bitmap * bmp) int mask = 1 << (x % CHAR_BIT); int byte = line[x / CHAR_BIT]; - printf("%s", out[!!(byte & mask)]); + fprintf(file, "%s", out[!!(byte & mask)]); } - putchar('\n'); + fputc('\n', file); line += bmp->stride; } @@ -127,7 +128,8 @@ void show_help() { "\t-v Specify QR version (size) 1 <= n <= 40\n" "\t-e Specify EC type: L, M, Q, H\n" "\t-a Output as ANSI graphics (default)\n" - "\t-p Output as PBM\n\n", + "\t-p Output as PBM\n" + "\t-o File to write (- for stdout)\n\n", "qrgen"); } @@ -138,6 +140,7 @@ void set_default_config(struct config * conf) conf->dtype = QR_DATA_8BIT; conf->ansi = 1; conf->file = NULL; + conf->outfile = NULL; conf->input = NULL; } @@ -146,7 +149,7 @@ void parse_options(int argc, char ** argv, struct config * conf) int c; for (;;) { - c = getopt(argc, argv, ":hf:v:e:t:ap"); + c = getopt(argc, argv, ":hf:v:e:t:apo:"); if (c == -1) /* no more options */ break; @@ -186,6 +189,8 @@ void parse_options(int argc, char ** argv, struct config * conf) conf->ansi = 1; break; case 'p': /* pnm */ conf->ansi = 0; break; + case 'o': /* output file */ + conf->outfile = optarg; break; case ':': fprintf(stderr, "Argument \"%s\" missing parameter\n", @@ -256,6 +261,7 @@ int main(int argc, char ** argv) { struct qr_code * code; char * file_data; size_t len; + FILE * outfile; set_default_config(&conf); parse_options(argc, argv, &conf); @@ -265,6 +271,19 @@ int main(int argc, char ** argv) { else len = strlen(conf.input); + if (!conf.outfile) { + conf.outfile = conf.ansi ? "-" : "qr.pbm"; + } + + if (strcmp(conf.outfile, "-") == 0) { + outfile = stdout; + } else { + outfile = fopen(conf.outfile, "wb"); + if (!outfile) { + perror("fopen"); + exit(2); + } + } code = create(conf.version, conf.ec, @@ -276,10 +295,11 @@ int main(int argc, char ** argv) { free(file_data); if (conf.ansi) - output_ansi(code->modules); + output_ansi(outfile, code->modules); else - output_pbm(code->modules, "libqr v" QR_VERSION); + output_pbm(outfile, code->modules, "libqr v" QR_VERSION); + fclose(outfile); qr_code_destroy(code); return 0; -- cgit v1.2.3-70-g09d2 From 7cfac56b2eaec43e507bf31313d5a16ac8133fba Mon Sep 17 00:00:00 2001 From: Leo Uino Date: Mon, 14 Jan 2013 23:01:58 +0900 Subject: qrgen: output to PNG --- lpg/libqr/Makefile | 2 +- lpg/libqr/qrgen.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++++---- 2 files changed, 104 insertions(+), 9 deletions(-) diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index fa6cf04..154bcbf 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -21,7 +21,7 @@ $(OBJECTS) : $(wildcard *.h qr/*.h) libqr : libqr.a($(OBJECTS)) qrgen : libqr qrgen.c - $(CC) $(CFLAGS) -o qrgen qrgen.c libqr.a + $(CC) $(CFLAGS) -o qrgen qrgen.c libqr.a $(shell pkg-config libpng --cflags --libs) qrparse : libqr qrparse.c $(CC) $(CFLAGS) -o qrparse qrparse.c libqr.a diff --git a/lpg/libqr/qrgen.c b/lpg/libqr/qrgen.c index 80e8ac2..cf518e5 100644 --- a/lpg/libqr/qrgen.c +++ b/lpg/libqr/qrgen.c @@ -2,6 +2,8 @@ #include #include #include +#include +#include #include #include #include @@ -16,7 +18,11 @@ struct config { int version; enum qr_ec_level ec; enum qr_data_type dtype; - int ansi; + enum { + FORMAT_ANSI, + FORMAT_PBM, + FORMAT_PNG + } format; const char * file; const char * outfile; const char * input; @@ -120,6 +126,78 @@ void output_ansi(FILE * file, const struct qr_bitmap * bmp) } } +void output_png(FILE * file, const struct qr_bitmap * bmp, const char * comment) +{ + const int px_size = 4; + png_structp png_ptr; + png_infop info_ptr; + png_text text; + int x, y, p; + unsigned char * row; + + png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (!png_ptr) + goto err; + + info_ptr = png_create_info_struct(png_ptr); + if (!info_ptr) + goto err; + + if (setjmp(png_jmpbuf(png_ptr))) + goto err; + + png_init_io(png_ptr, file); + png_set_IHDR(png_ptr, info_ptr, + (bmp->width + 8) * px_size, + (bmp->height + 8) * px_size, + 1, + PNG_COLOR_TYPE_GRAY, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, + PNG_FILTER_TYPE_DEFAULT); + + text.compression = PNG_TEXT_COMPRESSION_NONE; + text.key = "Software"; + text.text = (char *) comment; + text.text_length = strlen(comment); + png_set_text(png_ptr, info_ptr, &text, 1); + + png_write_info(png_ptr, info_ptr); + png_set_packing(png_ptr); + + row = malloc((bmp->width + 8) * px_size); + memset(row, 1, (bmp->width + 8) * px_size); + for (y = 0; y < 4; ++y) + for (p = 0; p < px_size; ++p) + png_write_row(png_ptr, row); + + for (y = 0; y < bmp->height; ++y) { + const unsigned char * bmp_row = bmp->bits + y * bmp->stride; + unsigned char * out = row + 4 * px_size; + for (x = 0; x < bmp->width; ++x) { + int px = bmp_row[x / CHAR_BIT] & (1 << (x % CHAR_BIT)); + for (p = 0; p < px_size; ++p) + *out++ = !px; + } + for (p = 0; p < px_size; ++p) + png_write_row(png_ptr, row); + } + + memset(row, 1, (bmp->width + 8) * px_size); + for (y = 0; y < 4; ++y) + for (p = 0; p < px_size; ++p) + png_write_row(png_ptr, row); + + free(row); + png_write_end(png_ptr, info_ptr); + png_destroy_write_struct(&png_ptr, NULL); + return; + +err: + fprintf(stderr, "error writing PNG\n"); + exit(2); +} + void show_help() { fprintf(stderr, "Usage:\n\t%s [options] \n\n" @@ -129,6 +207,7 @@ void show_help() { "\t-e Specify EC type: L, M, Q, H\n" "\t-a Output as ANSI graphics (default)\n" "\t-p Output as PBM\n" + "\t-g Output as PNG\n" "\t-o File to write (- for stdout)\n\n", "qrgen"); } @@ -138,7 +217,7 @@ void set_default_config(struct config * conf) conf->version = 0; conf->ec = QR_EC_LEVEL_M; conf->dtype = QR_DATA_8BIT; - conf->ansi = 1; + conf->format = FORMAT_ANSI; conf->file = NULL; conf->outfile = NULL; conf->input = NULL; @@ -149,7 +228,7 @@ void parse_options(int argc, char ** argv, struct config * conf) int c; for (;;) { - c = getopt(argc, argv, ":hf:v:e:t:apo:"); + c = getopt(argc, argv, ":hf:v:e:t:apgo:"); if (c == -1) /* no more options */ break; @@ -186,9 +265,11 @@ void parse_options(int argc, char ** argv, struct config * conf) fprintf(stderr, "XXX: ignored \"type\"\n"); break; case 'a': /* ansi */ - conf->ansi = 1; break; + conf->format = FORMAT_ANSI; break; case 'p': /* pnm */ - conf->ansi = 0; break; + conf->format = FORMAT_PBM; break; + case 'g': /* png */ + conf->format = FORMAT_PNG; break; case 'o': /* output file */ conf->outfile = optarg; break; case ':': @@ -272,7 +353,14 @@ int main(int argc, char ** argv) { len = strlen(conf.input); if (!conf.outfile) { - conf.outfile = conf.ansi ? "-" : "qr.pbm"; + switch (conf.format) { + case FORMAT_ANSI: + conf.outfile = "-"; break; + case FORMAT_PBM: + conf.outfile = "qr.pbm"; break; + case FORMAT_PNG: + conf.outfile = "qr.png"; break; + } } if (strcmp(conf.outfile, "-") == 0) { @@ -294,10 +382,17 @@ int main(int argc, char ** argv) { if (conf.file) free(file_data); - if (conf.ansi) + switch (conf.format) { + case FORMAT_ANSI: output_ansi(outfile, code->modules); - else + break; + case FORMAT_PBM: output_pbm(outfile, code->modules, "libqr v" QR_VERSION); + break; + case FORMAT_PNG: + output_png(outfile, code->modules, "libqr v" QR_VERSION); + break; + } fclose(outfile); qr_code_destroy(code); -- cgit v1.2.3-70-g09d2 From b4e84ab278658928787acbe5edffd07c3207ea18 Mon Sep 17 00:00:00 2001 From: Přemysl Eric Janouch Date: Fri, 10 Jan 2025 15:52:10 +0100 Subject: Add an important comment --- lpg/libqr/Makefile | 1 + 1 file changed, 1 insertion(+) diff --git a/lpg/libqr/Makefile b/lpg/libqr/Makefile index 154bcbf..176c30c 100644 --- a/lpg/libqr/Makefile +++ b/lpg/libqr/Makefile @@ -1,3 +1,4 @@ +# XXX: This Makefile only works single-threaded, -j1 is required. OBJECTS := bitmap.o \ bitstream.o \ constants.o \ -- cgit v1.2.3-70-g09d2 From ab64314222aca47dd7e52eca2d54d2fad0a58f6c Mon Sep 17 00:00:00 2001 From: Přemysl Eric Janouch Date: Fri, 10 Jan 2025 15:55:24 +0100 Subject: Resolve a compiler warning --- lpg/libqr/constants.c | 80 +++++++++++++++++++++++++-------------------------- 1 file changed, 40 insertions(+), 40 deletions(-) diff --git a/lpg/libqr/constants.c b/lpg/libqr/constants.c index 797d853..18c37e6 100644 --- a/lpg/libqr/constants.c +++ b/lpg/libqr/constants.c @@ -88,46 +88,46 @@ const int QR_DATA_WORD_COUNT[40][4] = { }; const int QR_RS_BLOCK_COUNT[40][4][2] = { - { 1, 0, 1, 0, 1, 0, 1, 0 }, /* 1 */ - { 1, 0, 1, 0, 1, 0, 1, 0 }, /* 2 */ - { 1, 0, 1, 0, 2, 0, 2, 0 }, /* 3 */ - { 1, 0, 2, 0, 2, 0, 4, 0 }, /* 4 */ - { 1, 0, 2, 0, 2, 2, 2, 2 }, /* 5 */ - { 2, 0, 4, 0, 4, 0, 4, 0 }, /* 6 */ - { 2, 0, 4, 0, 2, 4, 4, 1 }, /* 7 */ - { 2, 0, 2, 2, 4, 2, 4, 2 }, /* 8 */ - { 2, 0, 3, 2, 4, 4, 4, 4 }, /* 9 */ - { 2, 2, 4, 1, 6, 2, 6, 2 }, /* 10 */ - { 4, 0, 1, 4, 4, 4, 3, 8 }, /* 11 */ - { 2, 2, 6, 2, 4, 6, 7, 4 }, /* 12 */ - { 4, 0, 8, 1, 8, 4, 12, 4 }, /* 13 */ - { 3, 1, 4, 5, 11, 5, 11, 5 }, /* 14 */ - { 5, 1, 5, 5, 5, 7, 11, 7 }, /* 15 */ - { 5, 1, 7, 3, 15, 2, 3, 13 }, /* 16 */ - { 1, 5, 10, 1, 1, 15, 2, 17 }, /* 17 */ - { 5, 1, 9, 4, 17, 1, 2, 19 }, /* 18 */ - { 3, 4, 3, 11, 17, 4, 9, 16 }, /* 19 */ - { 3, 5, 3, 13, 15, 5, 15, 10 }, /* 20 */ - { 4, 4, 17, 0, 17, 6, 19, 6 }, /* 21 */ - { 2, 7, 17, 0, 7, 16, 34, 0 }, /* 22 */ - { 4, 5, 4, 14, 11, 14, 16, 14 }, /* 23 */ - { 6, 4, 6, 14, 11, 16, 30, 2 }, /* 24 */ - { 8, 4, 8, 13, 7, 22, 22, 13 }, /* 25 */ - { 10, 2, 19, 4, 28, 6, 33, 4 }, /* 26 */ - { 8, 4, 22, 3, 8, 26, 12, 28 }, /* 27 */ - { 3, 10, 3, 23, 4, 31, 11, 31 }, /* 28 */ - { 7, 7, 21, 7, 1, 37, 19, 26 }, /* 29 */ - { 5, 10, 19, 10, 15, 25, 23, 25 }, /* 30 */ - { 13, 3, 2, 29, 42, 1, 23, 28 }, /* 31 */ - { 17, 0, 10, 23, 10, 35, 19, 35 }, /* 32 */ - { 17, 1, 14, 21, 29, 19, 11, 46 }, /* 33 */ - { 13, 6, 14, 23, 44, 7, 59, 1 }, /* 34 */ - { 12, 7, 12, 26, 39, 14, 22, 41 }, /* 35 */ - { 6, 14, 6, 34, 46, 10, 2, 64 }, /* 36 */ - { 17, 4, 29, 14, 49, 10, 24, 46 }, /* 37 */ - { 4, 18, 13, 32, 48, 14, 42, 32 }, /* 38 */ - { 20, 4, 40, 7, 43, 22, 10, 67 }, /* 39 */ - { 19, 6, 18, 31, 34, 34, 20, 61 } /* 40 */ + { { 1, 0 }, { 1, 0 }, { 1, 0 }, { 1, 0 } }, /* 1 */ + { { 1, 0 }, { 1, 0 }, { 1, 0 }, { 1, 0 } }, /* 2 */ + { { 1, 0 }, { 1, 0 }, { 2, 0 }, { 2, 0 } }, /* 3 */ + { { 1, 0 }, { 2, 0 }, { 2, 0 }, { 4, 0 } }, /* 4 */ + { { 1, 0 }, { 2, 0 }, { 2, 2 }, { 2, 2 } }, /* 5 */ + { { 2, 0 }, { 4, 0 }, { 4, 0 }, { 4, 0 } }, /* 6 */ + { { 2, 0 }, { 4, 0 }, { 2, 4 }, { 4, 1 } }, /* 7 */ + { { 2, 0 }, { 2, 2 }, { 4, 2 }, { 4, 2 } }, /* 8 */ + { { 2, 0 }, { 3, 2 }, { 4, 4 }, { 4, 4 } }, /* 9 */ + { { 2, 2 }, { 4, 1 }, { 6, 2 }, { 6, 2 } }, /* 10 */ + { { 4, 0 }, { 1, 4 }, { 4, 4 }, { 3, 8 } }, /* 11 */ + { { 2, 2 }, { 6, 2 }, { 4, 6 }, { 7, 4 } }, /* 12 */ + { { 4, 0 }, { 8, 1 }, { 8, 4 }, { 12, 4 } }, /* 13 */ + { { 3, 1 }, { 4, 5 }, { 11, 5 }, { 11, 5 } }, /* 14 */ + { { 5, 1 }, { 5, 5 }, { 5, 7 }, { 11, 7 } }, /* 15 */ + { { 5, 1 }, { 7, 3 }, { 15, 2 }, { 3, 13 } }, /* 16 */ + { { 1, 5 }, { 10, 1 }, { 1, 15 }, { 2, 17 } }, /* 17 */ + { { 5, 1 }, { 9, 4 }, { 17, 1 }, { 2, 19 } }, /* 18 */ + { { 3, 4 }, { 3, 11 }, { 17, 4 }, { 9, 16 } }, /* 19 */ + { { 3, 5 }, { 3, 13 }, { 15, 5 }, { 15, 10 } }, /* 20 */ + { { 4, 4 }, { 17, 0 }, { 17, 6 }, { 19, 6 } }, /* 21 */ + { { 2, 7 }, { 17, 0 }, { 7, 16 }, { 34, 0 } }, /* 22 */ + { { 4, 5 }, { 4, 14 }, { 11, 14 }, { 16, 14 } }, /* 23 */ + { { 6, 4 }, { 6, 14 }, { 11, 16 }, { 30, 2 } }, /* 24 */ + { { 8, 4 }, { 8, 13 }, { 7, 22 }, { 22, 13 } }, /* 25 */ + { { 10, 2 }, { 19, 4 }, { 28, 6 }, { 33, 4 } }, /* 26 */ + { { 8, 4 }, { 22, 3 }, { 8, 26 }, { 12, 28 } }, /* 27 */ + { { 3, 10 }, { 3, 23 }, { 4, 31 }, { 11, 31 } }, /* 28 */ + { { 7, 7 }, { 21, 7 }, { 1, 37 }, { 19, 26 } }, /* 29 */ + { { 5, 10 }, { 19, 10 }, { 15, 25 }, { 23, 25 } }, /* 30 */ + { { 13, 3 }, { 2, 29 }, { 42, 1 }, { 23, 28 } }, /* 31 */ + { { 17, 0 }, { 10, 23 }, { 10, 35 }, { 19, 35 } }, /* 32 */ + { { 17, 1 }, { 14, 21 }, { 29, 19 }, { 11, 46 } }, /* 33 */ + { { 13, 6 }, { 14, 23 }, { 44, 7 }, { 59, 1 } }, /* 34 */ + { { 12, 7 }, { 12, 26 }, { 39, 14 }, { 22, 41 } }, /* 35 */ + { { 6, 14 }, { 6, 34 }, { 46, 10 }, { 2, 64 } }, /* 36 */ + { { 17, 4 }, { 29, 14 }, { 49, 10 }, { 24, 46 } }, /* 37 */ + { { 4, 18 }, { 13, 32 }, { 48, 14 }, { 42, 32 } }, /* 38 */ + { { 20, 4 }, { 40, 7 }, { 43, 22 }, { 10, 67 } }, /* 39 */ + { { 19, 6 }, { 18, 31 }, { 34, 34 }, { 20, 61 } } /* 40 */ }; const enum qr_data_type QR_TYPE_CODES[16] = { -- cgit v1.2.3-70-g09d2