img_scanner.c 22 KB

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