summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSebastian Reichel <sre@ring0.de>2014-02-03 00:26:01 +0100
committerSebastian Reichel <sre@ring0.de>2014-02-03 00:26:01 +0100
commit258c7c1dce42fed4b1a66900f8d3b45c42aa71e0 (patch)
tree9dec294b08ec3476d5742a396a4918160fdb1b8d
parentf4a4c177d0340a426643d90aca7a0928ef2ac727 (diff)
downloadserial-barcode-scanner-258c7c1dce42fed4b1a66900f8d3b45c42aa71e0.tar.bz2
initial libcairobarcode
-rw-r--r--TODO.md3
-rw-r--r--libcairobarcode/.gitignore2
-rw-r--r--libcairobarcode/Makefile14
-rw-r--r--libcairobarcode/code39.vala128
-rw-r--r--libcairobarcode/ean.vala150
-rw-r--r--libcairobarcode/error.vala19
-rw-r--r--libcairobarcode/test.vala53
7 files changed, 368 insertions, 1 deletions
diff --git a/TODO.md b/TODO.md
index 2324aa2..5e9ed73 100644
--- a/TODO.md
+++ b/TODO.md
@@ -11,7 +11,8 @@
- [old code](https://github.com/ktt-ol/serial-barcode-scanner/commit/504cefec4a93a9b52fa9d25d6f353a4676485c43)
#### libcairobarcode
- * write vala library using cairo to generate a barcode
+ * make this a library instead of a test binary
+ * cleanup code
#### USERLIST-PDF
* write new vala process, which generates a user list pdf using libcairobarcode
diff --git a/libcairobarcode/.gitignore b/libcairobarcode/.gitignore
new file mode 100644
index 0000000..c0503b2
--- /dev/null
+++ b/libcairobarcode/.gitignore
@@ -0,0 +1,2 @@
+test
+test.svg
diff --git a/libcairobarcode/Makefile b/libcairobarcode/Makefile
new file mode 100644
index 0000000..b47d3b3
--- /dev/null
+++ b/libcairobarcode/Makefile
@@ -0,0 +1,14 @@
+include ../config.mk
+
+all: test
+
+libcairobarcode.so:
+ #TODO
+
+test: test.vala ean.vala code39.vala error.vala
+ ${VALAC} -o $@ --pkg cairo $^
+
+clean:
+ rm -f test test.svg
+
+.PHONY: all clean
diff --git a/libcairobarcode/code39.vala b/libcairobarcode/code39.vala
new file mode 100644
index 0000000..dd3d8c5
--- /dev/null
+++ b/libcairobarcode/code39.vala
@@ -0,0 +1,128 @@
+/* Copyright 2014, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public class Code39 {
+ Cairo.Context ctx;
+ double width;
+ double height;
+
+ /* 0 = wide black, 1 = narrow black, 2 = wide white, 3 = narrow white */
+ static const uint32[] lookup_table = {
+ 0x1d8cd, 0xd9dc, 0x1c9dc, 0xc9dd, 0x1d8dc, 0xd8dd, 0x1c8dd, 0x1d9cc,
+ 0xd9cd, 0x1c9cd, 0xdd9c, 0x1cd9c, 0xcd9d, 0x1dc9c, 0xdc9d, 0x1cc9d,
+ 0x1dd8c, 0xdd8d, 0x1cd8d, 0x1dc8d, 0xddd8, 0x1cdd8, 0xcdd9, 0x1dcd8,
+ 0xdcd9, 0x1ccd9, 0x1ddc8, 0xddc9, 0x1cdc9, 0x1dcc9, 0x9ddc, 0x18ddc,
+ 0x8ddd, 0x19cdc, 0x9cdd, 0x18cdd, 0x19dcc, 0x9dcd, 0x18dcd, 0x1999d,
+ 0x199d9, 0x19d99, 0x1d999, 0x19ccd
+ };
+
+ public Code39(Cairo.Context ctx, double width, double height) {
+ this.ctx = ctx;
+ this.width = width;
+ this.height = height;
+ }
+
+ private int lookup_index(char c) throws BarcodeError {
+ if(c >= '0' && c <= '9')
+ return c - '0';
+ if(c >= 'A' && c <= 'Z')
+ return 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;
+ default:
+ throw new BarcodeError.UNEXPECTED_CHARACTER("Character '%c' is not allowed in Code 39".printf(c));
+ }
+ }
+
+ private uint32 lookup(char c) throws BarcodeError {
+ return lookup_table[lookup_index(c)];
+ }
+
+ private void draw_line(bool black, double linewidth) {
+ double x,y;
+
+ if(black)
+ ctx.set_source_rgb(0, 0, 0);
+ else
+ ctx.set_source_rgb(1, 1, 1);
+
+ ctx.rel_line_to(0,height);
+ ctx.rel_move_to(linewidth,-height);
+
+ ctx.get_current_point(out x, out y);
+ ctx.stroke();
+ ctx.move_to(x,y);
+ }
+
+ public void draw(string code) throws BarcodeError {
+ string mycode = code;
+
+ if(!mycode.has_prefix("*"))
+ mycode = "*" + mycode;
+ if(!mycode.has_suffix("*"))
+ mycode = mycode + "*";
+
+ double linewidth = width / (mycode.length * 13.0);
+
+ ctx.save();
+ ctx.set_line_width(linewidth);
+ ctx.move_to(0,0);
+ ctx.rel_move_to(0.5*linewidth,0);
+
+ for(int i=0; i<mycode.length; i++) {
+ var format = lookup(mycode[i]);
+
+ for(int j=8; j>=0; j--) {
+ var line = (format >> (2*j)) & 0x3;
+
+ switch(line) {
+ case 0:
+ draw_line(true, linewidth);
+ draw_line(true, linewidth);
+ break;
+ case 1:
+ draw_line(true, linewidth);
+ break;
+ case 2:
+ draw_line(false, linewidth);
+ draw_line(false, linewidth);
+ break;
+ default:
+ draw_line(false, linewidth);
+ break;
+ }
+ }
+
+ draw_line(false, linewidth);
+ }
+
+ ctx.restore();
+ }
+}
diff --git a/libcairobarcode/ean.vala b/libcairobarcode/ean.vala
new file mode 100644
index 0000000..d76f079
--- /dev/null
+++ b/libcairobarcode/ean.vala
@@ -0,0 +1,150 @@
+/* Copyright 2014, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public class EAN {
+ Cairo.Context ctx;
+ double width;
+ double height;
+ const double marker_length_diff = 10.0;
+
+ static const uint8[] C = { 0x00, 0x0b, 0x0d, 0x0e, 0x13, 0x19, 0x1c, 0x15, 0x16, 0x1a };
+
+ static uint8[,] lookup = {
+ { 0x0d, 0x19, 0x13, 0x3d, 0x23, 0x31, 0x2f, 0x3b, 0x37, 0x0b }, /* L */
+ { 0x27, 0x33, 0x1b, 0x21, 0x1d, 0x39, 0x05, 0x11, 0x09, 0x17 }, /* G */
+ { 0x72, 0x66, 0x6c, 0x42, 0x5c, 0x4e, 0x50, 0x44, 0x48, 0x74 } /* R */
+ };
+
+ public EAN(Cairo.Context ctx, double width, double height) {
+ this.ctx = ctx;
+ this.width = width / 95.0;
+ this.height = height;
+ }
+
+ private void draw_line(bool black, bool marker=false) {
+ double x,y;
+
+ if(black)
+ ctx.set_source_rgb(0, 0, 0);
+ else
+ ctx.set_source_rgb(1, 1, 1);
+
+ if(marker) {
+ ctx.rel_line_to(0,height);
+ ctx.rel_move_to(width,-height);
+ } else {
+ ctx.rel_line_to(0,height-marker_length_diff);
+ ctx.rel_move_to(width,-(height-marker_length_diff));
+ }
+
+ ctx.get_current_point(out x, out y);
+ ctx.stroke();
+ ctx.move_to(x,y);
+ }
+
+ private void draw_startstop() {
+ draw_line(true, true);
+ draw_line(false, true);
+ draw_line(true, true);
+ }
+
+ private void draw_middle() {
+ draw_line(false, true);
+ draw_line(true, true);
+ draw_line(false, true);
+ draw_line(true, true);
+ draw_line(false, true);
+ }
+
+ private void draw_number_text(uint8 number) {
+ double x, y;
+ ctx.get_current_point(out x, out y);
+ ctx.set_source_rgb(0, 0, 0);
+ ctx.rel_move_to(2.5,height);
+
+ ctx.show_text("%d".printf(number));
+
+ ctx.stroke();
+ ctx.move_to(x,y);
+ }
+
+ private void draw_number(uint8 number, uint8 type) {
+ draw_number_text(number);
+
+ for(int i=6; i>=0; i--) {
+ var bit = (lookup[type,number] >> i) & 1;
+ draw_line(bit == 1);
+ }
+ }
+
+ private uint8 get_number(string ean, int pos) {
+ return (uint8) int.parse("%c".printf(ean[pos]));
+ }
+
+ private void draw13(string ean) {
+ /* need some extra space for the checksum */
+ width = (width * 95.0) / 102.0;
+
+ uint8 LG = C[get_number(ean, 0)];
+ draw_number_text(get_number(ean, 0));
+ ctx.move_to(7*width,0);
+
+ draw_startstop();
+ for(int i=1, x = 5; i<7; i++, x--) {
+ uint8 type = (uint8) (LG >> x) & 1;
+ draw_number(get_number(ean,i), type);
+ }
+ draw_middle();
+ for(int i=7; i<13; i++)
+ draw_number(get_number(ean,i), 2);
+ draw_startstop();
+
+ /* remove extra space for the checksum */
+ width = (width * 102.0) / 95.0;
+
+ }
+
+ private void draw8(string ean) {
+ draw_startstop();
+ for(int i=0; i<4; i++)
+ draw_number(get_number(ean,i), 0);
+ draw_middle();
+ for(int i=4; i<8; i++)
+ draw_number(get_number(ean,i), 2);
+ draw_startstop();
+ }
+
+ public void draw(string ean) throws BarcodeError {
+ ctx.save();
+ ctx.set_line_width(width);
+ ctx.move_to(0,0);
+ ctx.rel_move_to(0.5*width,0);
+
+ for(int i=0; i<ean.length; i++) {
+ if(ean[i] < '0' || ean[i] > '9') {
+ throw new BarcodeError.UNEXPECTED_CHARACTER("Character '%c' is not allowed in EAN".printf(ean[i]));
+ }
+ }
+
+ if(ean.length == 13)
+ draw13(ean);
+ else if(ean.length == 8)
+ draw8(ean);
+ else
+ throw new BarcodeError.UNEXPECTED_LENGTH("length of EAN is incorrect (must be 8 or 13)");
+
+ ctx.restore();
+ }
+}
diff --git a/libcairobarcode/error.vala b/libcairobarcode/error.vala
new file mode 100644
index 0000000..f81df91
--- /dev/null
+++ b/libcairobarcode/error.vala
@@ -0,0 +1,19 @@
+/* Copyright 2014, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public errordomain BarcodeError {
+ UNEXPECTED_CHARACTER,
+ UNEXPECTED_LENGTH
+}
diff --git a/libcairobarcode/test.vala b/libcairobarcode/test.vala
new file mode 100644
index 0000000..de42d80
--- /dev/null
+++ b/libcairobarcode/test.vala
@@ -0,0 +1,53 @@
+/* Copyright 2014, Sebastian Reichel <sre@ring0.de>
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+public static int main(string[] args) {
+ double width = 190.0;
+ double height = 40.0;
+
+ var surface = new Cairo.SvgSurface("test.svg", width, height);
+ var ctx = new Cairo.Context(surface);
+ var ean = new EAN(ctx, width, height);
+ var code39 = new Code39(ctx, width, height);
+
+ if(args.length < 3) {
+ stderr.printf("Usage: %s <ean|code39> <message>\n", args[0]);
+ return 1;
+ }
+
+ try {
+ switch(args[1]) {
+ case "ean":
+ ean.draw(args[2]);
+ break;
+ case "code39":
+ code39.draw(args[2]);
+ break;
+ default:
+ stderr.printf("Usage: %s <ean|code39> <message>\n", args[0]);
+ return 1;
+ }
+ } catch (BarcodeError e) {
+ stderr.printf(e.message + "\n");
+ }
+
+ /* cleanup */
+ code39 = null;
+ ean = null;
+ ctx = null;
+ surface = null;
+
+ return 0;
+ }