ZBar bar code reader . http://zbar.sourceforge.net/ ZBar is licensed under the GNU LGPL 2.1 to enable development of both open source and commercial projects.

Dependents:   GR-PEACH_Camera_in_barcode levkov_ov7670

LICENSE

The ZBar Bar Code Reader is Copyright (C) 2007-2009 Jeff Brown <spadix@users.sourceforge.net> The QR Code reader is Copyright (C) 1999-2009 Timothy B. Terriberry <tterribe@xiph.org>

You can redistribute this library and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library 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 General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA

ISAAC is based on the public domain implementation by Robert J. Jenkins Jr., and is itself public domain.

Portions of the bit stream reader are copyright (C) The Xiph.Org Foundation 1994-2008, and are licensed under a BSD-style license.

The Reed-Solomon decoder is derived from an implementation (C) 1991-1995 Henry Minsky (hqm@ua.com, hqm@ai.mit.edu), and is licensed under the LGPL with permission.

Committer:
RyoheiHagimoto
Date:
Tue Apr 19 02:19:39 2016 +0000
Revision:
1:500d42699c34
Parent:
0:56c5742b9e2b
Add copying.txt and license.txt

Who changed what in which revision?

UserRevisionLine numberNew contents of line
RyoheiHagimoto 0:56c5742b9e2b 1 /*------------------------------------------------------------------------
RyoheiHagimoto 0:56c5742b9e2b 2 * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net>
RyoheiHagimoto 0:56c5742b9e2b 3 *
RyoheiHagimoto 0:56c5742b9e2b 4 * This file is part of the ZBar Bar Code Reader.
RyoheiHagimoto 0:56c5742b9e2b 5 *
RyoheiHagimoto 0:56c5742b9e2b 6 * The ZBar Bar Code Reader is free software; you can redistribute it
RyoheiHagimoto 0:56c5742b9e2b 7 * and/or modify it under the terms of the GNU Lesser Public License as
RyoheiHagimoto 0:56c5742b9e2b 8 * published by the Free Software Foundation; either version 2.1 of
RyoheiHagimoto 0:56c5742b9e2b 9 * the License, or (at your option) any later version.
RyoheiHagimoto 0:56c5742b9e2b 10 *
RyoheiHagimoto 0:56c5742b9e2b 11 * The ZBar Bar Code Reader is distributed in the hope that it will be
RyoheiHagimoto 0:56c5742b9e2b 12 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty
RyoheiHagimoto 0:56c5742b9e2b 13 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
RyoheiHagimoto 0:56c5742b9e2b 14 * GNU Lesser Public License for more details.
RyoheiHagimoto 0:56c5742b9e2b 15 *
RyoheiHagimoto 0:56c5742b9e2b 16 * You should have received a copy of the GNU Lesser Public License
RyoheiHagimoto 0:56c5742b9e2b 17 * along with the ZBar Bar Code Reader; if not, write to the Free
RyoheiHagimoto 0:56c5742b9e2b 18 * Software Foundation, Inc., 51 Franklin St, Fifth Floor,
RyoheiHagimoto 0:56c5742b9e2b 19 * Boston, MA 02110-1301 USA
RyoheiHagimoto 0:56c5742b9e2b 20 *
RyoheiHagimoto 0:56c5742b9e2b 21 * http://sourceforge.net/projects/zbar
RyoheiHagimoto 0:56c5742b9e2b 22 *------------------------------------------------------------------------*/
RyoheiHagimoto 0:56c5742b9e2b 23
RyoheiHagimoto 0:56c5742b9e2b 24 #include <config.h>
RyoheiHagimoto 0:56c5742b9e2b 25 #if (0) // not used
RyoheiHagimoto 0:56c5742b9e2b 26 #include <unistd.h>
RyoheiHagimoto 0:56c5742b9e2b 27 #endif
RyoheiHagimoto 0:56c5742b9e2b 28 #ifdef HAVE_INTTYPES_H
RyoheiHagimoto 0:56c5742b9e2b 29 # include <inttypes.h>
RyoheiHagimoto 0:56c5742b9e2b 30 #endif
RyoheiHagimoto 0:56c5742b9e2b 31 #include <stdlib.h> /* malloc, free */
RyoheiHagimoto 0:56c5742b9e2b 32 #include <time.h> /* clock_gettime */
RyoheiHagimoto 0:56c5742b9e2b 33 #if (0) // not used
RyoheiHagimoto 0:56c5742b9e2b 34 #include <sys/time.h> /* gettimeofday */
RyoheiHagimoto 0:56c5742b9e2b 35 #endif
RyoheiHagimoto 0:56c5742b9e2b 36 #include <string.h> /* memcmp, memset, memcpy */
RyoheiHagimoto 0:56c5742b9e2b 37 #include <assert.h>
RyoheiHagimoto 0:56c5742b9e2b 38
RyoheiHagimoto 0:56c5742b9e2b 39 #include <zbar.h>
RyoheiHagimoto 0:56c5742b9e2b 40 #include "error.h"
RyoheiHagimoto 0:56c5742b9e2b 41 #include "image.h"
RyoheiHagimoto 0:56c5742b9e2b 42 #ifdef ENABLE_QRCODE
RyoheiHagimoto 0:56c5742b9e2b 43 # include "qrcode.h"
RyoheiHagimoto 0:56c5742b9e2b 44 #endif
RyoheiHagimoto 0:56c5742b9e2b 45 #include "img_scanner.h"
RyoheiHagimoto 0:56c5742b9e2b 46 #include "svg.h"
RyoheiHagimoto 0:56c5742b9e2b 47
RyoheiHagimoto 0:56c5742b9e2b 48 #if 1
RyoheiHagimoto 0:56c5742b9e2b 49 # define ASSERT_POS \
RyoheiHagimoto 0:56c5742b9e2b 50 assert(p == data + x + y * (intptr_t)w)
RyoheiHagimoto 0:56c5742b9e2b 51 #else
RyoheiHagimoto 0:56c5742b9e2b 52 # define ASSERT_POS
RyoheiHagimoto 0:56c5742b9e2b 53 #endif
RyoheiHagimoto 0:56c5742b9e2b 54
RyoheiHagimoto 0:56c5742b9e2b 55 /* FIXME cache setting configurability */
RyoheiHagimoto 0:56c5742b9e2b 56
RyoheiHagimoto 0:56c5742b9e2b 57 /* number of times the same result must be detected
RyoheiHagimoto 0:56c5742b9e2b 58 * in "nearby" images before being reported
RyoheiHagimoto 0:56c5742b9e2b 59 */
RyoheiHagimoto 0:56c5742b9e2b 60 #define CACHE_CONSISTENCY 3 /* images */
RyoheiHagimoto 0:56c5742b9e2b 61
RyoheiHagimoto 0:56c5742b9e2b 62 /* time interval for which two images are considered "nearby"
RyoheiHagimoto 0:56c5742b9e2b 63 */
RyoheiHagimoto 0:56c5742b9e2b 64 #define CACHE_PROXIMITY 1000 /* ms */
RyoheiHagimoto 0:56c5742b9e2b 65
RyoheiHagimoto 0:56c5742b9e2b 66 /* time that a result must *not* be detected before
RyoheiHagimoto 0:56c5742b9e2b 67 * it will be reported again
RyoheiHagimoto 0:56c5742b9e2b 68 */
RyoheiHagimoto 0:56c5742b9e2b 69 #define CACHE_HYSTERESIS 2000 /* ms */
RyoheiHagimoto 0:56c5742b9e2b 70
RyoheiHagimoto 0:56c5742b9e2b 71 /* time after which cache entries are invalidated
RyoheiHagimoto 0:56c5742b9e2b 72 */
RyoheiHagimoto 0:56c5742b9e2b 73 #define CACHE_TIMEOUT (CACHE_HYSTERESIS * 2) /* ms */
RyoheiHagimoto 0:56c5742b9e2b 74
RyoheiHagimoto 0:56c5742b9e2b 75 #define NUM_SCN_CFGS (ZBAR_CFG_Y_DENSITY - ZBAR_CFG_X_DENSITY + 1)
RyoheiHagimoto 0:56c5742b9e2b 76
RyoheiHagimoto 0:56c5742b9e2b 77 #define CFG(iscn, cfg) ((iscn)->configs[(cfg) - ZBAR_CFG_X_DENSITY])
RyoheiHagimoto 0:56c5742b9e2b 78 #define TEST_CFG(iscn, cfg) (((iscn)->config >> ((cfg) - ZBAR_CFG_POSITION)) & 1)
RyoheiHagimoto 0:56c5742b9e2b 79
RyoheiHagimoto 0:56c5742b9e2b 80 #ifndef NO_STATS
RyoheiHagimoto 0:56c5742b9e2b 81 # define STAT(x) iscn->stat_##x++
RyoheiHagimoto 0:56c5742b9e2b 82 #else
RyoheiHagimoto 0:56c5742b9e2b 83 # define STAT(...)
RyoheiHagimoto 0:56c5742b9e2b 84 # define dump_stats(...)
RyoheiHagimoto 0:56c5742b9e2b 85 #endif
RyoheiHagimoto 0:56c5742b9e2b 86
RyoheiHagimoto 0:56c5742b9e2b 87 #define RECYCLE_BUCKETS 5
RyoheiHagimoto 0:56c5742b9e2b 88
RyoheiHagimoto 0:56c5742b9e2b 89 typedef struct recycle_bucket_s {
RyoheiHagimoto 0:56c5742b9e2b 90 int nsyms;
RyoheiHagimoto 0:56c5742b9e2b 91 zbar_symbol_t *head;
RyoheiHagimoto 0:56c5742b9e2b 92 } recycle_bucket_t;
RyoheiHagimoto 0:56c5742b9e2b 93
RyoheiHagimoto 0:56c5742b9e2b 94 /* image scanner state */
RyoheiHagimoto 0:56c5742b9e2b 95 struct zbar_image_scanner_s {
RyoheiHagimoto 0:56c5742b9e2b 96 zbar_scanner_t *scn; /* associated linear intensity scanner */
RyoheiHagimoto 0:56c5742b9e2b 97 zbar_decoder_t *dcode; /* associated symbol decoder */
RyoheiHagimoto 0:56c5742b9e2b 98 #ifdef ENABLE_QRCODE
RyoheiHagimoto 0:56c5742b9e2b 99 qr_reader *qr; /* QR Code 2D reader */
RyoheiHagimoto 0:56c5742b9e2b 100 #endif
RyoheiHagimoto 0:56c5742b9e2b 101
RyoheiHagimoto 0:56c5742b9e2b 102 const void *userdata; /* application data */
RyoheiHagimoto 0:56c5742b9e2b 103 /* user result callback */
RyoheiHagimoto 0:56c5742b9e2b 104 zbar_image_data_handler_t *handler;
RyoheiHagimoto 0:56c5742b9e2b 105
RyoheiHagimoto 0:56c5742b9e2b 106 unsigned long time; /* scan start time */
RyoheiHagimoto 0:56c5742b9e2b 107 zbar_image_t *img; /* currently scanning image *root* */
RyoheiHagimoto 0:56c5742b9e2b 108 int dx, dy, du, umin, v; /* current scan direction */
RyoheiHagimoto 0:56c5742b9e2b 109 zbar_symbol_set_t *syms; /* previous decode results */
RyoheiHagimoto 0:56c5742b9e2b 110 /* recycled symbols in 4^n size buckets */
RyoheiHagimoto 0:56c5742b9e2b 111 recycle_bucket_t recycle[RECYCLE_BUCKETS];
RyoheiHagimoto 0:56c5742b9e2b 112
RyoheiHagimoto 0:56c5742b9e2b 113 int enable_cache; /* current result cache state */
RyoheiHagimoto 0:56c5742b9e2b 114 zbar_symbol_t *cache; /* inter-image result cache entries */
RyoheiHagimoto 0:56c5742b9e2b 115
RyoheiHagimoto 0:56c5742b9e2b 116 /* configuration settings */
RyoheiHagimoto 0:56c5742b9e2b 117 unsigned config; /* config flags */
RyoheiHagimoto 0:56c5742b9e2b 118 int configs[NUM_SCN_CFGS]; /* int valued configurations */
RyoheiHagimoto 0:56c5742b9e2b 119
RyoheiHagimoto 0:56c5742b9e2b 120 #ifndef NO_STATS
RyoheiHagimoto 0:56c5742b9e2b 121 int stat_syms_new;
RyoheiHagimoto 0:56c5742b9e2b 122 int stat_iscn_syms_inuse, stat_iscn_syms_recycle;
RyoheiHagimoto 0:56c5742b9e2b 123 int stat_img_syms_inuse, stat_img_syms_recycle;
RyoheiHagimoto 0:56c5742b9e2b 124 int stat_sym_new;
RyoheiHagimoto 0:56c5742b9e2b 125 int stat_sym_recycle[RECYCLE_BUCKETS];
RyoheiHagimoto 0:56c5742b9e2b 126 #endif
RyoheiHagimoto 0:56c5742b9e2b 127 };
RyoheiHagimoto 0:56c5742b9e2b 128
RyoheiHagimoto 0:56c5742b9e2b 129 void _zbar_image_scanner_recycle_syms (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 130 zbar_symbol_t *sym)
RyoheiHagimoto 0:56c5742b9e2b 131 {
RyoheiHagimoto 0:56c5742b9e2b 132 zbar_symbol_t *next = NULL;
RyoheiHagimoto 0:56c5742b9e2b 133 for(; sym; sym = next) {
RyoheiHagimoto 0:56c5742b9e2b 134 next = sym->next;
RyoheiHagimoto 0:56c5742b9e2b 135 if(sym->refcnt && _zbar_refcnt(&sym->refcnt, -1)) {
RyoheiHagimoto 0:56c5742b9e2b 136 /* unlink referenced symbol */
RyoheiHagimoto 0:56c5742b9e2b 137 /* FIXME handle outstanding component refs (currently unsupported)
RyoheiHagimoto 0:56c5742b9e2b 138 */
RyoheiHagimoto 0:56c5742b9e2b 139 assert(sym->data_alloc);
RyoheiHagimoto 0:56c5742b9e2b 140 sym->next = NULL;
RyoheiHagimoto 0:56c5742b9e2b 141 }
RyoheiHagimoto 0:56c5742b9e2b 142 else {
RyoheiHagimoto 0:56c5742b9e2b 143 /* recycle unreferenced symbol */
RyoheiHagimoto 0:56c5742b9e2b 144 if(!sym->data_alloc) {
RyoheiHagimoto 0:56c5742b9e2b 145 sym->data = NULL;
RyoheiHagimoto 0:56c5742b9e2b 146 sym->datalen = 0;
RyoheiHagimoto 0:56c5742b9e2b 147 }
RyoheiHagimoto 0:56c5742b9e2b 148 if(sym->syms) {
RyoheiHagimoto 0:56c5742b9e2b 149 if(_zbar_refcnt(&sym->syms->refcnt, -1))
RyoheiHagimoto 0:56c5742b9e2b 150 assert(0);
RyoheiHagimoto 0:56c5742b9e2b 151 _zbar_image_scanner_recycle_syms(iscn, sym->syms->head);
RyoheiHagimoto 0:56c5742b9e2b 152 sym->syms->head = NULL;
RyoheiHagimoto 0:56c5742b9e2b 153 _zbar_symbol_set_free(sym->syms);
RyoheiHagimoto 0:56c5742b9e2b 154 sym->syms = NULL;
RyoheiHagimoto 0:56c5742b9e2b 155 }
RyoheiHagimoto 0:56c5742b9e2b 156 int i;
RyoheiHagimoto 0:56c5742b9e2b 157 for(i = 0; i < RECYCLE_BUCKETS; i++)
RyoheiHagimoto 0:56c5742b9e2b 158 if(sym->data_alloc < 1 << (i * 2))
RyoheiHagimoto 0:56c5742b9e2b 159 break;
RyoheiHagimoto 0:56c5742b9e2b 160 if(i == RECYCLE_BUCKETS) {
RyoheiHagimoto 0:56c5742b9e2b 161 assert(sym->data);
RyoheiHagimoto 0:56c5742b9e2b 162 free(sym->data);
RyoheiHagimoto 0:56c5742b9e2b 163 sym->data = NULL;
RyoheiHagimoto 0:56c5742b9e2b 164 sym->data_alloc = 0;
RyoheiHagimoto 0:56c5742b9e2b 165 i = 0;
RyoheiHagimoto 0:56c5742b9e2b 166 }
RyoheiHagimoto 0:56c5742b9e2b 167 recycle_bucket_t *bucket = &iscn->recycle[i];
RyoheiHagimoto 0:56c5742b9e2b 168 /* FIXME cap bucket fill */
RyoheiHagimoto 0:56c5742b9e2b 169 bucket->nsyms++;
RyoheiHagimoto 0:56c5742b9e2b 170 sym->next = bucket->head;
RyoheiHagimoto 0:56c5742b9e2b 171 bucket->head = sym;
RyoheiHagimoto 0:56c5742b9e2b 172 }
RyoheiHagimoto 0:56c5742b9e2b 173 }
RyoheiHagimoto 0:56c5742b9e2b 174 }
RyoheiHagimoto 0:56c5742b9e2b 175
RyoheiHagimoto 0:56c5742b9e2b 176 static inline int recycle_syms (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 177 zbar_symbol_set_t *syms)
RyoheiHagimoto 0:56c5742b9e2b 178 {
RyoheiHagimoto 0:56c5742b9e2b 179 if(_zbar_refcnt(&syms->refcnt, -1))
RyoheiHagimoto 0:56c5742b9e2b 180 return(1);
RyoheiHagimoto 0:56c5742b9e2b 181
RyoheiHagimoto 0:56c5742b9e2b 182 _zbar_image_scanner_recycle_syms(iscn, syms->head);
RyoheiHagimoto 0:56c5742b9e2b 183 syms->head = syms->tail = NULL;
RyoheiHagimoto 0:56c5742b9e2b 184 syms->nsyms = 0;
RyoheiHagimoto 0:56c5742b9e2b 185 return(0);
RyoheiHagimoto 0:56c5742b9e2b 186 }
RyoheiHagimoto 0:56c5742b9e2b 187
RyoheiHagimoto 0:56c5742b9e2b 188 inline void zbar_image_scanner_recycle_image (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 189 zbar_image_t *img)
RyoheiHagimoto 0:56c5742b9e2b 190 {
RyoheiHagimoto 0:56c5742b9e2b 191 zbar_symbol_set_t *syms = iscn->syms;
RyoheiHagimoto 0:56c5742b9e2b 192 if(syms && syms->refcnt) {
RyoheiHagimoto 0:56c5742b9e2b 193 if(recycle_syms(iscn, syms)) {
RyoheiHagimoto 0:56c5742b9e2b 194 STAT(iscn_syms_inuse);
RyoheiHagimoto 0:56c5742b9e2b 195 iscn->syms = NULL;
RyoheiHagimoto 0:56c5742b9e2b 196 }
RyoheiHagimoto 0:56c5742b9e2b 197 else
RyoheiHagimoto 0:56c5742b9e2b 198 STAT(iscn_syms_recycle);
RyoheiHagimoto 0:56c5742b9e2b 199 }
RyoheiHagimoto 0:56c5742b9e2b 200
RyoheiHagimoto 0:56c5742b9e2b 201 syms = img->syms;
RyoheiHagimoto 0:56c5742b9e2b 202 img->syms = NULL;
RyoheiHagimoto 0:56c5742b9e2b 203 if(syms && recycle_syms(iscn, syms)) {
RyoheiHagimoto 0:56c5742b9e2b 204 STAT(img_syms_inuse);
RyoheiHagimoto 0:56c5742b9e2b 205 syms = iscn->syms;
RyoheiHagimoto 0:56c5742b9e2b 206 }
RyoheiHagimoto 0:56c5742b9e2b 207 else if(syms) {
RyoheiHagimoto 0:56c5742b9e2b 208 STAT(img_syms_recycle);
RyoheiHagimoto 0:56c5742b9e2b 209
RyoheiHagimoto 0:56c5742b9e2b 210 /* select one set to resurrect, destroy the other */
RyoheiHagimoto 0:56c5742b9e2b 211 if(iscn->syms) {
RyoheiHagimoto 0:56c5742b9e2b 212 _zbar_symbol_set_free(syms);
RyoheiHagimoto 0:56c5742b9e2b 213 syms = iscn->syms;
RyoheiHagimoto 0:56c5742b9e2b 214 }
RyoheiHagimoto 0:56c5742b9e2b 215 else
RyoheiHagimoto 0:56c5742b9e2b 216 iscn->syms = syms;
RyoheiHagimoto 0:56c5742b9e2b 217 }
RyoheiHagimoto 0:56c5742b9e2b 218 }
RyoheiHagimoto 0:56c5742b9e2b 219
RyoheiHagimoto 0:56c5742b9e2b 220 inline zbar_symbol_t*
RyoheiHagimoto 0:56c5742b9e2b 221 _zbar_image_scanner_alloc_sym (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 222 zbar_symbol_type_t type,
RyoheiHagimoto 0:56c5742b9e2b 223 int datalen)
RyoheiHagimoto 0:56c5742b9e2b 224 {
RyoheiHagimoto 0:56c5742b9e2b 225 /* recycle old or alloc new symbol */
RyoheiHagimoto 0:56c5742b9e2b 226 int i;
RyoheiHagimoto 0:56c5742b9e2b 227 for(i = 0; i < RECYCLE_BUCKETS - 1; i++)
RyoheiHagimoto 0:56c5742b9e2b 228 if(datalen <= 1 << (i * 2))
RyoheiHagimoto 0:56c5742b9e2b 229 break;
RyoheiHagimoto 0:56c5742b9e2b 230
RyoheiHagimoto 0:56c5742b9e2b 231 zbar_symbol_t *sym = NULL;
RyoheiHagimoto 0:56c5742b9e2b 232 for(; i > 0; i--)
RyoheiHagimoto 0:56c5742b9e2b 233 if((sym = iscn->recycle[i].head)) {
RyoheiHagimoto 0:56c5742b9e2b 234 STAT(sym_recycle[i]);
RyoheiHagimoto 0:56c5742b9e2b 235 break;
RyoheiHagimoto 0:56c5742b9e2b 236 }
RyoheiHagimoto 0:56c5742b9e2b 237
RyoheiHagimoto 0:56c5742b9e2b 238 if(sym) {
RyoheiHagimoto 0:56c5742b9e2b 239 iscn->recycle[i].head = sym->next;
RyoheiHagimoto 0:56c5742b9e2b 240 sym->next = NULL;
RyoheiHagimoto 0:56c5742b9e2b 241 assert(iscn->recycle[i].nsyms);
RyoheiHagimoto 0:56c5742b9e2b 242 iscn->recycle[i].nsyms--;
RyoheiHagimoto 0:56c5742b9e2b 243 }
RyoheiHagimoto 0:56c5742b9e2b 244 else {
RyoheiHagimoto 0:56c5742b9e2b 245 sym = calloc(1, sizeof(zbar_symbol_t));
RyoheiHagimoto 0:56c5742b9e2b 246 STAT(sym_new);
RyoheiHagimoto 0:56c5742b9e2b 247 }
RyoheiHagimoto 0:56c5742b9e2b 248
RyoheiHagimoto 0:56c5742b9e2b 249 /* init new symbol */
RyoheiHagimoto 0:56c5742b9e2b 250 sym->type = type;
RyoheiHagimoto 0:56c5742b9e2b 251 sym->quality = 1;
RyoheiHagimoto 0:56c5742b9e2b 252 sym->npts = 0;
RyoheiHagimoto 0:56c5742b9e2b 253 sym->cache_count = 0;
RyoheiHagimoto 0:56c5742b9e2b 254 sym->time = iscn->time;
RyoheiHagimoto 0:56c5742b9e2b 255 assert(!sym->syms);
RyoheiHagimoto 0:56c5742b9e2b 256
RyoheiHagimoto 0:56c5742b9e2b 257 if(datalen > 0) {
RyoheiHagimoto 0:56c5742b9e2b 258 sym->datalen = datalen - 1;
RyoheiHagimoto 0:56c5742b9e2b 259 if(sym->data_alloc < datalen) {
RyoheiHagimoto 0:56c5742b9e2b 260 if(sym->data)
RyoheiHagimoto 0:56c5742b9e2b 261 free(sym->data);
RyoheiHagimoto 0:56c5742b9e2b 262 sym->data_alloc = datalen;
RyoheiHagimoto 0:56c5742b9e2b 263 sym->data = malloc(datalen);
RyoheiHagimoto 0:56c5742b9e2b 264 }
RyoheiHagimoto 0:56c5742b9e2b 265 }
RyoheiHagimoto 0:56c5742b9e2b 266 else {
RyoheiHagimoto 0:56c5742b9e2b 267 if(sym->data)
RyoheiHagimoto 0:56c5742b9e2b 268 free(sym->data);
RyoheiHagimoto 0:56c5742b9e2b 269 sym->data = NULL;
RyoheiHagimoto 0:56c5742b9e2b 270 sym->datalen = sym->data_alloc = 0;
RyoheiHagimoto 0:56c5742b9e2b 271 }
RyoheiHagimoto 0:56c5742b9e2b 272 return(sym);
RyoheiHagimoto 0:56c5742b9e2b 273 }
RyoheiHagimoto 0:56c5742b9e2b 274
RyoheiHagimoto 0:56c5742b9e2b 275 static inline zbar_symbol_t *cache_lookup (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 276 zbar_symbol_t *sym)
RyoheiHagimoto 0:56c5742b9e2b 277 {
RyoheiHagimoto 0:56c5742b9e2b 278 /* search for matching entry in cache */
RyoheiHagimoto 0:56c5742b9e2b 279 zbar_symbol_t **entry = &iscn->cache;
RyoheiHagimoto 0:56c5742b9e2b 280 while(*entry) {
RyoheiHagimoto 0:56c5742b9e2b 281 if((*entry)->type == sym->type &&
RyoheiHagimoto 0:56c5742b9e2b 282 (*entry)->datalen == sym->datalen &&
RyoheiHagimoto 0:56c5742b9e2b 283 !memcmp((*entry)->data, sym->data, sym->datalen))
RyoheiHagimoto 0:56c5742b9e2b 284 break;
RyoheiHagimoto 0:56c5742b9e2b 285 if((sym->time - (*entry)->time) > CACHE_TIMEOUT) {
RyoheiHagimoto 0:56c5742b9e2b 286 /* recycle stale cache entry */
RyoheiHagimoto 0:56c5742b9e2b 287 zbar_symbol_t *next = (*entry)->next;
RyoheiHagimoto 0:56c5742b9e2b 288 (*entry)->next = NULL;
RyoheiHagimoto 0:56c5742b9e2b 289 _zbar_image_scanner_recycle_syms(iscn, *entry);
RyoheiHagimoto 0:56c5742b9e2b 290 *entry = next;
RyoheiHagimoto 0:56c5742b9e2b 291 }
RyoheiHagimoto 0:56c5742b9e2b 292 else
RyoheiHagimoto 0:56c5742b9e2b 293 entry = &(*entry)->next;
RyoheiHagimoto 0:56c5742b9e2b 294 }
RyoheiHagimoto 0:56c5742b9e2b 295 return(*entry);
RyoheiHagimoto 0:56c5742b9e2b 296 }
RyoheiHagimoto 0:56c5742b9e2b 297
RyoheiHagimoto 0:56c5742b9e2b 298 static inline void cache_sym (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 299 zbar_symbol_t *sym)
RyoheiHagimoto 0:56c5742b9e2b 300 {
RyoheiHagimoto 0:56c5742b9e2b 301 if(iscn->enable_cache) {
RyoheiHagimoto 0:56c5742b9e2b 302 zbar_symbol_t *entry = cache_lookup(iscn, sym);
RyoheiHagimoto 0:56c5742b9e2b 303 if(!entry) {
RyoheiHagimoto 0:56c5742b9e2b 304 /* FIXME reuse sym */
RyoheiHagimoto 0:56c5742b9e2b 305 entry = _zbar_image_scanner_alloc_sym(iscn, sym->type,
RyoheiHagimoto 0:56c5742b9e2b 306 sym->datalen + 1);
RyoheiHagimoto 0:56c5742b9e2b 307 memcpy(entry->data, sym->data, sym->datalen);
RyoheiHagimoto 0:56c5742b9e2b 308 entry->time = sym->time - CACHE_HYSTERESIS;
RyoheiHagimoto 0:56c5742b9e2b 309 entry->cache_count = -CACHE_CONSISTENCY;
RyoheiHagimoto 0:56c5742b9e2b 310 /* add to cache */
RyoheiHagimoto 0:56c5742b9e2b 311 entry->next = iscn->cache;
RyoheiHagimoto 0:56c5742b9e2b 312 iscn->cache = entry;
RyoheiHagimoto 0:56c5742b9e2b 313 }
RyoheiHagimoto 0:56c5742b9e2b 314
RyoheiHagimoto 0:56c5742b9e2b 315 /* consistency check and hysteresis */
RyoheiHagimoto 0:56c5742b9e2b 316 uint32_t age = sym->time - entry->time;
RyoheiHagimoto 0:56c5742b9e2b 317 entry->time = sym->time;
RyoheiHagimoto 0:56c5742b9e2b 318 int near_thresh = (age < CACHE_PROXIMITY);
RyoheiHagimoto 0:56c5742b9e2b 319 int far_thresh = (age >= CACHE_HYSTERESIS);
RyoheiHagimoto 0:56c5742b9e2b 320 int dup = (entry->cache_count >= 0);
RyoheiHagimoto 0:56c5742b9e2b 321 if((!dup && !near_thresh) || far_thresh)
RyoheiHagimoto 0:56c5742b9e2b 322 entry->cache_count = -CACHE_CONSISTENCY;
RyoheiHagimoto 0:56c5742b9e2b 323 else if(dup || near_thresh)
RyoheiHagimoto 0:56c5742b9e2b 324 entry->cache_count++;
RyoheiHagimoto 0:56c5742b9e2b 325
RyoheiHagimoto 0:56c5742b9e2b 326 sym->cache_count = entry->cache_count;
RyoheiHagimoto 0:56c5742b9e2b 327 }
RyoheiHagimoto 0:56c5742b9e2b 328 else
RyoheiHagimoto 0:56c5742b9e2b 329 sym->cache_count = 0;
RyoheiHagimoto 0:56c5742b9e2b 330 }
RyoheiHagimoto 0:56c5742b9e2b 331
RyoheiHagimoto 0:56c5742b9e2b 332 void _zbar_image_scanner_add_sym(zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 333 zbar_symbol_t *sym)
RyoheiHagimoto 0:56c5742b9e2b 334 {
RyoheiHagimoto 0:56c5742b9e2b 335 cache_sym(iscn, sym);
RyoheiHagimoto 0:56c5742b9e2b 336
RyoheiHagimoto 0:56c5742b9e2b 337 zbar_symbol_set_t *syms = iscn->syms;
RyoheiHagimoto 0:56c5742b9e2b 338 if(sym->cache_count || !syms->tail) {
RyoheiHagimoto 0:56c5742b9e2b 339 sym->next = syms->head;
RyoheiHagimoto 0:56c5742b9e2b 340 syms->head = sym;
RyoheiHagimoto 0:56c5742b9e2b 341 }
RyoheiHagimoto 0:56c5742b9e2b 342 else {
RyoheiHagimoto 0:56c5742b9e2b 343 sym->next = syms->tail->next;
RyoheiHagimoto 0:56c5742b9e2b 344 syms->tail->next = sym;
RyoheiHagimoto 0:56c5742b9e2b 345 }
RyoheiHagimoto 0:56c5742b9e2b 346
RyoheiHagimoto 0:56c5742b9e2b 347 if(!sym->cache_count)
RyoheiHagimoto 0:56c5742b9e2b 348 syms->nsyms++;
RyoheiHagimoto 0:56c5742b9e2b 349 else if(!syms->tail)
RyoheiHagimoto 0:56c5742b9e2b 350 syms->tail = sym;
RyoheiHagimoto 0:56c5742b9e2b 351
RyoheiHagimoto 0:56c5742b9e2b 352 _zbar_symbol_refcnt(sym, 1);
RyoheiHagimoto 0:56c5742b9e2b 353 }
RyoheiHagimoto 0:56c5742b9e2b 354
RyoheiHagimoto 0:56c5742b9e2b 355 #ifdef ENABLE_QRCODE
RyoheiHagimoto 0:56c5742b9e2b 356 extern qr_finder_line *_zbar_decoder_get_qr_finder_line(zbar_decoder_t*);
RyoheiHagimoto 0:56c5742b9e2b 357
RyoheiHagimoto 0:56c5742b9e2b 358 # define QR_FIXED(v, rnd) ((((v) << 1) + (rnd)) << (QR_FINDER_SUBPREC - 1))
RyoheiHagimoto 0:56c5742b9e2b 359 # define PRINT_FIXED(val, prec) \
RyoheiHagimoto 0:56c5742b9e2b 360 ((val) >> (prec)), \
RyoheiHagimoto 0:56c5742b9e2b 361 (1000 * ((val) & ((1 << (prec)) - 1)) / (1 << (prec)))
RyoheiHagimoto 0:56c5742b9e2b 362
RyoheiHagimoto 0:56c5742b9e2b 363 static inline void qr_handler (zbar_image_scanner_t *iscn)
RyoheiHagimoto 0:56c5742b9e2b 364 {
RyoheiHagimoto 0:56c5742b9e2b 365 qr_finder_line *line = _zbar_decoder_get_qr_finder_line(iscn->dcode);
RyoheiHagimoto 0:56c5742b9e2b 366 assert(line);
RyoheiHagimoto 0:56c5742b9e2b 367 unsigned u = zbar_scanner_get_edge(iscn->scn, line->pos[0],
RyoheiHagimoto 0:56c5742b9e2b 368 QR_FINDER_SUBPREC);
RyoheiHagimoto 0:56c5742b9e2b 369 line->boffs = u - zbar_scanner_get_edge(iscn->scn, line->boffs,
RyoheiHagimoto 0:56c5742b9e2b 370 QR_FINDER_SUBPREC);
RyoheiHagimoto 0:56c5742b9e2b 371 line->len = zbar_scanner_get_edge(iscn->scn, line->len,
RyoheiHagimoto 0:56c5742b9e2b 372 QR_FINDER_SUBPREC);
RyoheiHagimoto 0:56c5742b9e2b 373 line->eoffs = zbar_scanner_get_edge(iscn->scn, line->eoffs,
RyoheiHagimoto 0:56c5742b9e2b 374 QR_FINDER_SUBPREC) - line->len;
RyoheiHagimoto 0:56c5742b9e2b 375 line->len -= u;
RyoheiHagimoto 0:56c5742b9e2b 376
RyoheiHagimoto 0:56c5742b9e2b 377 u = QR_FIXED(iscn->umin, 0) + iscn->du * u;
RyoheiHagimoto 0:56c5742b9e2b 378 if(iscn->du < 0) {
RyoheiHagimoto 0:56c5742b9e2b 379 u -= line->len;
RyoheiHagimoto 0:56c5742b9e2b 380 int tmp = line->boffs;
RyoheiHagimoto 0:56c5742b9e2b 381 line->boffs = line->eoffs;
RyoheiHagimoto 0:56c5742b9e2b 382 line->eoffs = tmp;
RyoheiHagimoto 0:56c5742b9e2b 383 }
RyoheiHagimoto 0:56c5742b9e2b 384 int vert = !iscn->dx;
RyoheiHagimoto 0:56c5742b9e2b 385 line->pos[vert] = u;
RyoheiHagimoto 0:56c5742b9e2b 386 line->pos[!vert] = QR_FIXED(iscn->v, 1);
RyoheiHagimoto 0:56c5742b9e2b 387
RyoheiHagimoto 0:56c5742b9e2b 388 _zbar_qr_found_line(iscn->qr, vert, line);
RyoheiHagimoto 0:56c5742b9e2b 389 }
RyoheiHagimoto 0:56c5742b9e2b 390 #endif
RyoheiHagimoto 0:56c5742b9e2b 391
RyoheiHagimoto 0:56c5742b9e2b 392 static void symbol_handler (zbar_decoder_t *dcode)
RyoheiHagimoto 0:56c5742b9e2b 393 {
RyoheiHagimoto 0:56c5742b9e2b 394 zbar_image_scanner_t *iscn = zbar_decoder_get_userdata(dcode);
RyoheiHagimoto 0:56c5742b9e2b 395 zbar_symbol_type_t type = zbar_decoder_get_type(dcode);
RyoheiHagimoto 0:56c5742b9e2b 396 /* FIXME assert(type == ZBAR_PARTIAL) */
RyoheiHagimoto 0:56c5742b9e2b 397 /* FIXME debug flag to save/display all PARTIALs */
RyoheiHagimoto 0:56c5742b9e2b 398 if(type <= ZBAR_PARTIAL)
RyoheiHagimoto 0:56c5742b9e2b 399 return;
RyoheiHagimoto 0:56c5742b9e2b 400
RyoheiHagimoto 0:56c5742b9e2b 401 #ifdef ENABLE_QRCODE
RyoheiHagimoto 0:56c5742b9e2b 402 if(type == ZBAR_QRCODE) {
RyoheiHagimoto 0:56c5742b9e2b 403 qr_handler(iscn);
RyoheiHagimoto 0:56c5742b9e2b 404 return;
RyoheiHagimoto 0:56c5742b9e2b 405 }
RyoheiHagimoto 0:56c5742b9e2b 406 #else
RyoheiHagimoto 0:56c5742b9e2b 407 assert(type != ZBAR_QRCODE);
RyoheiHagimoto 0:56c5742b9e2b 408 #endif
RyoheiHagimoto 0:56c5742b9e2b 409
RyoheiHagimoto 0:56c5742b9e2b 410 const char *data = zbar_decoder_get_data(dcode);
RyoheiHagimoto 0:56c5742b9e2b 411 unsigned datalen = zbar_decoder_get_data_length(dcode);
RyoheiHagimoto 0:56c5742b9e2b 412
RyoheiHagimoto 0:56c5742b9e2b 413 int x = 0, y = 0;
RyoheiHagimoto 0:56c5742b9e2b 414 if(TEST_CFG(iscn, ZBAR_CFG_POSITION)) {
RyoheiHagimoto 0:56c5742b9e2b 415 /* tmp position fixup */
RyoheiHagimoto 0:56c5742b9e2b 416 int w = zbar_scanner_get_width(iscn->scn);
RyoheiHagimoto 0:56c5742b9e2b 417 int u = iscn->umin + iscn->du * zbar_scanner_get_edge(iscn->scn, w, 0);
RyoheiHagimoto 0:56c5742b9e2b 418 if(iscn->dx) {
RyoheiHagimoto 0:56c5742b9e2b 419 x = u;
RyoheiHagimoto 0:56c5742b9e2b 420 y = iscn->v;
RyoheiHagimoto 0:56c5742b9e2b 421 }
RyoheiHagimoto 0:56c5742b9e2b 422 else {
RyoheiHagimoto 0:56c5742b9e2b 423 x = iscn->v;
RyoheiHagimoto 0:56c5742b9e2b 424 y = u;
RyoheiHagimoto 0:56c5742b9e2b 425 }
RyoheiHagimoto 0:56c5742b9e2b 426 }
RyoheiHagimoto 0:56c5742b9e2b 427
RyoheiHagimoto 0:56c5742b9e2b 428 /* FIXME need better symbol matching */
RyoheiHagimoto 0:56c5742b9e2b 429 zbar_symbol_t *sym;
RyoheiHagimoto 0:56c5742b9e2b 430 for(sym = iscn->syms->head; sym; sym = sym->next)
RyoheiHagimoto 0:56c5742b9e2b 431 if(sym->type == type &&
RyoheiHagimoto 0:56c5742b9e2b 432 sym->datalen == datalen &&
RyoheiHagimoto 0:56c5742b9e2b 433 !memcmp(sym->data, data, datalen)) {
RyoheiHagimoto 0:56c5742b9e2b 434 sym->quality++;
RyoheiHagimoto 0:56c5742b9e2b 435 if(TEST_CFG(iscn, ZBAR_CFG_POSITION))
RyoheiHagimoto 0:56c5742b9e2b 436 /* add new point to existing set */
RyoheiHagimoto 0:56c5742b9e2b 437 /* FIXME should be polygon */
RyoheiHagimoto 0:56c5742b9e2b 438 sym_add_point(sym, x, y);
RyoheiHagimoto 0:56c5742b9e2b 439 return;
RyoheiHagimoto 0:56c5742b9e2b 440 }
RyoheiHagimoto 0:56c5742b9e2b 441
RyoheiHagimoto 0:56c5742b9e2b 442 sym = _zbar_image_scanner_alloc_sym(iscn, type, datalen + 1);
RyoheiHagimoto 0:56c5742b9e2b 443 /* FIXME grab decoder buffer */
RyoheiHagimoto 0:56c5742b9e2b 444 memcpy(sym->data, data, datalen + 1);
RyoheiHagimoto 0:56c5742b9e2b 445
RyoheiHagimoto 0:56c5742b9e2b 446 /* initialize first point */
RyoheiHagimoto 0:56c5742b9e2b 447 if(TEST_CFG(iscn, ZBAR_CFG_POSITION))
RyoheiHagimoto 0:56c5742b9e2b 448 sym_add_point(sym, x, y);
RyoheiHagimoto 0:56c5742b9e2b 449
RyoheiHagimoto 0:56c5742b9e2b 450 _zbar_image_scanner_add_sym(iscn, sym);
RyoheiHagimoto 0:56c5742b9e2b 451 }
RyoheiHagimoto 0:56c5742b9e2b 452
RyoheiHagimoto 0:56c5742b9e2b 453 zbar_image_scanner_t *zbar_image_scanner_create ()
RyoheiHagimoto 0:56c5742b9e2b 454 {
RyoheiHagimoto 0:56c5742b9e2b 455 zbar_image_scanner_t *iscn = calloc(1, sizeof(zbar_image_scanner_t));
RyoheiHagimoto 0:56c5742b9e2b 456 if(!iscn)
RyoheiHagimoto 0:56c5742b9e2b 457 return(NULL);
RyoheiHagimoto 0:56c5742b9e2b 458 iscn->dcode = zbar_decoder_create();
RyoheiHagimoto 0:56c5742b9e2b 459 iscn->scn = zbar_scanner_create(iscn->dcode);
RyoheiHagimoto 0:56c5742b9e2b 460 if(!iscn->dcode || !iscn->scn) {
RyoheiHagimoto 0:56c5742b9e2b 461 zbar_image_scanner_destroy(iscn);
RyoheiHagimoto 0:56c5742b9e2b 462 return(NULL);
RyoheiHagimoto 0:56c5742b9e2b 463 }
RyoheiHagimoto 0:56c5742b9e2b 464 zbar_decoder_set_userdata(iscn->dcode, iscn);
RyoheiHagimoto 0:56c5742b9e2b 465 zbar_decoder_set_handler(iscn->dcode, symbol_handler);
RyoheiHagimoto 0:56c5742b9e2b 466
RyoheiHagimoto 0:56c5742b9e2b 467 #ifdef ENABLE_QRCODE
RyoheiHagimoto 0:56c5742b9e2b 468 iscn->qr = _zbar_qr_create();
RyoheiHagimoto 0:56c5742b9e2b 469 #endif
RyoheiHagimoto 0:56c5742b9e2b 470
RyoheiHagimoto 0:56c5742b9e2b 471 /* apply default configuration */
RyoheiHagimoto 0:56c5742b9e2b 472 CFG(iscn, ZBAR_CFG_X_DENSITY) = 1;
RyoheiHagimoto 0:56c5742b9e2b 473 CFG(iscn, ZBAR_CFG_Y_DENSITY) = 1;
RyoheiHagimoto 0:56c5742b9e2b 474 zbar_image_scanner_set_config(iscn, 0, ZBAR_CFG_POSITION, 1);
RyoheiHagimoto 0:56c5742b9e2b 475 return(iscn);
RyoheiHagimoto 0:56c5742b9e2b 476 }
RyoheiHagimoto 0:56c5742b9e2b 477
RyoheiHagimoto 0:56c5742b9e2b 478 #ifndef NO_STATS
RyoheiHagimoto 0:56c5742b9e2b 479 static inline void dump_stats (const zbar_image_scanner_t *iscn)
RyoheiHagimoto 0:56c5742b9e2b 480 {
RyoheiHagimoto 0:56c5742b9e2b 481 zprintf(1, "symbol sets allocated = %-4d\n", iscn->stat_syms_new);
RyoheiHagimoto 0:56c5742b9e2b 482 zprintf(1, " scanner syms in use = %-4d\trecycled = %-4d\n",
RyoheiHagimoto 0:56c5742b9e2b 483 iscn->stat_iscn_syms_inuse, iscn->stat_iscn_syms_recycle);
RyoheiHagimoto 0:56c5742b9e2b 484 zprintf(1, " image syms in use = %-4d\trecycled = %-4d\n",
RyoheiHagimoto 0:56c5742b9e2b 485 iscn->stat_img_syms_inuse, iscn->stat_img_syms_recycle);
RyoheiHagimoto 0:56c5742b9e2b 486 zprintf(1, "symbols allocated = %-4d\n", iscn->stat_sym_new);
RyoheiHagimoto 0:56c5742b9e2b 487 int i;
RyoheiHagimoto 0:56c5742b9e2b 488 for(i = 0; i < RECYCLE_BUCKETS; i++)
RyoheiHagimoto 0:56c5742b9e2b 489 zprintf(1, " recycled[%d] = %-4d\n",
RyoheiHagimoto 0:56c5742b9e2b 490 i, iscn->stat_sym_recycle[i]);
RyoheiHagimoto 0:56c5742b9e2b 491 }
RyoheiHagimoto 0:56c5742b9e2b 492 #endif
RyoheiHagimoto 0:56c5742b9e2b 493
RyoheiHagimoto 0:56c5742b9e2b 494 void zbar_image_scanner_destroy (zbar_image_scanner_t *iscn)
RyoheiHagimoto 0:56c5742b9e2b 495 {
RyoheiHagimoto 0:56c5742b9e2b 496 dump_stats(iscn);
RyoheiHagimoto 0:56c5742b9e2b 497 if(iscn->syms) {
RyoheiHagimoto 0:56c5742b9e2b 498 if(iscn->syms->refcnt)
RyoheiHagimoto 0:56c5742b9e2b 499 zbar_symbol_set_ref(iscn->syms, -1);
RyoheiHagimoto 0:56c5742b9e2b 500 else
RyoheiHagimoto 0:56c5742b9e2b 501 _zbar_symbol_set_free(iscn->syms);
RyoheiHagimoto 0:56c5742b9e2b 502 iscn->syms = NULL;
RyoheiHagimoto 0:56c5742b9e2b 503 }
RyoheiHagimoto 0:56c5742b9e2b 504 if(iscn->scn)
RyoheiHagimoto 0:56c5742b9e2b 505 zbar_scanner_destroy(iscn->scn);
RyoheiHagimoto 0:56c5742b9e2b 506 iscn->scn = NULL;
RyoheiHagimoto 0:56c5742b9e2b 507 if(iscn->dcode)
RyoheiHagimoto 0:56c5742b9e2b 508 zbar_decoder_destroy(iscn->dcode);
RyoheiHagimoto 0:56c5742b9e2b 509 iscn->dcode = NULL;
RyoheiHagimoto 0:56c5742b9e2b 510 int i;
RyoheiHagimoto 0:56c5742b9e2b 511 for(i = 0; i < RECYCLE_BUCKETS; i++) {
RyoheiHagimoto 0:56c5742b9e2b 512 zbar_symbol_t *sym, *next;
RyoheiHagimoto 0:56c5742b9e2b 513 for(sym = iscn->recycle[i].head; sym; sym = next) {
RyoheiHagimoto 0:56c5742b9e2b 514 next = sym->next;
RyoheiHagimoto 0:56c5742b9e2b 515 _zbar_symbol_free(sym);
RyoheiHagimoto 0:56c5742b9e2b 516 }
RyoheiHagimoto 0:56c5742b9e2b 517 }
RyoheiHagimoto 0:56c5742b9e2b 518 #ifdef ENABLE_QRCODE
RyoheiHagimoto 0:56c5742b9e2b 519 if(iscn->qr) {
RyoheiHagimoto 0:56c5742b9e2b 520 _zbar_qr_destroy(iscn->qr);
RyoheiHagimoto 0:56c5742b9e2b 521 iscn->qr = NULL;
RyoheiHagimoto 0:56c5742b9e2b 522 }
RyoheiHagimoto 0:56c5742b9e2b 523 #endif
RyoheiHagimoto 0:56c5742b9e2b 524 free(iscn);
RyoheiHagimoto 0:56c5742b9e2b 525 }
RyoheiHagimoto 0:56c5742b9e2b 526
RyoheiHagimoto 0:56c5742b9e2b 527 zbar_image_data_handler_t*
RyoheiHagimoto 0:56c5742b9e2b 528 zbar_image_scanner_set_data_handler (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 529 zbar_image_data_handler_t *handler,
RyoheiHagimoto 0:56c5742b9e2b 530 const void *userdata)
RyoheiHagimoto 0:56c5742b9e2b 531 {
RyoheiHagimoto 0:56c5742b9e2b 532 zbar_image_data_handler_t *result = iscn->handler;
RyoheiHagimoto 0:56c5742b9e2b 533 iscn->handler = handler;
RyoheiHagimoto 0:56c5742b9e2b 534 iscn->userdata = userdata;
RyoheiHagimoto 0:56c5742b9e2b 535 return(result);
RyoheiHagimoto 0:56c5742b9e2b 536 }
RyoheiHagimoto 0:56c5742b9e2b 537
RyoheiHagimoto 0:56c5742b9e2b 538 int zbar_image_scanner_set_config (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 539 zbar_symbol_type_t sym,
RyoheiHagimoto 0:56c5742b9e2b 540 zbar_config_t cfg,
RyoheiHagimoto 0:56c5742b9e2b 541 int val)
RyoheiHagimoto 0:56c5742b9e2b 542 {
RyoheiHagimoto 0:56c5742b9e2b 543 if(cfg < ZBAR_CFG_POSITION)
RyoheiHagimoto 0:56c5742b9e2b 544 return(zbar_decoder_set_config(iscn->dcode, sym, cfg, val));
RyoheiHagimoto 0:56c5742b9e2b 545
RyoheiHagimoto 0:56c5742b9e2b 546 if(sym > ZBAR_PARTIAL)
RyoheiHagimoto 0:56c5742b9e2b 547 return(1);
RyoheiHagimoto 0:56c5742b9e2b 548
RyoheiHagimoto 0:56c5742b9e2b 549 if(cfg >= ZBAR_CFG_X_DENSITY && cfg <= ZBAR_CFG_Y_DENSITY) {
RyoheiHagimoto 0:56c5742b9e2b 550
RyoheiHagimoto 0:56c5742b9e2b 551 CFG(iscn, cfg) = val;
RyoheiHagimoto 0:56c5742b9e2b 552 return(0);
RyoheiHagimoto 0:56c5742b9e2b 553 }
RyoheiHagimoto 0:56c5742b9e2b 554
RyoheiHagimoto 0:56c5742b9e2b 555 if(cfg > ZBAR_CFG_POSITION)
RyoheiHagimoto 0:56c5742b9e2b 556 return(1);
RyoheiHagimoto 0:56c5742b9e2b 557 cfg -= ZBAR_CFG_POSITION;
RyoheiHagimoto 0:56c5742b9e2b 558
RyoheiHagimoto 0:56c5742b9e2b 559 if(!val)
RyoheiHagimoto 0:56c5742b9e2b 560 iscn->config &= ~(1 << cfg);
RyoheiHagimoto 0:56c5742b9e2b 561 else if(val == 1)
RyoheiHagimoto 0:56c5742b9e2b 562 iscn->config |= (1 << cfg);
RyoheiHagimoto 0:56c5742b9e2b 563 else
RyoheiHagimoto 0:56c5742b9e2b 564 return(1);
RyoheiHagimoto 0:56c5742b9e2b 565
RyoheiHagimoto 0:56c5742b9e2b 566 return(0);
RyoheiHagimoto 0:56c5742b9e2b 567 }
RyoheiHagimoto 0:56c5742b9e2b 568
RyoheiHagimoto 0:56c5742b9e2b 569 void zbar_image_scanner_enable_cache (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 570 int enable)
RyoheiHagimoto 0:56c5742b9e2b 571 {
RyoheiHagimoto 0:56c5742b9e2b 572 if(iscn->cache) {
RyoheiHagimoto 0:56c5742b9e2b 573 /* recycle all cached syms */
RyoheiHagimoto 0:56c5742b9e2b 574 _zbar_image_scanner_recycle_syms(iscn, iscn->cache);
RyoheiHagimoto 0:56c5742b9e2b 575 iscn->cache = NULL;
RyoheiHagimoto 0:56c5742b9e2b 576 }
RyoheiHagimoto 0:56c5742b9e2b 577 iscn->enable_cache = (enable) ? 1 : 0;
RyoheiHagimoto 0:56c5742b9e2b 578 }
RyoheiHagimoto 0:56c5742b9e2b 579
RyoheiHagimoto 0:56c5742b9e2b 580 const zbar_symbol_set_t *
RyoheiHagimoto 0:56c5742b9e2b 581 zbar_image_scanner_get_results (const zbar_image_scanner_t *iscn)
RyoheiHagimoto 0:56c5742b9e2b 582 {
RyoheiHagimoto 0:56c5742b9e2b 583 return(iscn->syms);
RyoheiHagimoto 0:56c5742b9e2b 584 }
RyoheiHagimoto 0:56c5742b9e2b 585
RyoheiHagimoto 0:56c5742b9e2b 586 static inline void quiet_border (zbar_image_scanner_t *iscn)
RyoheiHagimoto 0:56c5742b9e2b 587 {
RyoheiHagimoto 0:56c5742b9e2b 588 /* flush scanner pipeline */
RyoheiHagimoto 0:56c5742b9e2b 589 zbar_scanner_t *scn = iscn->scn;
RyoheiHagimoto 0:56c5742b9e2b 590 zbar_scanner_flush(scn);
RyoheiHagimoto 0:56c5742b9e2b 591 zbar_scanner_flush(scn);
RyoheiHagimoto 0:56c5742b9e2b 592 zbar_scanner_new_scan(scn);
RyoheiHagimoto 0:56c5742b9e2b 593 }
RyoheiHagimoto 0:56c5742b9e2b 594
RyoheiHagimoto 0:56c5742b9e2b 595 #define movedelta(dx, dy) do { \
RyoheiHagimoto 0:56c5742b9e2b 596 x += (dx); \
RyoheiHagimoto 0:56c5742b9e2b 597 y += (dy); \
RyoheiHagimoto 0:56c5742b9e2b 598 p += (dx) + ((intptr_t)(dy) * w); \
RyoheiHagimoto 0:56c5742b9e2b 599 } while(0);
RyoheiHagimoto 0:56c5742b9e2b 600
RyoheiHagimoto 0:56c5742b9e2b 601 int zbar_scan_image (zbar_image_scanner_t *iscn,
RyoheiHagimoto 0:56c5742b9e2b 602 zbar_image_t *img)
RyoheiHagimoto 0:56c5742b9e2b 603 {
RyoheiHagimoto 0:56c5742b9e2b 604 /* timestamp image
RyoheiHagimoto 0:56c5742b9e2b 605 * FIXME prefer video timestamp
RyoheiHagimoto 0:56c5742b9e2b 606 */
RyoheiHagimoto 0:56c5742b9e2b 607 #if _POSIX_TIMERS > 0
RyoheiHagimoto 0:56c5742b9e2b 608 struct timespec abstime;
RyoheiHagimoto 0:56c5742b9e2b 609 clock_gettime(CLOCK_REALTIME, &abstime);
RyoheiHagimoto 0:56c5742b9e2b 610 iscn->time = (abstime.tv_sec * 1000) + ((abstime.tv_nsec / 500000) + 1) / 2;
RyoheiHagimoto 0:56c5742b9e2b 611 #else
RyoheiHagimoto 0:56c5742b9e2b 612 #if (0) // not used
RyoheiHagimoto 0:56c5742b9e2b 613 struct timeval abstime;
RyoheiHagimoto 0:56c5742b9e2b 614 gettimeofday(&abstime, NULL);
RyoheiHagimoto 0:56c5742b9e2b 615 iscn->time = (abstime.tv_sec * 1000) + ((abstime.tv_usec / 500) + 1) / 2;
RyoheiHagimoto 0:56c5742b9e2b 616 #endif
RyoheiHagimoto 0:56c5742b9e2b 617 #endif
RyoheiHagimoto 0:56c5742b9e2b 618
RyoheiHagimoto 0:56c5742b9e2b 619 #ifdef ENABLE_QRCODE
RyoheiHagimoto 0:56c5742b9e2b 620 _zbar_qr_reset(iscn->qr);
RyoheiHagimoto 0:56c5742b9e2b 621 #endif
RyoheiHagimoto 0:56c5742b9e2b 622
RyoheiHagimoto 0:56c5742b9e2b 623 /* get grayscale image, convert if necessary */
RyoheiHagimoto 0:56c5742b9e2b 624 if(img->format != fourcc('Y','8','0','0') &&
RyoheiHagimoto 0:56c5742b9e2b 625 img->format != fourcc('G','R','E','Y'))
RyoheiHagimoto 0:56c5742b9e2b 626 return(-1);
RyoheiHagimoto 0:56c5742b9e2b 627 iscn->img = img;
RyoheiHagimoto 0:56c5742b9e2b 628
RyoheiHagimoto 0:56c5742b9e2b 629 /* recycle previous scanner and image results */
RyoheiHagimoto 0:56c5742b9e2b 630 zbar_image_scanner_recycle_image(iscn, img);
RyoheiHagimoto 0:56c5742b9e2b 631 zbar_symbol_set_t *syms = iscn->syms;
RyoheiHagimoto 0:56c5742b9e2b 632 if(!syms) {
RyoheiHagimoto 0:56c5742b9e2b 633 syms = iscn->syms = _zbar_symbol_set_create();
RyoheiHagimoto 0:56c5742b9e2b 634 STAT(syms_new);
RyoheiHagimoto 0:56c5742b9e2b 635 zbar_symbol_set_ref(syms, 1);
RyoheiHagimoto 0:56c5742b9e2b 636 }
RyoheiHagimoto 0:56c5742b9e2b 637 else
RyoheiHagimoto 0:56c5742b9e2b 638 zbar_symbol_set_ref(syms, 2);
RyoheiHagimoto 0:56c5742b9e2b 639 img->syms = syms;
RyoheiHagimoto 0:56c5742b9e2b 640
RyoheiHagimoto 0:56c5742b9e2b 641 unsigned w = img->width;
RyoheiHagimoto 0:56c5742b9e2b 642 unsigned h = img->height;
RyoheiHagimoto 0:56c5742b9e2b 643 const uint8_t *data = img->data;
RyoheiHagimoto 0:56c5742b9e2b 644
RyoheiHagimoto 0:56c5742b9e2b 645 zbar_image_write_png(img, "debug.png");
RyoheiHagimoto 0:56c5742b9e2b 646 svg_open("debug.svg", 0, 0, w, h);
RyoheiHagimoto 0:56c5742b9e2b 647 svg_image("debug.png", w, h);
RyoheiHagimoto 0:56c5742b9e2b 648
RyoheiHagimoto 0:56c5742b9e2b 649 zbar_scanner_t *scn = iscn->scn;
RyoheiHagimoto 0:56c5742b9e2b 650
RyoheiHagimoto 0:56c5742b9e2b 651 int density = CFG(iscn, ZBAR_CFG_Y_DENSITY);
RyoheiHagimoto 0:56c5742b9e2b 652 if(density > 0) {
RyoheiHagimoto 0:56c5742b9e2b 653 svg_group_start("scanner", 0, 1, 1, 0, 0);
RyoheiHagimoto 0:56c5742b9e2b 654 const uint8_t *p = data;
RyoheiHagimoto 0:56c5742b9e2b 655 int x = 0, y = 0;
RyoheiHagimoto 0:56c5742b9e2b 656 iscn->dy = 0;
RyoheiHagimoto 0:56c5742b9e2b 657
RyoheiHagimoto 0:56c5742b9e2b 658 int border = (((h - 1) % density) + 1) / 2;
RyoheiHagimoto 0:56c5742b9e2b 659 if(border > h / 2)
RyoheiHagimoto 0:56c5742b9e2b 660 border = h / 2;
RyoheiHagimoto 0:56c5742b9e2b 661 movedelta(0, border);
RyoheiHagimoto 0:56c5742b9e2b 662 iscn->v = y;
RyoheiHagimoto 0:56c5742b9e2b 663
RyoheiHagimoto 0:56c5742b9e2b 664 zbar_scanner_new_scan(scn);
RyoheiHagimoto 0:56c5742b9e2b 665
RyoheiHagimoto 0:56c5742b9e2b 666 while(y < h) {
RyoheiHagimoto 0:56c5742b9e2b 667 zprintf(128, "img_x+: %04d,%04d @%p\n", x, y, p);
RyoheiHagimoto 0:56c5742b9e2b 668 svg_path_start("vedge", 1. / 32, 0, y + 0.5);
RyoheiHagimoto 0:56c5742b9e2b 669 iscn->dx = iscn->du = 1;
RyoheiHagimoto 0:56c5742b9e2b 670 iscn->umin = 0;
RyoheiHagimoto 0:56c5742b9e2b 671 while(x < w) {
RyoheiHagimoto 0:56c5742b9e2b 672 uint8_t d = *p;
RyoheiHagimoto 0:56c5742b9e2b 673 movedelta(1, 0);
RyoheiHagimoto 0:56c5742b9e2b 674 zbar_scan_y(scn, d);
RyoheiHagimoto 0:56c5742b9e2b 675 }
RyoheiHagimoto 0:56c5742b9e2b 676 ASSERT_POS;
RyoheiHagimoto 0:56c5742b9e2b 677 quiet_border(iscn);
RyoheiHagimoto 0:56c5742b9e2b 678 svg_path_end();
RyoheiHagimoto 0:56c5742b9e2b 679
RyoheiHagimoto 0:56c5742b9e2b 680 movedelta(-1, density);
RyoheiHagimoto 0:56c5742b9e2b 681 iscn->v = y;
RyoheiHagimoto 0:56c5742b9e2b 682 if(y >= h)
RyoheiHagimoto 0:56c5742b9e2b 683 break;
RyoheiHagimoto 0:56c5742b9e2b 684
RyoheiHagimoto 0:56c5742b9e2b 685 zprintf(128, "img_x-: %04d,%04d @%p\n", x, y, p);
RyoheiHagimoto 0:56c5742b9e2b 686 svg_path_start("vedge", -1. / 32, w, y + 0.5);
RyoheiHagimoto 0:56c5742b9e2b 687 iscn->dx = iscn->du = -1;
RyoheiHagimoto 0:56c5742b9e2b 688 iscn->umin = w;
RyoheiHagimoto 0:56c5742b9e2b 689 while(x >= 0) {
RyoheiHagimoto 0:56c5742b9e2b 690 uint8_t d = *p;
RyoheiHagimoto 0:56c5742b9e2b 691 movedelta(-1, 0);
RyoheiHagimoto 0:56c5742b9e2b 692 zbar_scan_y(scn, d);
RyoheiHagimoto 0:56c5742b9e2b 693 }
RyoheiHagimoto 0:56c5742b9e2b 694 ASSERT_POS;
RyoheiHagimoto 0:56c5742b9e2b 695 quiet_border(iscn);
RyoheiHagimoto 0:56c5742b9e2b 696 svg_path_end();
RyoheiHagimoto 0:56c5742b9e2b 697
RyoheiHagimoto 0:56c5742b9e2b 698 movedelta(1, density);
RyoheiHagimoto 0:56c5742b9e2b 699 iscn->v = y;
RyoheiHagimoto 0:56c5742b9e2b 700 }
RyoheiHagimoto 0:56c5742b9e2b 701 svg_group_end();
RyoheiHagimoto 0:56c5742b9e2b 702 }
RyoheiHagimoto 0:56c5742b9e2b 703 iscn->dx = 0;
RyoheiHagimoto 0:56c5742b9e2b 704
RyoheiHagimoto 0:56c5742b9e2b 705 density = CFG(iscn, ZBAR_CFG_X_DENSITY);
RyoheiHagimoto 0:56c5742b9e2b 706 if(density > 0) {
RyoheiHagimoto 0:56c5742b9e2b 707 svg_group_start("scanner", 90, 1, -1, 0, 0);
RyoheiHagimoto 0:56c5742b9e2b 708 const uint8_t *p = data;
RyoheiHagimoto 0:56c5742b9e2b 709 int x = 0, y = 0;
RyoheiHagimoto 0:56c5742b9e2b 710
RyoheiHagimoto 0:56c5742b9e2b 711 int border = (((w - 1) % density) + 1) / 2;
RyoheiHagimoto 0:56c5742b9e2b 712 if(border > w / 2)
RyoheiHagimoto 0:56c5742b9e2b 713 border = w / 2;
RyoheiHagimoto 0:56c5742b9e2b 714 movedelta(border, 0);
RyoheiHagimoto 0:56c5742b9e2b 715 iscn->v = x;
RyoheiHagimoto 0:56c5742b9e2b 716
RyoheiHagimoto 0:56c5742b9e2b 717 while(x < w) {
RyoheiHagimoto 0:56c5742b9e2b 718 zprintf(128, "img_y+: %04d,%04d @%p\n", x, y, p);
RyoheiHagimoto 0:56c5742b9e2b 719 svg_path_start("vedge", 1. / 32, 0, x + 0.5);
RyoheiHagimoto 0:56c5742b9e2b 720 iscn->dy = iscn->du = 1;
RyoheiHagimoto 0:56c5742b9e2b 721 iscn->umin = 0;
RyoheiHagimoto 0:56c5742b9e2b 722 while(y < h) {
RyoheiHagimoto 0:56c5742b9e2b 723 uint8_t d = *p;
RyoheiHagimoto 0:56c5742b9e2b 724 movedelta(0, 1);
RyoheiHagimoto 0:56c5742b9e2b 725 zbar_scan_y(scn, d);
RyoheiHagimoto 0:56c5742b9e2b 726 }
RyoheiHagimoto 0:56c5742b9e2b 727 ASSERT_POS;
RyoheiHagimoto 0:56c5742b9e2b 728 quiet_border(iscn);
RyoheiHagimoto 0:56c5742b9e2b 729 svg_path_end();
RyoheiHagimoto 0:56c5742b9e2b 730
RyoheiHagimoto 0:56c5742b9e2b 731 movedelta(density, -1);
RyoheiHagimoto 0:56c5742b9e2b 732 iscn->v = x;
RyoheiHagimoto 0:56c5742b9e2b 733 if(x >= w)
RyoheiHagimoto 0:56c5742b9e2b 734 break;
RyoheiHagimoto 0:56c5742b9e2b 735
RyoheiHagimoto 0:56c5742b9e2b 736 zprintf(128, "img_y-: %04d,%04d @%p\n", x, y, p);
RyoheiHagimoto 0:56c5742b9e2b 737 svg_path_start("vedge", -1. / 32, h, x + 0.5);
RyoheiHagimoto 0:56c5742b9e2b 738 iscn->dy = iscn->du = -1;
RyoheiHagimoto 0:56c5742b9e2b 739 iscn->umin = h;
RyoheiHagimoto 0:56c5742b9e2b 740 while(y >= 0) {
RyoheiHagimoto 0:56c5742b9e2b 741 uint8_t d = *p;
RyoheiHagimoto 0:56c5742b9e2b 742 movedelta(0, -1);
RyoheiHagimoto 0:56c5742b9e2b 743 zbar_scan_y(scn, d);
RyoheiHagimoto 0:56c5742b9e2b 744 }
RyoheiHagimoto 0:56c5742b9e2b 745 ASSERT_POS;
RyoheiHagimoto 0:56c5742b9e2b 746 quiet_border(iscn);
RyoheiHagimoto 0:56c5742b9e2b 747 svg_path_end();
RyoheiHagimoto 0:56c5742b9e2b 748
RyoheiHagimoto 0:56c5742b9e2b 749 movedelta(density, 1);
RyoheiHagimoto 0:56c5742b9e2b 750 iscn->v = x;
RyoheiHagimoto 0:56c5742b9e2b 751 }
RyoheiHagimoto 0:56c5742b9e2b 752 svg_group_end();
RyoheiHagimoto 0:56c5742b9e2b 753 }
RyoheiHagimoto 0:56c5742b9e2b 754 iscn->dy = 0;
RyoheiHagimoto 0:56c5742b9e2b 755 iscn->img = NULL;
RyoheiHagimoto 0:56c5742b9e2b 756
RyoheiHagimoto 0:56c5742b9e2b 757 #ifdef ENABLE_QRCODE
RyoheiHagimoto 0:56c5742b9e2b 758 _zbar_qr_decode(iscn->qr, iscn, img);
RyoheiHagimoto 0:56c5742b9e2b 759 #endif
RyoheiHagimoto 0:56c5742b9e2b 760
RyoheiHagimoto 0:56c5742b9e2b 761 /* FIXME tmp hack to filter bad EAN results */
RyoheiHagimoto 0:56c5742b9e2b 762 if(syms->nsyms && !iscn->enable_cache &&
RyoheiHagimoto 0:56c5742b9e2b 763 (density == 1 || CFG(iscn, ZBAR_CFG_Y_DENSITY) == 1)) {
RyoheiHagimoto 0:56c5742b9e2b 764 zbar_symbol_t **symp = &syms->head, *sym;
RyoheiHagimoto 0:56c5742b9e2b 765 while((sym = *symp)) {
RyoheiHagimoto 0:56c5742b9e2b 766 if(sym->type < ZBAR_I25 && sym->type > ZBAR_PARTIAL &&
RyoheiHagimoto 0:56c5742b9e2b 767 sym->quality < 3) {
RyoheiHagimoto 0:56c5742b9e2b 768 /* recycle */
RyoheiHagimoto 0:56c5742b9e2b 769 *symp = sym->next;
RyoheiHagimoto 0:56c5742b9e2b 770 syms->nsyms--;
RyoheiHagimoto 0:56c5742b9e2b 771 sym->next = NULL;
RyoheiHagimoto 0:56c5742b9e2b 772 _zbar_image_scanner_recycle_syms(iscn, sym);
RyoheiHagimoto 0:56c5742b9e2b 773 }
RyoheiHagimoto 0:56c5742b9e2b 774 else
RyoheiHagimoto 0:56c5742b9e2b 775 symp = &sym->next;
RyoheiHagimoto 0:56c5742b9e2b 776 }
RyoheiHagimoto 0:56c5742b9e2b 777 }
RyoheiHagimoto 0:56c5742b9e2b 778
RyoheiHagimoto 0:56c5742b9e2b 779 if(syms->nsyms && iscn->handler)
RyoheiHagimoto 0:56c5742b9e2b 780 iscn->handler(img, iscn->userdata);
RyoheiHagimoto 0:56c5742b9e2b 781
RyoheiHagimoto 0:56c5742b9e2b 782 svg_close();
RyoheiHagimoto 0:56c5742b9e2b 783 return(syms->nsyms);
RyoheiHagimoto 0:56c5742b9e2b 784 }
RyoheiHagimoto 0:56c5742b9e2b 785
RyoheiHagimoto 0:56c5742b9e2b 786 #ifdef DEBUG_SVG
RyoheiHagimoto 0:56c5742b9e2b 787 /* FIXME lame...*/
RyoheiHagimoto 0:56c5742b9e2b 788 # include "svg.c"
RyoheiHagimoto 0:56c5742b9e2b 789 #endif
RyoheiHagimoto 0:56c5742b9e2b 790