aboutsummaryrefslogtreecommitdiff
path: root/lpg
diff options
context:
space:
mode:
Diffstat (limited to 'lpg')
-rw-r--r--lpg/libqr/Makefile1
-rw-r--r--lpg/libqr/code-create.c82
-rw-r--r--lpg/libqr/code-layout.c125
-rw-r--r--lpg/libqr/code-layout.h12
-rw-r--r--lpg/libqr/test.c15
5 files changed, 227 insertions, 8 deletions
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 <qr/code.h>
#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 <limits.h>
+#include <stdlib.h>
+#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;
}