summaryrefslogtreecommitdiffstats
path: root/zbar/decoder/pdf417.c
diff options
context:
space:
mode:
Diffstat (limited to 'zbar/decoder/pdf417.c')
-rw-r--r--zbar/decoder/pdf417.c224
1 files changed, 224 insertions, 0 deletions
diff --git a/zbar/decoder/pdf417.c b/zbar/decoder/pdf417.c
new file mode 100644
index 0000000..436a7bd
--- /dev/null
+++ b/zbar/decoder/pdf417.c
@@ -0,0 +1,224 @@
+/*------------------------------------------------------------------------
+ * Copyright 2008-2010 (c) Jeff Brown <spadix@users.sourceforge.net>
+ *
+ * This file is part of the ZBar Bar Code Reader.
+ *
+ * The ZBar Bar Code Reader is free software; you can redistribute it
+ * and/or modify it under the terms of the GNU Lesser Public License as
+ * published by the Free Software Foundation; either version 2.1 of
+ * the License, or (at your option) any later version.
+ *
+ * The ZBar Bar Code Reader is distributed in the hope that it will be
+ * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Lesser Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser Public License
+ * along with the ZBar Bar Code Reader; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
+ * Boston, MA 02110-1301 USA
+ *
+ * http://sourceforge.net/projects/zbar
+ *------------------------------------------------------------------------*/
+
+#include "config.h"
+
+#include <zbar.h>
+
+#ifdef DEBUG_PDF417
+#define DEBUG_LEVEL (DEBUG_PDF417)
+#endif
+#include "debug.h"
+#include "decoder.h"
+
+#include "pdf417_hash.h"
+
+#define PDF417_STOP 0xbff
+
+static inline signed short pdf417_decode8(zbar_decoder_t *dcode)
+{
+ long sig = 0;
+ signed char e;
+ unsigned char i;
+ int clst;
+ signed short g[3];
+ unsigned short c;
+ /* build edge signature of character
+ * from similar edge measurements
+ */
+ unsigned s = dcode->pdf417.s8;
+ dbprintf(2, " s=%d ", s);
+ if (s < 8)
+ return (-1);
+
+ for (i = 0; i < 7; i++) {
+ if (get_color(dcode) == ZBAR_SPACE)
+ e = decode_e(get_width(dcode, i) + get_width(dcode, i + 1), s, 17);
+ else
+ e = decode_e(get_width(dcode, 7 - i) + get_width(dcode, 6 - i), s,
+ 17);
+ dbprintf(4, "%x", e);
+ if (e < 0 || e > 8)
+ return (-1);
+ sig = (sig << 3) ^ e;
+ }
+ dbprintf(2, " sig=%06lx", sig);
+
+ /* determine cluster number */
+ clst =
+ ((sig & 7) - ((sig >> 3) & 7) + ((sig >> 12) & 7) - ((sig >> 15) & 7));
+ if (clst < 0)
+ clst += 9;
+ dbprintf(2, " k=%d", clst);
+ zassert(clst >= 0 && clst < 9, -1, "dir=%x sig=%lx k=%x %s\n",
+ dcode->pdf417.direction, sig, clst,
+ _zbar_decoder_buf_dump(dcode->buf, dcode->pdf417.character));
+
+ if (clst != 0 && clst != 3 && clst != 6) {
+ if (get_color(dcode) && clst == 7 && sig == 0x080007)
+ return (PDF417_STOP);
+ return (-1);
+ }
+
+ sig &= 0x3ffff;
+ g[0] = pdf417_hash[(sig - (sig >> 10)) & PDF417_HASH_MASK];
+ g[1] = pdf417_hash[((sig >> 8) - sig) & PDF417_HASH_MASK];
+ g[2] = pdf417_hash[((sig >> 14) - (sig >> 1)) & PDF417_HASH_MASK];
+ zassert(g[0] >= 0 && g[1] >= 0 && g[2] >= 0, -1,
+ "dir=%x sig=%lx k=%x g0=%03x g1=%03x g2=%03x %s\n",
+ dcode->pdf417.direction, sig, clst, g[0], g[1], g[2],
+ _zbar_decoder_buf_dump(dcode->buf, dcode->pdf417.character));
+
+ c = (g[0] + g[1] + g[2]) & PDF417_HASH_MASK;
+ dbprintf(2, " g0=%x g1=%x g2=%x c=%03d(%d)", g[0], g[1], g[2], c & 0x3ff,
+ c >> 10);
+ return (c);
+}
+
+static inline signed char pdf417_decode_start(zbar_decoder_t *dcode)
+{
+ int ei, ex;
+ pdf417_decoder_t *dcode417;
+ unsigned s = dcode->pdf417.s8;
+ if (s < 8)
+ return (0);
+
+ ei = decode_e(get_width(dcode, 0) + get_width(dcode, 1), s, 17);
+ ex = (get_color(dcode) == ZBAR_SPACE) ? 2 : 6;
+ if (ei != ex)
+ return (0);
+
+ ei = decode_e(get_width(dcode, 1) + get_width(dcode, 2), s, 17);
+ if (ei)
+ return (0);
+
+ ei = decode_e(get_width(dcode, 2) + get_width(dcode, 3), s, 17);
+ ex = (get_color(dcode) == ZBAR_SPACE) ? 0 : 2;
+ if (ei != ex)
+ return (0);
+
+ ei = decode_e(get_width(dcode, 3) + get_width(dcode, 4), s, 17);
+ ex = (get_color(dcode) == ZBAR_SPACE) ? 0 : 2;
+ if (ei != ex)
+ return (0);
+
+ ei = decode_e(get_width(dcode, 4) + get_width(dcode, 5), s, 17);
+ if (ei)
+ return (0);
+
+ ei = decode_e(get_width(dcode, 5) + get_width(dcode, 6), s, 17);
+ if (ei)
+ return (0);
+
+ ei = decode_e(get_width(dcode, 6) + get_width(dcode, 7), s, 17);
+ ex = (get_color(dcode) == ZBAR_SPACE) ? 7 : 1;
+ if (ei != ex)
+ return (0);
+
+ ei = decode_e(get_width(dcode, 7) + get_width(dcode, 8), s, 17);
+ ex = (get_color(dcode) == ZBAR_SPACE) ? 8 : 1;
+
+ if (get_color(dcode) == ZBAR_BAR) {
+ /* stop character has extra bar */
+ if (ei != 1)
+ return (0);
+ ei = decode_e(get_width(dcode, 8) + get_width(dcode, 9), s, 17);
+ }
+
+ dbprintf(2, " pdf417[%c]: s=%d", (get_color(dcode)) ? '<' : '>', s);
+
+ /* check quiet zone */
+ if (ei >= 0 && ei < ex) {
+ dbprintf(2, " [invalid quiet]\n");
+ return (0);
+ }
+
+ /* lock shared resources */
+ if (acquire_lock(dcode, ZBAR_PDF417)) {
+ dbprintf(2, " [locked %d]\n", dcode->lock);
+ return (0);
+ }
+
+ dcode417 = &dcode->pdf417;
+ dcode417->direction = get_color(dcode);
+ dcode417->element = 0;
+ dcode417->character = 0;
+
+ dbprintf(2, " [valid start]\n");
+ return (ZBAR_PARTIAL);
+}
+
+zbar_symbol_type_t _zbar_decode_pdf417(zbar_decoder_t *dcode)
+{
+ signed short c;
+ pdf417_decoder_t *dcode417 = &dcode->pdf417;
+
+ /* update latest character width */
+ dcode417->s8 -= get_width(dcode, 8);
+ dcode417->s8 += get_width(dcode, 0);
+
+ if (dcode417->character < 0) {
+ pdf417_decode_start(dcode);
+ dbprintf(4, "\n");
+ return (0);
+ }
+
+ /* process every 8th element of active symbol */
+ if (++dcode417->element)
+ return (0);
+ dcode417->element = 0;
+
+ dbprintf(2, " pdf417[%c%02d]:", (dcode417->direction) ? '<' : '>',
+ dcode417->character);
+
+ if (get_color(dcode) != dcode417->direction) {
+ int c = dcode417->character;
+ release_lock(dcode, ZBAR_PDF417);
+ dcode417->character = -1;
+ zassert(get_color(dcode) == dcode417->direction, ZBAR_NONE,
+ "color=%x dir=%x char=%d elem=0 %s\n", get_color(dcode),
+ dcode417->direction, c, _zbar_decoder_buf_dump(dcode->buf, c));
+ }
+
+ c = pdf417_decode8(dcode);
+ if (c < 0 || size_buf(dcode, dcode417->character + 1)) {
+ dbprintf(1, (c < 0) ? " [aborted]\n" : " [overflow]\n");
+ release_lock(dcode, ZBAR_PDF417);
+ dcode417->character = -1;
+ return (0);
+ }
+
+ /* FIXME TBD infer dimensions, save codewords */
+
+ if (c == PDF417_STOP) {
+ dbprintf(1, " [valid stop]");
+ /* FIXME check trailing bar and qz */
+ dcode->direction = 1 - 2 * dcode417->direction;
+ dcode->modifiers = 0;
+ release_lock(dcode, ZBAR_PDF417);
+ dcode417->character = -1;
+ }
+
+ dbprintf(2, "\n");
+ return (0);
+}