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
img_scanner.c
00001 /*------------------------------------------------------------------------ 00002 * Copyright 2007-2009 (c) Jeff Brown <spadix@users.sourceforge.net> 00003 * 00004 * This file is part of the ZBar Bar Code Reader. 00005 * 00006 * The ZBar Bar Code Reader is free software; you can redistribute it 00007 * and/or modify it under the terms of the GNU Lesser Public License as 00008 * published by the Free Software Foundation; either version 2.1 of 00009 * the License, or (at your option) any later version. 00010 * 00011 * The ZBar Bar Code Reader is distributed in the hope that it will be 00012 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty 00013 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00014 * GNU Lesser Public License for more details. 00015 * 00016 * You should have received a copy of the GNU Lesser Public License 00017 * along with the ZBar Bar Code Reader; if not, write to the Free 00018 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, 00019 * Boston, MA 02110-1301 USA 00020 * 00021 * http://sourceforge.net/projects/zbar 00022 *------------------------------------------------------------------------*/ 00023 00024 #include <config.h> 00025 #if (0) // not used 00026 #include <unistd.h> 00027 #endif 00028 #ifdef HAVE_INTTYPES_H 00029 # include <inttypes.h> 00030 #endif 00031 #include <stdlib.h> /* malloc, free */ 00032 #include <time.h> /* clock_gettime */ 00033 #if (0) // not used 00034 #include <sys/time.h> /* gettimeofday */ 00035 #endif 00036 #include <string.h> /* memcmp, memset, memcpy */ 00037 #include <assert.h> 00038 00039 #include <zbar.h> 00040 #include "error.h" 00041 #include "image.h" 00042 #ifdef ENABLE_QRCODE 00043 # include "qrcode.h" 00044 #endif 00045 #include "img_scanner.h" 00046 #include "svg.h" 00047 00048 #if 1 00049 # define ASSERT_POS \ 00050 assert(p == data + x + y * (intptr_t)w) 00051 #else 00052 # define ASSERT_POS 00053 #endif 00054 00055 /* FIXME cache setting configurability */ 00056 00057 /* number of times the same result must be detected 00058 * in "nearby" images before being reported 00059 */ 00060 #define CACHE_CONSISTENCY 3 /* images */ 00061 00062 /* time interval for which two images are considered "nearby" 00063 */ 00064 #define CACHE_PROXIMITY 1000 /* ms */ 00065 00066 /* time that a result must *not* be detected before 00067 * it will be reported again 00068 */ 00069 #define CACHE_HYSTERESIS 2000 /* ms */ 00070 00071 /* time after which cache entries are invalidated 00072 */ 00073 #define CACHE_TIMEOUT (CACHE_HYSTERESIS * 2) /* ms */ 00074 00075 #define NUM_SCN_CFGS (ZBAR_CFG_Y_DENSITY - ZBAR_CFG_X_DENSITY + 1) 00076 00077 #define CFG(iscn, cfg) ((iscn)->configs[(cfg) - ZBAR_CFG_X_DENSITY]) 00078 #define TEST_CFG(iscn, cfg) (((iscn)->config >> ((cfg) - ZBAR_CFG_POSITION)) & 1) 00079 00080 #ifndef NO_STATS 00081 # define STAT(x) iscn->stat_##x++ 00082 #else 00083 # define STAT(...) 00084 # define dump_stats(...) 00085 #endif 00086 00087 #define RECYCLE_BUCKETS 5 00088 00089 typedef struct recycle_bucket_s { 00090 int nsyms; 00091 zbar_symbol_t *head; 00092 } recycle_bucket_t; 00093 00094 /* image scanner state */ 00095 struct zbar_image_scanner_s { 00096 zbar_scanner_t *scn; /* associated linear intensity scanner */ 00097 zbar_decoder_t *dcode; /* associated symbol decoder */ 00098 #ifdef ENABLE_QRCODE 00099 qr_reader *qr; /* QR Code 2D reader */ 00100 #endif 00101 00102 const void *userdata; /* application data */ 00103 /* user result callback */ 00104 zbar_image_data_handler_t *handler; 00105 00106 unsigned long time; /* scan start time */ 00107 zbar_image_t *img; /* currently scanning image *root* */ 00108 int dx, dy, du, umin, v; /* current scan direction */ 00109 zbar_symbol_set_t *syms; /* previous decode results */ 00110 /* recycled symbols in 4^n size buckets */ 00111 recycle_bucket_t recycle[RECYCLE_BUCKETS]; 00112 00113 int enable_cache; /* current result cache state */ 00114 zbar_symbol_t *cache; /* inter-image result cache entries */ 00115 00116 /* configuration settings */ 00117 unsigned config; /* config flags */ 00118 int configs[NUM_SCN_CFGS]; /* int valued configurations */ 00119 00120 #ifndef NO_STATS 00121 int stat_syms_new; 00122 int stat_iscn_syms_inuse, stat_iscn_syms_recycle; 00123 int stat_img_syms_inuse, stat_img_syms_recycle; 00124 int stat_sym_new; 00125 int stat_sym_recycle[RECYCLE_BUCKETS]; 00126 #endif 00127 }; 00128 00129 void _zbar_image_scanner_recycle_syms (zbar_image_scanner_t *iscn, 00130 zbar_symbol_t *sym) 00131 { 00132 zbar_symbol_t *next = NULL; 00133 for(; sym; sym = next) { 00134 next = sym->next; 00135 if(sym->refcnt && _zbar_refcnt(&sym->refcnt, -1)) { 00136 /* unlink referenced symbol */ 00137 /* FIXME handle outstanding component refs (currently unsupported) 00138 */ 00139 assert(sym->data_alloc); 00140 sym->next = NULL; 00141 } 00142 else { 00143 /* recycle unreferenced symbol */ 00144 if(!sym->data_alloc) { 00145 sym->data = NULL; 00146 sym->datalen = 0; 00147 } 00148 if(sym->syms) { 00149 if(_zbar_refcnt(&sym->syms->refcnt, -1)) 00150 assert(0); 00151 _zbar_image_scanner_recycle_syms(iscn, sym->syms->head); 00152 sym->syms->head = NULL; 00153 _zbar_symbol_set_free(sym->syms); 00154 sym->syms = NULL; 00155 } 00156 int i; 00157 for(i = 0; i < RECYCLE_BUCKETS; i++) 00158 if(sym->data_alloc < 1 << (i * 2)) 00159 break; 00160 if(i == RECYCLE_BUCKETS) { 00161 assert(sym->data); 00162 free(sym->data); 00163 sym->data = NULL; 00164 sym->data_alloc = 0; 00165 i = 0; 00166 } 00167 recycle_bucket_t *bucket = &iscn->recycle[i]; 00168 /* FIXME cap bucket fill */ 00169 bucket->nsyms++; 00170 sym->next = bucket->head; 00171 bucket->head = sym; 00172 } 00173 } 00174 } 00175 00176 static inline int recycle_syms (zbar_image_scanner_t *iscn, 00177 zbar_symbol_set_t *syms) 00178 { 00179 if(_zbar_refcnt(&syms->refcnt, -1)) 00180 return(1); 00181 00182 _zbar_image_scanner_recycle_syms(iscn, syms->head); 00183 syms->head = syms->tail = NULL; 00184 syms->nsyms = 0; 00185 return(0); 00186 } 00187 00188 inline void zbar_image_scanner_recycle_image (zbar_image_scanner_t *iscn, 00189 zbar_image_t *img) 00190 { 00191 zbar_symbol_set_t *syms = iscn->syms; 00192 if(syms && syms->refcnt) { 00193 if(recycle_syms(iscn, syms)) { 00194 STAT(iscn_syms_inuse); 00195 iscn->syms = NULL; 00196 } 00197 else 00198 STAT(iscn_syms_recycle); 00199 } 00200 00201 syms = img->syms; 00202 img->syms = NULL; 00203 if(syms && recycle_syms(iscn, syms)) { 00204 STAT(img_syms_inuse); 00205 syms = iscn->syms; 00206 } 00207 else if(syms) { 00208 STAT(img_syms_recycle); 00209 00210 /* select one set to resurrect, destroy the other */ 00211 if(iscn->syms) { 00212 _zbar_symbol_set_free(syms); 00213 syms = iscn->syms; 00214 } 00215 else 00216 iscn->syms = syms; 00217 } 00218 } 00219 00220 inline zbar_symbol_t* 00221 _zbar_image_scanner_alloc_sym (zbar_image_scanner_t *iscn, 00222 zbar_symbol_type_t type, 00223 int datalen) 00224 { 00225 /* recycle old or alloc new symbol */ 00226 int i; 00227 for(i = 0; i < RECYCLE_BUCKETS - 1; i++) 00228 if(datalen <= 1 << (i * 2)) 00229 break; 00230 00231 zbar_symbol_t *sym = NULL; 00232 for(; i > 0; i--) 00233 if((sym = iscn->recycle[i].head)) { 00234 STAT(sym_recycle[i]); 00235 break; 00236 } 00237 00238 if(sym) { 00239 iscn->recycle[i].head = sym->next; 00240 sym->next = NULL; 00241 assert(iscn->recycle[i].nsyms); 00242 iscn->recycle[i].nsyms--; 00243 } 00244 else { 00245 sym = calloc(1, sizeof(zbar_symbol_t)); 00246 STAT(sym_new); 00247 } 00248 00249 /* init new symbol */ 00250 sym->type = type; 00251 sym->quality = 1; 00252 sym->npts = 0; 00253 sym->cache_count = 0; 00254 sym->time = iscn->time; 00255 assert(!sym->syms); 00256 00257 if(datalen > 0) { 00258 sym->datalen = datalen - 1; 00259 if(sym->data_alloc < datalen) { 00260 if(sym->data) 00261 free(sym->data); 00262 sym->data_alloc = datalen; 00263 sym->data = malloc(datalen); 00264 } 00265 } 00266 else { 00267 if(sym->data) 00268 free(sym->data); 00269 sym->data = NULL; 00270 sym->datalen = sym->data_alloc = 0; 00271 } 00272 return(sym); 00273 } 00274 00275 static inline zbar_symbol_t *cache_lookup (zbar_image_scanner_t *iscn, 00276 zbar_symbol_t *sym) 00277 { 00278 /* search for matching entry in cache */ 00279 zbar_symbol_t **entry = &iscn->cache; 00280 while(*entry) { 00281 if((*entry)->type == sym->type && 00282 (*entry)->datalen == sym->datalen && 00283 !memcmp((*entry)->data, sym->data, sym->datalen)) 00284 break; 00285 if((sym->time - (*entry)->time) > CACHE_TIMEOUT) { 00286 /* recycle stale cache entry */ 00287 zbar_symbol_t *next = (*entry)->next; 00288 (*entry)->next = NULL; 00289 _zbar_image_scanner_recycle_syms(iscn, *entry); 00290 *entry = next; 00291 } 00292 else 00293 entry = &(*entry)->next; 00294 } 00295 return(*entry); 00296 } 00297 00298 static inline void cache_sym (zbar_image_scanner_t *iscn, 00299 zbar_symbol_t *sym) 00300 { 00301 if(iscn->enable_cache) { 00302 zbar_symbol_t *entry = cache_lookup(iscn, sym); 00303 if(!entry) { 00304 /* FIXME reuse sym */ 00305 entry = _zbar_image_scanner_alloc_sym(iscn, sym->type, 00306 sym->datalen + 1); 00307 memcpy(entry->data, sym->data, sym->datalen); 00308 entry->time = sym->time - CACHE_HYSTERESIS; 00309 entry->cache_count = -CACHE_CONSISTENCY; 00310 /* add to cache */ 00311 entry->next = iscn->cache; 00312 iscn->cache = entry; 00313 } 00314 00315 /* consistency check and hysteresis */ 00316 uint32_t age = sym->time - entry->time; 00317 entry->time = sym->time; 00318 int near_thresh = (age < CACHE_PROXIMITY); 00319 int far_thresh = (age >= CACHE_HYSTERESIS); 00320 int dup = (entry->cache_count >= 0); 00321 if((!dup && !near_thresh) || far_thresh) 00322 entry->cache_count = -CACHE_CONSISTENCY; 00323 else if(dup || near_thresh) 00324 entry->cache_count++; 00325 00326 sym->cache_count = entry->cache_count; 00327 } 00328 else 00329 sym->cache_count = 0; 00330 } 00331 00332 void _zbar_image_scanner_add_sym(zbar_image_scanner_t *iscn, 00333 zbar_symbol_t *sym) 00334 { 00335 cache_sym(iscn, sym); 00336 00337 zbar_symbol_set_t *syms = iscn->syms; 00338 if(sym->cache_count || !syms->tail) { 00339 sym->next = syms->head; 00340 syms->head = sym; 00341 } 00342 else { 00343 sym->next = syms->tail->next; 00344 syms->tail->next = sym; 00345 } 00346 00347 if(!sym->cache_count) 00348 syms->nsyms++; 00349 else if(!syms->tail) 00350 syms->tail = sym; 00351 00352 _zbar_symbol_refcnt(sym, 1); 00353 } 00354 00355 #ifdef ENABLE_QRCODE 00356 extern qr_finder_line *_zbar_decoder_get_qr_finder_line(zbar_decoder_t*); 00357 00358 # define QR_FIXED(v, rnd) ((((v) << 1) + (rnd)) << (QR_FINDER_SUBPREC - 1)) 00359 # define PRINT_FIXED(val, prec) \ 00360 ((val) >> (prec)), \ 00361 (1000 * ((val) & ((1 << (prec)) - 1)) / (1 << (prec))) 00362 00363 static inline void qr_handler (zbar_image_scanner_t *iscn) 00364 { 00365 qr_finder_line *line = _zbar_decoder_get_qr_finder_line(iscn->dcode); 00366 assert(line); 00367 unsigned u = zbar_scanner_get_edge(iscn->scn, line->pos[0], 00368 QR_FINDER_SUBPREC); 00369 line->boffs = u - zbar_scanner_get_edge(iscn->scn, line->boffs, 00370 QR_FINDER_SUBPREC); 00371 line->len = zbar_scanner_get_edge(iscn->scn, line->len, 00372 QR_FINDER_SUBPREC); 00373 line->eoffs = zbar_scanner_get_edge(iscn->scn, line->eoffs, 00374 QR_FINDER_SUBPREC) - line->len; 00375 line->len -= u; 00376 00377 u = QR_FIXED(iscn->umin, 0) + iscn->du * u; 00378 if(iscn->du < 0) { 00379 u -= line->len; 00380 int tmp = line->boffs; 00381 line->boffs = line->eoffs; 00382 line->eoffs = tmp; 00383 } 00384 int vert = !iscn->dx; 00385 line->pos[vert] = u; 00386 line->pos[!vert] = QR_FIXED(iscn->v, 1); 00387 00388 _zbar_qr_found_line(iscn->qr, vert, line); 00389 } 00390 #endif 00391 00392 static void symbol_handler (zbar_decoder_t *dcode) 00393 { 00394 zbar_image_scanner_t *iscn = zbar_decoder_get_userdata(dcode); 00395 zbar_symbol_type_t type = zbar_decoder_get_type(dcode); 00396 /* FIXME assert(type == ZBAR_PARTIAL) */ 00397 /* FIXME debug flag to save/display all PARTIALs */ 00398 if(type <= ZBAR_PARTIAL) 00399 return; 00400 00401 #ifdef ENABLE_QRCODE 00402 if(type == ZBAR_QRCODE) { 00403 qr_handler(iscn); 00404 return; 00405 } 00406 #else 00407 assert(type != ZBAR_QRCODE); 00408 #endif 00409 00410 const char *data = zbar_decoder_get_data(dcode); 00411 unsigned datalen = zbar_decoder_get_data_length(dcode); 00412 00413 int x = 0, y = 0; 00414 if(TEST_CFG(iscn, ZBAR_CFG_POSITION)) { 00415 /* tmp position fixup */ 00416 int w = zbar_scanner_get_width(iscn->scn); 00417 int u = iscn->umin + iscn->du * zbar_scanner_get_edge(iscn->scn, w, 0); 00418 if(iscn->dx) { 00419 x = u; 00420 y = iscn->v; 00421 } 00422 else { 00423 x = iscn->v; 00424 y = u; 00425 } 00426 } 00427 00428 /* FIXME need better symbol matching */ 00429 zbar_symbol_t *sym; 00430 for(sym = iscn->syms->head; sym; sym = sym->next) 00431 if(sym->type == type && 00432 sym->datalen == datalen && 00433 !memcmp(sym->data, data, datalen)) { 00434 sym->quality++; 00435 if(TEST_CFG(iscn, ZBAR_CFG_POSITION)) 00436 /* add new point to existing set */ 00437 /* FIXME should be polygon */ 00438 sym_add_point(sym, x, y); 00439 return; 00440 } 00441 00442 sym = _zbar_image_scanner_alloc_sym(iscn, type, datalen + 1); 00443 /* FIXME grab decoder buffer */ 00444 memcpy(sym->data, data, datalen + 1); 00445 00446 /* initialize first point */ 00447 if(TEST_CFG(iscn, ZBAR_CFG_POSITION)) 00448 sym_add_point(sym, x, y); 00449 00450 _zbar_image_scanner_add_sym(iscn, sym); 00451 } 00452 00453 zbar_image_scanner_t *zbar_image_scanner_create () 00454 { 00455 zbar_image_scanner_t *iscn = calloc(1, sizeof(zbar_image_scanner_t)); 00456 if(!iscn) 00457 return(NULL); 00458 iscn->dcode = zbar_decoder_create(); 00459 iscn->scn = zbar_scanner_create(iscn->dcode); 00460 if(!iscn->dcode || !iscn->scn) { 00461 zbar_image_scanner_destroy(iscn); 00462 return(NULL); 00463 } 00464 zbar_decoder_set_userdata(iscn->dcode, iscn); 00465 zbar_decoder_set_handler(iscn->dcode, symbol_handler); 00466 00467 #ifdef ENABLE_QRCODE 00468 iscn->qr = _zbar_qr_create(); 00469 #endif 00470 00471 /* apply default configuration */ 00472 CFG(iscn, ZBAR_CFG_X_DENSITY) = 1; 00473 CFG(iscn, ZBAR_CFG_Y_DENSITY) = 1; 00474 zbar_image_scanner_set_config(iscn, 0, ZBAR_CFG_POSITION, 1); 00475 return(iscn); 00476 } 00477 00478 #ifndef NO_STATS 00479 static inline void dump_stats (const zbar_image_scanner_t *iscn) 00480 { 00481 zprintf(1, "symbol sets allocated = %-4d\n", iscn->stat_syms_new); 00482 zprintf(1, " scanner syms in use = %-4d\trecycled = %-4d\n", 00483 iscn->stat_iscn_syms_inuse, iscn->stat_iscn_syms_recycle); 00484 zprintf(1, " image syms in use = %-4d\trecycled = %-4d\n", 00485 iscn->stat_img_syms_inuse, iscn->stat_img_syms_recycle); 00486 zprintf(1, "symbols allocated = %-4d\n", iscn->stat_sym_new); 00487 int i; 00488 for(i = 0; i < RECYCLE_BUCKETS; i++) 00489 zprintf(1, " recycled[%d] = %-4d\n", 00490 i, iscn->stat_sym_recycle[i]); 00491 } 00492 #endif 00493 00494 void zbar_image_scanner_destroy (zbar_image_scanner_t *iscn) 00495 { 00496 dump_stats(iscn); 00497 if(iscn->syms) { 00498 if(iscn->syms->refcnt) 00499 zbar_symbol_set_ref(iscn->syms, -1); 00500 else 00501 _zbar_symbol_set_free(iscn->syms); 00502 iscn->syms = NULL; 00503 } 00504 if(iscn->scn) 00505 zbar_scanner_destroy(iscn->scn); 00506 iscn->scn = NULL; 00507 if(iscn->dcode) 00508 zbar_decoder_destroy(iscn->dcode); 00509 iscn->dcode = NULL; 00510 int i; 00511 for(i = 0; i < RECYCLE_BUCKETS; i++) { 00512 zbar_symbol_t *sym, *next; 00513 for(sym = iscn->recycle[i].head; sym; sym = next) { 00514 next = sym->next; 00515 _zbar_symbol_free(sym); 00516 } 00517 } 00518 #ifdef ENABLE_QRCODE 00519 if(iscn->qr) { 00520 _zbar_qr_destroy(iscn->qr); 00521 iscn->qr = NULL; 00522 } 00523 #endif 00524 free(iscn); 00525 } 00526 00527 zbar_image_data_handler_t* 00528 zbar_image_scanner_set_data_handler (zbar_image_scanner_t *iscn, 00529 zbar_image_data_handler_t *handler, 00530 const void *userdata) 00531 { 00532 zbar_image_data_handler_t *result = iscn->handler; 00533 iscn->handler = handler; 00534 iscn->userdata = userdata; 00535 return(result); 00536 } 00537 00538 int zbar_image_scanner_set_config (zbar_image_scanner_t *iscn, 00539 zbar_symbol_type_t sym, 00540 zbar_config_t cfg, 00541 int val) 00542 { 00543 if(cfg < ZBAR_CFG_POSITION) 00544 return(zbar_decoder_set_config(iscn->dcode, sym, cfg, val)); 00545 00546 if(sym > ZBAR_PARTIAL) 00547 return(1); 00548 00549 if(cfg >= ZBAR_CFG_X_DENSITY && cfg <= ZBAR_CFG_Y_DENSITY) { 00550 00551 CFG(iscn, cfg) = val; 00552 return(0); 00553 } 00554 00555 if(cfg > ZBAR_CFG_POSITION) 00556 return(1); 00557 cfg -= ZBAR_CFG_POSITION; 00558 00559 if(!val) 00560 iscn->config &= ~(1 << cfg); 00561 else if(val == 1) 00562 iscn->config |= (1 << cfg); 00563 else 00564 return(1); 00565 00566 return(0); 00567 } 00568 00569 void zbar_image_scanner_enable_cache (zbar_image_scanner_t *iscn, 00570 int enable) 00571 { 00572 if(iscn->cache) { 00573 /* recycle all cached syms */ 00574 _zbar_image_scanner_recycle_syms(iscn, iscn->cache); 00575 iscn->cache = NULL; 00576 } 00577 iscn->enable_cache = (enable) ? 1 : 0; 00578 } 00579 00580 const zbar_symbol_set_t * 00581 zbar_image_scanner_get_results (const zbar_image_scanner_t *iscn) 00582 { 00583 return(iscn->syms); 00584 } 00585 00586 static inline void quiet_border (zbar_image_scanner_t *iscn) 00587 { 00588 /* flush scanner pipeline */ 00589 zbar_scanner_t *scn = iscn->scn; 00590 zbar_scanner_flush(scn); 00591 zbar_scanner_flush(scn); 00592 zbar_scanner_new_scan(scn); 00593 } 00594 00595 #define movedelta(dx, dy) do { \ 00596 x += (dx); \ 00597 y += (dy); \ 00598 p += (dx) + ((intptr_t)(dy) * w); \ 00599 } while(0); 00600 00601 int zbar_scan_image (zbar_image_scanner_t *iscn, 00602 zbar_image_t *img) 00603 { 00604 /* timestamp image 00605 * FIXME prefer video timestamp 00606 */ 00607 #if _POSIX_TIMERS > 0 00608 struct timespec abstime; 00609 clock_gettime(CLOCK_REALTIME, &abstime); 00610 iscn->time = (abstime.tv_sec * 1000) + ((abstime.tv_nsec / 500000) + 1) / 2; 00611 #else 00612 #if (0) // not used 00613 struct timeval abstime; 00614 gettimeofday(&abstime, NULL); 00615 iscn->time = (abstime.tv_sec * 1000) + ((abstime.tv_usec / 500) + 1) / 2; 00616 #endif 00617 #endif 00618 00619 #ifdef ENABLE_QRCODE 00620 _zbar_qr_reset(iscn->qr); 00621 #endif 00622 00623 /* get grayscale image, convert if necessary */ 00624 if(img->format != fourcc('Y','8','0','0') && 00625 img->format != fourcc('G','R','E','Y')) 00626 return(-1); 00627 iscn->img = img; 00628 00629 /* recycle previous scanner and image results */ 00630 zbar_image_scanner_recycle_image(iscn, img); 00631 zbar_symbol_set_t *syms = iscn->syms; 00632 if(!syms) { 00633 syms = iscn->syms = _zbar_symbol_set_create(); 00634 STAT(syms_new); 00635 zbar_symbol_set_ref(syms, 1); 00636 } 00637 else 00638 zbar_symbol_set_ref(syms, 2); 00639 img->syms = syms; 00640 00641 unsigned w = img->width; 00642 unsigned h = img->height; 00643 const uint8_t *data = img->data; 00644 00645 zbar_image_write_png(img, "debug.png"); 00646 svg_open("debug.svg", 0, 0, w, h); 00647 svg_image("debug.png", w, h); 00648 00649 zbar_scanner_t *scn = iscn->scn; 00650 00651 int density = CFG(iscn, ZBAR_CFG_Y_DENSITY); 00652 if(density > 0) { 00653 svg_group_start("scanner", 0, 1, 1, 0, 0); 00654 const uint8_t *p = data; 00655 int x = 0, y = 0; 00656 iscn->dy = 0; 00657 00658 int border = (((h - 1) % density) + 1) / 2; 00659 if(border > h / 2) 00660 border = h / 2; 00661 movedelta(0, border); 00662 iscn->v = y; 00663 00664 zbar_scanner_new_scan(scn); 00665 00666 while(y < h) { 00667 zprintf(128, "img_x+: %04d,%04d @%p\n", x, y, p); 00668 svg_path_start("vedge", 1. / 32, 0, y + 0.5); 00669 iscn->dx = iscn->du = 1; 00670 iscn->umin = 0; 00671 while(x < w) { 00672 uint8_t d = *p; 00673 movedelta(1, 0); 00674 zbar_scan_y(scn, d); 00675 } 00676 ASSERT_POS; 00677 quiet_border(iscn); 00678 svg_path_end(); 00679 00680 movedelta(-1, density); 00681 iscn->v = y; 00682 if(y >= h) 00683 break; 00684 00685 zprintf(128, "img_x-: %04d,%04d @%p\n", x, y, p); 00686 svg_path_start("vedge", -1. / 32, w, y + 0.5); 00687 iscn->dx = iscn->du = -1; 00688 iscn->umin = w; 00689 while(x >= 0) { 00690 uint8_t d = *p; 00691 movedelta(-1, 0); 00692 zbar_scan_y(scn, d); 00693 } 00694 ASSERT_POS; 00695 quiet_border(iscn); 00696 svg_path_end(); 00697 00698 movedelta(1, density); 00699 iscn->v = y; 00700 } 00701 svg_group_end(); 00702 } 00703 iscn->dx = 0; 00704 00705 density = CFG(iscn, ZBAR_CFG_X_DENSITY); 00706 if(density > 0) { 00707 svg_group_start("scanner", 90, 1, -1, 0, 0); 00708 const uint8_t *p = data; 00709 int x = 0, y = 0; 00710 00711 int border = (((w - 1) % density) + 1) / 2; 00712 if(border > w / 2) 00713 border = w / 2; 00714 movedelta(border, 0); 00715 iscn->v = x; 00716 00717 while(x < w) { 00718 zprintf(128, "img_y+: %04d,%04d @%p\n", x, y, p); 00719 svg_path_start("vedge", 1. / 32, 0, x + 0.5); 00720 iscn->dy = iscn->du = 1; 00721 iscn->umin = 0; 00722 while(y < h) { 00723 uint8_t d = *p; 00724 movedelta(0, 1); 00725 zbar_scan_y(scn, d); 00726 } 00727 ASSERT_POS; 00728 quiet_border(iscn); 00729 svg_path_end(); 00730 00731 movedelta(density, -1); 00732 iscn->v = x; 00733 if(x >= w) 00734 break; 00735 00736 zprintf(128, "img_y-: %04d,%04d @%p\n", x, y, p); 00737 svg_path_start("vedge", -1. / 32, h, x + 0.5); 00738 iscn->dy = iscn->du = -1; 00739 iscn->umin = h; 00740 while(y >= 0) { 00741 uint8_t d = *p; 00742 movedelta(0, -1); 00743 zbar_scan_y(scn, d); 00744 } 00745 ASSERT_POS; 00746 quiet_border(iscn); 00747 svg_path_end(); 00748 00749 movedelta(density, 1); 00750 iscn->v = x; 00751 } 00752 svg_group_end(); 00753 } 00754 iscn->dy = 0; 00755 iscn->img = NULL; 00756 00757 #ifdef ENABLE_QRCODE 00758 _zbar_qr_decode(iscn->qr, iscn, img); 00759 #endif 00760 00761 /* FIXME tmp hack to filter bad EAN results */ 00762 if(syms->nsyms && !iscn->enable_cache && 00763 (density == 1 || CFG(iscn, ZBAR_CFG_Y_DENSITY) == 1)) { 00764 zbar_symbol_t **symp = &syms->head, *sym; 00765 while((sym = *symp)) { 00766 if(sym->type < ZBAR_I25 && sym->type > ZBAR_PARTIAL && 00767 sym->quality < 3) { 00768 /* recycle */ 00769 *symp = sym->next; 00770 syms->nsyms--; 00771 sym->next = NULL; 00772 _zbar_image_scanner_recycle_syms(iscn, sym); 00773 } 00774 else 00775 symp = &sym->next; 00776 } 00777 } 00778 00779 if(syms->nsyms && iscn->handler) 00780 iscn->handler(img, iscn->userdata); 00781 00782 svg_close(); 00783 return(syms->nsyms); 00784 } 00785 00786 #ifdef DEBUG_SVG 00787 /* FIXME lame...*/ 00788 # include "svg.c" 00789 #endif 00790
Generated on Tue Jul 12 2022 18:54:12 by 1.7.2