1 /*------------------------------------------------------------------------
2  *  Copyright 2007-2010 (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 
24 #include <config.h>
25 #ifdef HAVE_UNISTD_H
26 # include <unistd.h>
27 #endif
28 #ifdef HAVE_INTTYPES_H
29 # include <inttypes.h>
30 #endif
31 #ifdef HAVE_DBUS
32 #include <dbus/dbus.h>
33 #endif
34 
35 #include <stdlib.h>     /* malloc, free */
36 #include <string.h>     /* memcmp, memset, memcpy */
37 #include <assert.h>
38 
39 #include <zbar.h>
40 #include "error.h"
41 #include "image.h"
42 #include "timer.h"
43 #if ENABLE_QRCODE == 1
44 # include "qrcode.h"
45 #endif
46 #if ENABLE_SQCODE == 1
47 # include "sqcode.h"
48 #endif
49 #include "img_scanner.h"
50 #include "svg.h"
51 
52 #if 1
53 # define ASSERT_POS \
54     assert(p == data + x + y * (intptr_t)w)
55 #else
56 # define ASSERT_POS
57 #endif
58 
59 /* FIXME cache setting configurability */
60 
61 /* time interval for which two images are considered "nearby"
62  */
63 #define CACHE_PROXIMITY   1000 /* ms */
64 
65 /* time that a result must *not* be detected before
66  * it will be reported again
67  */
68 #define CACHE_HYSTERESIS  2000 /* ms */
69 
70 /* time after which cache entries are invalidated
71  */
72 #define CACHE_TIMEOUT     (CACHE_HYSTERESIS * 2) /* ms */
73 
74 #define NUM_SCN_CFGS (ZBAR_CFG_Y_DENSITY - ZBAR_CFG_X_DENSITY + 1)
75 
76 #define CFG(iscn, cfg) ((iscn)->configs[(cfg) - ZBAR_CFG_X_DENSITY])
77 #define TEST_CFG(iscn, cfg) (((iscn)->config >> ((cfg) - ZBAR_CFG_POSITION)) & 1)
78 
79 #ifndef NO_STATS
80 # define STAT(x) iscn->stat_##x++
81 #else
82 # define STAT(...)
83 # define dump_stats(...)
84 #endif
85 
86 #define RECYCLE_BUCKETS     5
87 
88 typedef struct recycle_bucket_s {
89     int nsyms;
90     zbar_symbol_t *head;
91 } recycle_bucket_t;
92 
93 /* image scanner state */
94 struct zbar_image_scanner_s {
95     zbar_scanner_t *scn;        /* associated linear intensity scanner */
96     zbar_decoder_t *dcode;      /* associated symbol decoder */
97 #if ENABLE_QRCODE == 1
98     qr_reader *qr;              /* QR Code 2D reader */
99 #endif
100 #if ENABLE_SQCODE == 1
101     sq_reader *sq;              /* SQ Code 2D reader */
102 #endif
103 
104     const void *userdata;       /* application data */
105     /* user result callback */
106     zbar_image_data_handler_t *handler;
107 
108     unsigned long time;         /* scan start time */
109     zbar_image_t *img;          /* currently scanning image *root* */
110     int dx, dy, du, umin, v;    /* current scan direction */
111     zbar_symbol_set_t *syms;    /* previous decode results */
112     /* recycled symbols in 4^n size buckets */
113     recycle_bucket_t recycle[RECYCLE_BUCKETS];
114 
115     int enable_cache;           /* current result cache state */
116     zbar_symbol_t *cache;       /* inter-image result cache entries */
117 
118     /* configuration settings */
119     unsigned config;            /* config flags */
120     unsigned ean_config;
121     int configs[NUM_SCN_CFGS];  /* int valued configurations */
122     int sym_configs[1][NUM_SYMS]; /* per-symbology configurations */
123 
124 #ifndef NO_STATS
125     int stat_syms_new;
126     int stat_iscn_syms_inuse, stat_iscn_syms_recycle;
127     int stat_img_syms_inuse, stat_img_syms_recycle;
128     int stat_sym_new;
129     int stat_sym_recycle[RECYCLE_BUCKETS];
130 #endif
131 
132 #ifdef HAVE_DBUS
133     int is_dbus_enabled;        /* dbus enabled flag */
134 #endif
135 };
136 
_zbar_image_scanner_recycle_syms(zbar_image_scanner_t * iscn,zbar_symbol_t * sym)137 void _zbar_image_scanner_recycle_syms (zbar_image_scanner_t *iscn,
138                                        zbar_symbol_t *sym)
139 {
140     zbar_symbol_t *next = NULL;
141     for(; sym; sym = next) {
142         next = sym->next;
143         if(sym->refcnt && _zbar_refcnt(&sym->refcnt, -1)) {
144             /* unlink referenced symbol */
145             /* FIXME handle outstanding component refs (currently unsupported)
146              */
147             assert(sym->data_alloc);
148             sym->next = NULL;
149         }
150         else {
151             int i;
152             recycle_bucket_t *bucket;
153             /* recycle unreferenced symbol */
154             if(!sym->data_alloc) {
155                 sym->data = NULL;
156                 sym->datalen = 0;
157             }
158             if(sym->syms) {
159                 if(_zbar_refcnt(&sym->syms->refcnt, -1))
160                     assert(0);
161                 _zbar_image_scanner_recycle_syms(iscn, sym->syms->head);
162                 sym->syms->head = NULL;
163                 _zbar_symbol_set_free(sym->syms);
164                 sym->syms = NULL;
165             }
166             for(i = 0; i < RECYCLE_BUCKETS; i++)
167                 if(sym->data_alloc < 1 << (i * 2))
168                     break;
169             if(i == RECYCLE_BUCKETS) {
170                 assert(sym->data);
171                 free(sym->data);
172                 sym->data = NULL;
173                 sym->data_alloc = 0;
174                 i = 0;
175             }
176             bucket = &iscn->recycle[i];
177             /* FIXME cap bucket fill */
178             bucket->nsyms++;
179             sym->next = bucket->head;
180             bucket->head = sym;
181         }
182     }
183 }
184 
recycle_syms(zbar_image_scanner_t * iscn,zbar_symbol_set_t * syms)185 static inline int recycle_syms (zbar_image_scanner_t *iscn,
186                                 zbar_symbol_set_t *syms)
187 {
188     if(_zbar_refcnt(&syms->refcnt, -1))
189         return(1);
190 
191     _zbar_image_scanner_recycle_syms(iscn, syms->head);
192     syms->head = syms->tail = NULL;
193     syms->nsyms = 0;
194     return(0);
195 }
196 
zbar_image_scanner_recycle_image(zbar_image_scanner_t * iscn,zbar_image_t * img)197 inline void zbar_image_scanner_recycle_image (zbar_image_scanner_t *iscn,
198                                               zbar_image_t *img)
199 {
200     zbar_symbol_set_t *syms = iscn->syms;
201     if(syms && syms->refcnt) {
202         if(recycle_syms(iscn, syms)) {
203             STAT(iscn_syms_inuse);
204             iscn->syms = NULL;
205         }
206         else
207             STAT(iscn_syms_recycle);
208     }
209 
210     syms = img->syms;
211     img->syms = NULL;
212     if(syms && recycle_syms(iscn, syms))
213         STAT(img_syms_inuse);
214     else if(syms) {
215         STAT(img_syms_recycle);
216 
217         /* select one set to resurrect, destroy the other */
218         if(iscn->syms)
219             _zbar_symbol_set_free(syms);
220         else
221             iscn->syms = syms;
222     }
223 }
224 
225 inline zbar_symbol_t*
_zbar_image_scanner_alloc_sym(zbar_image_scanner_t * iscn,zbar_symbol_type_t type,int datalen)226 _zbar_image_scanner_alloc_sym (zbar_image_scanner_t *iscn,
227                                zbar_symbol_type_t type,
228                                int datalen)
229 {
230     /* recycle old or alloc new symbol */
231     zbar_symbol_t *sym = NULL;
232     int i;
233     for(i = 0; i < RECYCLE_BUCKETS - 1; i++)
234         if(datalen <= 1 << (i * 2))
235             break;
236 
237     for(; i > 0; i--)
238         if((sym = iscn->recycle[i].head)) {
239             STAT(sym_recycle[i]);
240             break;
241         }
242 
243     if(sym) {
244         iscn->recycle[i].head = sym->next;
245         sym->next = NULL;
246         assert(iscn->recycle[i].nsyms);
247         iscn->recycle[i].nsyms--;
248     }
249     else {
250         sym = calloc(1, sizeof(zbar_symbol_t));
251         STAT(sym_new);
252     }
253 
254     /* init new symbol */
255     sym->type = type;
256     sym->quality = 1;
257     sym->npts = 0;
258     sym->orient = ZBAR_ORIENT_UNKNOWN;
259     sym->cache_count = 0;
260     sym->time = iscn->time;
261     assert(!sym->syms);
262 
263     if(datalen > 0) {
264         sym->datalen = datalen - 1;
265         if(sym->data_alloc < datalen) {
266             if(sym->data)
267                 free(sym->data);
268             sym->data_alloc = datalen;
269             sym->data = malloc(datalen);
270         }
271     }
272     else {
273         if(sym->data)
274             free(sym->data);
275         sym->data = NULL;
276         sym->datalen = sym->data_alloc = 0;
277     }
278     return(sym);
279 }
280 
cache_lookup(zbar_image_scanner_t * iscn,zbar_symbol_t * sym)281 static inline zbar_symbol_t *cache_lookup (zbar_image_scanner_t *iscn,
282                                            zbar_symbol_t *sym)
283 {
284     /* search for matching entry in cache */
285     zbar_symbol_t **entry = &iscn->cache;
286     while(*entry) {
287         if((*entry)->type == sym->type &&
288            (*entry)->datalen == sym->datalen &&
289            !memcmp((*entry)->data, sym->data, sym->datalen))
290             break;
291         if((sym->time - (*entry)->time) > CACHE_TIMEOUT) {
292             /* recycle stale cache entry */
293             zbar_symbol_t *next = (*entry)->next;
294             (*entry)->next = NULL;
295             _zbar_image_scanner_recycle_syms(iscn, *entry);
296             *entry = next;
297         }
298         else
299             entry = &(*entry)->next;
300     }
301     return(*entry);
302 }
303 
cache_sym(zbar_image_scanner_t * iscn,zbar_symbol_t * sym)304 static inline void cache_sym (zbar_image_scanner_t *iscn,
305                               zbar_symbol_t *sym)
306 {
307     if(iscn->enable_cache) {
308         uint32_t age, near_thresh, far_thresh, dup;
309         zbar_symbol_t *entry = cache_lookup(iscn, sym);
310         if(!entry) {
311             /* FIXME reuse sym */
312             entry = _zbar_image_scanner_alloc_sym(iscn, sym->type,
313                                                   sym->datalen + 1);
314             entry->configs = sym->configs;
315             entry->modifiers = sym->modifiers;
316             memcpy(entry->data, sym->data, sym->datalen);
317             entry->time = sym->time - CACHE_HYSTERESIS;
318             entry->cache_count = 0;
319             /* add to cache */
320             entry->next = iscn->cache;
321             iscn->cache = entry;
322         }
323 
324         /* consistency check and hysteresis */
325         age = sym->time - entry->time;
326         entry->time = sym->time;
327         near_thresh = (age < CACHE_PROXIMITY);
328         far_thresh = (age >= CACHE_HYSTERESIS);
329         dup = (entry->cache_count >= 0);
330         if((!dup && !near_thresh) || far_thresh) {
331             int type = sym->type;
332             int h = _zbar_get_symbol_hash(type);
333             entry->cache_count = -iscn->sym_configs[0][h];
334         }
335         else if(dup || near_thresh)
336             entry->cache_count++;
337 
338         sym->cache_count = entry->cache_count;
339     }
340     else
341         sym->cache_count = 0;
342 }
343 
_zbar_image_scanner_add_sym(zbar_image_scanner_t * iscn,zbar_symbol_t * sym)344 void _zbar_image_scanner_add_sym(zbar_image_scanner_t *iscn,
345                                  zbar_symbol_t *sym)
346 {
347     zbar_symbol_set_t *syms;
348     cache_sym(iscn, sym);
349 
350     syms = iscn->syms;
351     if(sym->cache_count || !syms->tail) {
352         sym->next = syms->head;
353         syms->head = sym;
354     }
355     else {
356         sym->next = syms->tail->next;
357         syms->tail->next = sym;
358     }
359 
360     if(!sym->cache_count)
361         syms->nsyms++;
362     else if(!syms->tail)
363         syms->tail = sym;
364 
365     _zbar_symbol_refcnt(sym, 1);
366 }
367 
368 #if ENABLE_QRCODE == 1
369 extern qr_finder_line *_zbar_decoder_get_qr_finder_line(zbar_decoder_t*);
370 
371 # define QR_FIXED(v, rnd) ((((v) << 1) + (rnd)) << (QR_FINDER_SUBPREC - 1))
372 # define PRINT_FIXED(val, prec) \
373     ((val) >> (prec)),         \
374         (1000 * ((val) & ((1 << (prec)) - 1)) / (1 << (prec)))
375 
qr_handler(zbar_image_scanner_t * iscn)376 static inline void qr_handler (zbar_image_scanner_t *iscn)
377 {
378     unsigned u;
379     int vert;
380     qr_finder_line *line = _zbar_decoder_get_qr_finder_line(iscn->dcode);
381     assert(line);
382     u = zbar_scanner_get_edge(iscn->scn, line->pos[0],
383                               QR_FINDER_SUBPREC);
384     line->boffs = u - zbar_scanner_get_edge(iscn->scn, line->boffs,
385                                             QR_FINDER_SUBPREC);
386     line->len = zbar_scanner_get_edge(iscn->scn, line->len,
387                                       QR_FINDER_SUBPREC);
388     line->eoffs = zbar_scanner_get_edge(iscn->scn, line->eoffs,
389                                         QR_FINDER_SUBPREC) - line->len;
390     line->len -= u;
391 
392     u = QR_FIXED(iscn->umin, 0) + iscn->du * u;
393     if(iscn->du < 0) {
394         int tmp = line->boffs;
395         line->boffs = line->eoffs;
396         line->eoffs = tmp;
397         u -= line->len;
398     }
399     vert = !iscn->dx;
400     line->pos[vert] = u;
401     line->pos[!vert] = QR_FIXED(iscn->v, 1);
402 
403     _zbar_qr_found_line(iscn->qr, vert, line);
404 }
405 #endif
406 
407 #if ENABLE_SQCODE == 1
408 extern unsigned _zbar_decoder_get_sq_finder_config(zbar_decoder_t*);
409 
sq_handler(zbar_image_scanner_t * iscn)410 static void sq_handler (zbar_image_scanner_t *iscn)
411 {
412     unsigned config = _zbar_decoder_get_sq_finder_config(iscn->dcode);
413     _zbar_sq_new_config(iscn->sq, config);
414 }
415 #endif
416 
symbol_handler(zbar_decoder_t * dcode)417 static void symbol_handler (zbar_decoder_t *dcode)
418 {
419     zbar_image_scanner_t *iscn = zbar_decoder_get_userdata(dcode);
420     zbar_symbol_type_t type = zbar_decoder_get_type(dcode);
421     int x = 0, y = 0, dir;
422     const char *data;
423     unsigned datalen;
424     zbar_symbol_t *sym;
425 
426 #if ENABLE_QRCODE == 1
427     if(type == ZBAR_QRCODE) {
428         qr_handler(iscn);
429         return;
430     }
431 #else
432     assert(type != ZBAR_QRCODE);
433 #endif
434 
435     if(TEST_CFG(iscn, ZBAR_CFG_POSITION)) {
436         /* tmp position fixup */
437         int w = zbar_scanner_get_width(iscn->scn);
438         int u = iscn->umin + iscn->du * zbar_scanner_get_edge(iscn->scn, w, 0);
439         if(iscn->dx) {
440             x = u;
441             y = iscn->v;
442         }
443         else {
444             x = iscn->v;
445             y = u;
446         }
447     }
448 
449     /* FIXME debug flag to save/display all PARTIALs */
450     if(type <= ZBAR_PARTIAL) {
451         zprintf(256, "partial symbol @(%d,%d)\n", x, y);
452         return;
453     }
454 
455     data = zbar_decoder_get_data(dcode);
456     datalen = zbar_decoder_get_data_length(dcode);
457 
458     /* FIXME need better symbol matching */
459     for(sym = iscn->syms->head; sym; sym = sym->next)
460         if(sym->type == type &&
461            sym->datalen == datalen &&
462            !memcmp(sym->data, data, datalen)) {
463             sym->quality++;
464             zprintf(224, "dup symbol @(%d,%d): dup %s: %.20s\n",
465                     x, y, zbar_get_symbol_name(type), data);
466             if(TEST_CFG(iscn, ZBAR_CFG_POSITION))
467                 /* add new point to existing set */
468                 /* FIXME should be polygon */
469                 sym_add_point(sym, x, y);
470             return;
471         }
472 
473     sym = _zbar_image_scanner_alloc_sym(iscn, type, datalen + 1);
474     sym->configs = zbar_decoder_get_configs(dcode, type);
475     sym->modifiers = zbar_decoder_get_modifiers(dcode);
476     /* FIXME grab decoder buffer */
477     memcpy(sym->data, data, datalen + 1);
478 
479     /* initialize first point */
480     if(TEST_CFG(iscn, ZBAR_CFG_POSITION)) {
481         zprintf(192, "new symbol @(%d,%d): %s: %.20s\n",
482                 x, y, zbar_get_symbol_name(type), data);
483         sym_add_point(sym, x, y);
484     }
485 
486     dir = zbar_decoder_get_direction(dcode);
487     if(dir)
488         sym->orient = (iscn->dy != 0) + ((iscn->du ^ dir) & 2);
489 
490     _zbar_image_scanner_add_sym(iscn, sym);
491 }
492 
zbar_image_scanner_create()493 zbar_image_scanner_t *zbar_image_scanner_create ()
494 {
495     zbar_image_scanner_t *iscn = calloc(1, sizeof(zbar_image_scanner_t));
496     if(!iscn)
497         return(NULL);
498     iscn->dcode = zbar_decoder_create();
499     iscn->scn = zbar_scanner_create(iscn->dcode);
500     if(!iscn->dcode || !iscn->scn) {
501         zbar_image_scanner_destroy(iscn);
502         return(NULL);
503     }
504     zbar_decoder_set_userdata(iscn->dcode, iscn);
505     zbar_decoder_set_handler(iscn->dcode, symbol_handler);
506 
507 #if ENABLE_QRCODE == 1
508     iscn->qr = _zbar_qr_create();
509 #endif
510 
511 #if ENABLE_SQCODE == 1
512     iscn->sq = _zbar_sq_create();
513 #endif
514 
515     /* apply default configuration */
516     CFG(iscn, ZBAR_CFG_X_DENSITY) = 1;
517     CFG(iscn, ZBAR_CFG_Y_DENSITY) = 1;
518     zbar_image_scanner_set_config(iscn, 0, ZBAR_CFG_POSITION, 1);
519     zbar_image_scanner_set_config(iscn, 0, ZBAR_CFG_UNCERTAINTY, 2);
520     zbar_image_scanner_set_config(iscn, 0, ZBAR_CFG_TEST_INVERTED, 0);
521     zbar_image_scanner_set_config(iscn, ZBAR_QRCODE, ZBAR_CFG_UNCERTAINTY, 0);
522     zbar_image_scanner_set_config(iscn, ZBAR_QRCODE, ZBAR_CFG_BINARY, 0);
523     zbar_image_scanner_set_config(iscn, ZBAR_CODE128, ZBAR_CFG_UNCERTAINTY, 0);
524     zbar_image_scanner_set_config(iscn, ZBAR_CODE93, ZBAR_CFG_UNCERTAINTY, 0);
525     zbar_image_scanner_set_config(iscn, ZBAR_CODE39, ZBAR_CFG_UNCERTAINTY, 0);
526     zbar_image_scanner_set_config(iscn, ZBAR_CODABAR, ZBAR_CFG_UNCERTAINTY, 1);
527     zbar_image_scanner_set_config(iscn, ZBAR_COMPOSITE, ZBAR_CFG_UNCERTAINTY, 0);
528     return(iscn);
529 }
530 
531 #ifndef NO_STATS
dump_stats(const zbar_image_scanner_t * iscn)532 static inline void dump_stats (const zbar_image_scanner_t *iscn)
533 {
534     int i;
535     zprintf(1, "symbol sets allocated   = %-4d\n", iscn->stat_syms_new);
536     zprintf(1, "    scanner syms in use = %-4d\trecycled  = %-4d\n",
537             iscn->stat_iscn_syms_inuse, iscn->stat_iscn_syms_recycle);
538     zprintf(1, "    image syms in use   = %-4d\trecycled  = %-4d\n",
539             iscn->stat_img_syms_inuse, iscn->stat_img_syms_recycle);
540     zprintf(1, "symbols allocated       = %-4d\n", iscn->stat_sym_new);
541     for(i = 0; i < RECYCLE_BUCKETS; i++)
542         zprintf(1, "     recycled[%d]        = %-4d\n",
543                 i, iscn->stat_sym_recycle[i]);
544 }
545 #endif
546 
zbar_image_scanner_destroy(zbar_image_scanner_t * iscn)547 void zbar_image_scanner_destroy (zbar_image_scanner_t *iscn)
548 {
549     int i;
550     dump_stats(iscn);
551     if(iscn->syms) {
552         if(iscn->syms->refcnt)
553             zbar_symbol_set_ref(iscn->syms, -1);
554         else
555             _zbar_symbol_set_free(iscn->syms);
556         iscn->syms = NULL;
557     }
558     if(iscn->scn)
559         zbar_scanner_destroy(iscn->scn);
560     iscn->scn = NULL;
561     if(iscn->dcode)
562         zbar_decoder_destroy(iscn->dcode);
563     iscn->dcode = NULL;
564     for(i = 0; i < RECYCLE_BUCKETS; i++) {
565         zbar_symbol_t *sym, *next;
566         for(sym = iscn->recycle[i].head; sym; sym = next) {
567             next = sym->next;
568             _zbar_symbol_free(sym);
569         }
570     }
571 #if ENABLE_QRCODE == 1
572     if(iscn->qr) {
573         _zbar_qr_destroy(iscn->qr);
574         iscn->qr = NULL;
575     }
576 #endif
577 #if ENABLE_SQCODE == 1
578     if(iscn->sq) {
579         _zbar_sq_destroy(iscn->sq);
580         iscn->sq = NULL;
581     }
582 #endif
583     free(iscn);
584 }
585 
586 zbar_image_data_handler_t*
zbar_image_scanner_set_data_handler(zbar_image_scanner_t * iscn,zbar_image_data_handler_t * handler,const void * userdata)587 zbar_image_scanner_set_data_handler (zbar_image_scanner_t *iscn,
588                                      zbar_image_data_handler_t *handler,
589                                      const void *userdata)
590 {
591     zbar_image_data_handler_t *result = iscn->handler;
592     iscn->handler = handler;
593     iscn->userdata = userdata;
594     return(result);
595 }
596 
zbar_image_scanner_set_config(zbar_image_scanner_t * iscn,zbar_symbol_type_t sym,zbar_config_t cfg,int val)597 int zbar_image_scanner_set_config (zbar_image_scanner_t *iscn,
598                                    zbar_symbol_type_t sym,
599                                    zbar_config_t cfg,
600                                    int val)
601 {
602     if((sym == 0 || sym == ZBAR_COMPOSITE) && cfg == ZBAR_CFG_ENABLE) {
603         iscn->ean_config = !!val;
604         if(sym)
605             return(0);
606     }
607 
608     if(cfg < ZBAR_CFG_UNCERTAINTY)
609         return(zbar_decoder_set_config(iscn->dcode, sym, cfg, val));
610 
611     if(cfg < ZBAR_CFG_POSITION) {
612         int c, i;
613         if(cfg > ZBAR_CFG_UNCERTAINTY)
614             return(1);
615         c = cfg - ZBAR_CFG_UNCERTAINTY;
616         if(sym > ZBAR_PARTIAL) {
617             i = _zbar_get_symbol_hash(sym);
618             iscn->sym_configs[c][i] = val;
619         }
620         else
621             for(i = 0; i < NUM_SYMS; i++)
622                 iscn->sym_configs[c][i] = val;
623         return(0);
624     }
625 
626     /* Image scanner parameters apply only to ZBAR_PARTIAL */
627     if(sym > ZBAR_PARTIAL)
628         return(1);
629 
630     if(cfg >= ZBAR_CFG_X_DENSITY && cfg <= ZBAR_CFG_Y_DENSITY) {
631         CFG(iscn, cfg) = val;
632         return(0);
633     }
634 
635     cfg -= ZBAR_CFG_POSITION;
636 
637     if(!val)
638         iscn->config &= ~(1 << cfg);
639     else if(val == 1)
640         iscn->config |= (1 << cfg);
641     else
642         return(1);
643 
644     return(0);
645 }
646 
zbar_image_scanner_get_config(zbar_image_scanner_t * iscn,zbar_symbol_type_t sym,zbar_config_t cfg,int * val)647 int zbar_image_scanner_get_config(zbar_image_scanner_t *iscn,
648                                   zbar_symbol_type_t sym,
649                                   zbar_config_t cfg,
650                                   int *val)
651 {
652     /* Return error if symbol doesn't have config */
653     if(sym < ZBAR_PARTIAL || sym > ZBAR_CODE128 || sym == ZBAR_COMPOSITE)
654         return 1;
655 
656     if (cfg < ZBAR_CFG_UNCERTAINTY)
657         return zbar_decoder_get_config(iscn->dcode, sym, cfg, val);
658 
659     if(cfg < ZBAR_CFG_POSITION) {
660         if(sym == ZBAR_PARTIAL)
661             return(1);
662 
663         int i = _zbar_get_symbol_hash(sym);
664 
665         *val = iscn->sym_configs[cfg - ZBAR_CFG_UNCERTAINTY][i];
666         return 0;
667     }
668 
669     /* Image scanner parameters apply only to ZBAR_PARTIAL */
670     if(sym > ZBAR_PARTIAL)
671         return(1);
672 
673     if(cfg < ZBAR_CFG_X_DENSITY) {
674         *val = (iscn->config & (1 << (cfg - ZBAR_CFG_POSITION))) != 0;
675         return 0;
676     }
677 
678     if(cfg <= ZBAR_CFG_Y_DENSITY) {
679         *val = CFG(iscn, cfg);
680         return 0;
681     }
682 
683     return 1;
684 }
685 
zbar_image_scanner_enable_cache(zbar_image_scanner_t * iscn,int enable)686 void zbar_image_scanner_enable_cache (zbar_image_scanner_t *iscn,
687                                       int enable)
688 {
689     if(iscn->cache) {
690         /* recycle all cached syms */
691         _zbar_image_scanner_recycle_syms(iscn, iscn->cache);
692         iscn->cache = NULL;
693     }
694     iscn->enable_cache = (enable) ? 1 : 0;
695 }
696 
697 const zbar_symbol_set_t *
zbar_image_scanner_get_results(const zbar_image_scanner_t * iscn)698 zbar_image_scanner_get_results (const zbar_image_scanner_t *iscn)
699 {
700     return(iscn->syms);
701 }
702 
quiet_border(zbar_image_scanner_t * iscn)703 static inline void quiet_border (zbar_image_scanner_t *iscn)
704 {
705     /* flush scanner pipeline */
706     zbar_scanner_t *scn = iscn->scn;
707     zbar_scanner_flush(scn);
708     zbar_scanner_flush(scn);
709     zbar_scanner_new_scan(scn);
710 }
711 
712 
713 #ifdef HAVE_DBUS
dict_add_property(DBusMessageIter * property,const char * key,const char * value,unsigned int value_length,int is_binary)714 static int dict_add_property (DBusMessageIter *property,
715                               const char *key,
716                               const char *value,
717                               unsigned int value_length,
718                               int is_binary)
719 {
720 
721     DBusMessageIter dict_entry, dict_val, array_val;
722     DBusError err;
723     dbus_error_init(&err);
724     dbus_message_iter_open_container(property, DBUS_TYPE_DICT_ENTRY, NULL, &dict_entry);
725     if (!dbus_message_iter_append_basic(&dict_entry, DBUS_TYPE_STRING, &key)){
726         fprintf(stderr, "Key Error\n");
727         dbus_message_iter_close_container(property, &dict_entry);
728         goto error;
729     }
730 
731     if (is_binary) {
732         dbus_message_iter_open_container(&dict_entry, DBUS_TYPE_VARIANT, "ay", &dict_val);
733         dbus_message_iter_open_container(&dict_val, DBUS_TYPE_ARRAY, "y", &array_val);
734         if (!dbus_message_iter_append_fixed_array(&array_val, DBUS_TYPE_BYTE, &value, value_length)) {
735             fprintf(stderr, "Byte Array Value Error\n");
736             dbus_message_iter_close_container(&dict_val, &array_val);
737             dbus_message_iter_close_container(&dict_entry, &dict_val);
738             dbus_message_iter_close_container(property, &dict_entry);
739             goto error;
740         }
741     } else {
742         dbus_message_iter_open_container(&dict_entry, DBUS_TYPE_VARIANT, DBUS_TYPE_STRING_AS_STRING, &dict_val);
743         if (!dbus_message_iter_append_basic(&dict_val, DBUS_TYPE_STRING, &value)) {
744             fprintf(stderr, "String Value Error\n");
745             dbus_message_iter_close_container(&dict_entry, &dict_val);
746             dbus_message_iter_close_container(property, &dict_entry);
747             goto error;
748         }
749     }
750 
751     if (is_binary)
752         dbus_message_iter_close_container(&dict_val, &array_val);
753     dbus_message_iter_close_container(&dict_entry, &dict_val);
754     dbus_message_iter_close_container(property, &dict_entry);
755     return(1);
756 
757 error:
758     if (dbus_error_is_set(&err)) {
759         fprintf(stderr, "Name Error (%s)\n", err.message);
760         dbus_error_free(&err);
761     }
762     return(0);
763 }
764 
zbar_send_dbus(int type,const char * sigvalue,unsigned int length,int is_binary)765 static void zbar_send_dbus(int type, const char* sigvalue,
766                            unsigned int length, int is_binary)
767 {
768     DBusMessage* msg;
769     DBusMessageIter args, dict;
770     DBusConnection* conn;
771     const char *type_name;
772     const char *value_key = is_binary ? "BinaryData" : "Data";
773     DBusError err;
774     int ret;
775     dbus_uint32_t serial = 0;
776 
777     // initialise the error value
778     dbus_error_init(&err);
779 
780     // connect to the DBUS system bus, and check for errors
781     conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
782     if (dbus_error_is_set(&err)) {
783         fprintf(stderr, "Connection Error (%s)\n", err.message);
784         dbus_error_free(&err);
785     }
786     if (NULL == conn) {
787         fprintf(stderr, "Connection Null\n");
788         return;
789     }
790 
791     // register our name on the bus, and check for errors
792     ret = dbus_bus_request_name(conn, "org.linuxtv.Zbar", DBUS_NAME_FLAG_REPLACE_EXISTING, &err);
793     if (dbus_error_is_set(&err)) {
794         fprintf(stderr, "Name Error (%s)\n", err.message);
795         dbus_error_free(&err);
796     }
797     if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
798         return;
799     }
800 
801     // create a signal & check for errors
802     msg = dbus_message_new_signal("/org/linuxtv/Zbar1/Code", // object name of the signal
803                                  "org.linuxtv.Zbar1.Code", // interface name of the signal
804                                  "Code"); // name of the signal
805     if (NULL == msg)
806     {
807         fprintf(stderr, "Message Null\n");
808         return;
809     }
810 
811     // append arguments onto signal
812     dbus_message_iter_init_append(msg, &args);
813     if (!dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY, "{sv}", &dict)) {
814         fprintf(stderr, "Out Of Dict Container Memory!\n");
815         dbus_message_unref(msg);
816         return;
817     }
818 
819     type_name = zbar_get_symbol_name(type);
820     if (!dict_add_property(&dict, "Type", type_name, 0, 0)) {
821         fprintf(stderr, "Out Of Property Memory!\n");
822         dbus_message_unref(msg);
823         return;
824     }
825 
826     if (!dict_add_property(&dict, value_key, sigvalue, length, is_binary)) {
827         fprintf(stderr, "Out Of Property Memory!\n");
828         dbus_message_unref(msg);
829         return;
830     }
831 
832     dbus_message_iter_close_container(&args, &dict);
833 
834     // send the message and flush the connection
835     if (!dbus_connection_send(conn, msg, &serial)) {
836         fprintf(stderr, "Out Of Memory!\n");
837         dbus_message_unref(msg);
838         return;
839     }
840 
841     dbus_connection_flush(conn);
842     dbus_bus_release_name(conn, "org.linuxtv.Zbar", &err);
843     if (dbus_error_is_set(&err)) {
844         fprintf(stderr, "Name Release Error (%s)\n", err.message);
845         dbus_error_free(&err);
846     }
847 
848     // free the message
849     dbus_message_unref(msg);
850 }
851 
zbar_send_code_via_dbus(zbar_image_scanner_t * iscn,zbar_image_t * img)852 static void zbar_send_code_via_dbus(zbar_image_scanner_t *iscn,
853                                     zbar_image_t *img)
854 {
855     const zbar_symbol_t *sym = zbar_image_first_symbol(img);
856 
857     if (!sym)
858         return;
859     for(; sym; sym = zbar_symbol_next(sym)) {
860         if(zbar_symbol_get_count(sym))
861             continue;
862 
863         zbar_symbol_type_t type = zbar_symbol_get_type(sym);
864         if(type == ZBAR_PARTIAL)
865             continue;
866 
867         int is_binary = 0;
868         zbar_image_scanner_get_config(iscn, type, ZBAR_CFG_BINARY, &is_binary);
869 
870         zbar_send_dbus(type,
871                        zbar_symbol_get_data(sym),
872                        zbar_symbol_get_data_length(sym),
873                        is_binary);
874     }
875 }
876 #endif
877 
878 #define movedelta(dx, dy) do {                  \
879         x += (dx);                              \
880         y += (dy);                              \
881         p += (dx) + ((uintptr_t)(dy) * w);       \
882     } while(0);
883 
_zbar_scan_image(zbar_image_scanner_t * iscn,zbar_image_t * img)884 static void *_zbar_scan_image(zbar_image_scanner_t *iscn,
885                               zbar_image_t *img)
886 {
887     zbar_symbol_set_t *syms;
888     const uint8_t *data;
889     zbar_scanner_t *scn = iscn->scn;
890     unsigned w, h, cx1, cy1;
891     int density;
892 
893     /* timestamp image
894      * FIXME prefer video timestamp
895      */
896     iscn->time = _zbar_timer_now();
897 
898 #if ENABLE_QRCODE == 1
899     _zbar_qr_reset(iscn->qr);
900 #endif
901 
902 #if ENABLE_SQCODE == 1
903     _zbar_sq_reset(iscn->sq);
904 #endif
905 
906     /* image must be in grayscale format */
907     if(img->format != fourcc('Y','8','0','0') &&
908        img->format != fourcc('G','R','E','Y'))
909         return NULL;
910     iscn->img = img;
911 
912     /* recycle previous scanner and image results */
913     zbar_image_scanner_recycle_image(iscn, img);
914     syms = iscn->syms;
915     if(!syms) {
916         syms = iscn->syms = _zbar_symbol_set_create();
917         STAT(syms_new);
918         zbar_symbol_set_ref(syms, 1);
919     }
920     else
921         zbar_symbol_set_ref(syms, 2);
922     img->syms = syms;
923 
924     w = img->width;
925     h = img->height;
926     cx1 = img->crop_x + img->crop_w;
927     assert(cx1 <= w);
928     cy1 = img->crop_y + img->crop_h;
929     assert(cy1 <= h);
930     data = img->data;
931 
932     zbar_image_write_png(img, "debug.png");
933     svg_open("debug.svg", 0, 0, w, h);
934     svg_image("debug.png", w, h);
935 
936     zbar_scanner_new_scan(scn);
937 
938     density = CFG(iscn, ZBAR_CFG_Y_DENSITY);
939     if(density > 0) {
940         const uint8_t *p = data;
941         int x = 0, y = 0;
942 
943         int border = (((img->crop_h - 1) % density) + 1) / 2;
944         if(border > img->crop_h / 2)
945             border = img->crop_h / 2;
946         border += img->crop_y;
947         assert(border <= h);
948         svg_group_start("scanner", 0, 1, 1, 0, 0);
949         iscn->dy = 0;
950 
951         movedelta(img->crop_x, border);
952         iscn->v = y;
953 
954         while(y < cy1) {
955             int cx0 = img->crop_x;;
956             zprintf(128, "img_x+: %04d,%04d @%p\n", x, y, p);
957             svg_path_start("vedge", 1. / 32, 0, y + 0.5);
958             iscn->dx = iscn->du = 1;
959             iscn->umin = cx0;
960             while(x < cx1) {
961                 uint8_t d = *p;
962                 movedelta(1, 0);
963                 zbar_scan_y(scn, d);
964             }
965             ASSERT_POS;
966             quiet_border(iscn);
967             svg_path_end();
968 
969             movedelta(-1, density);
970             iscn->v = y;
971             if(y >= cy1)
972                 break;
973 
974             zprintf(128, "img_x-: %04d,%04d @%p\n", x, y, p);
975             svg_path_start("vedge", -1. / 32, w, y + 0.5);
976             iscn->dx = iscn->du = -1;
977             iscn->umin = cx1;
978             while(x >= cx0) {
979                 uint8_t d = *p;
980                 movedelta(-1, 0);
981                 zbar_scan_y(scn, d);
982             }
983             ASSERT_POS;
984             quiet_border(iscn);
985             svg_path_end();
986 
987             movedelta(1, density);
988             iscn->v = y;
989         }
990         svg_group_end();
991     }
992     iscn->dx = 0;
993 
994     density = CFG(iscn, ZBAR_CFG_X_DENSITY);
995     if(density > 0) {
996         const uint8_t *p = data;
997         int x = 0, y = 0;
998 
999         int border = (((img->crop_w - 1) % density) + 1) / 2;
1000         if(border > img->crop_w / 2)
1001             border = img->crop_w / 2;
1002         border += img->crop_x;
1003         assert(border <= w);
1004         svg_group_start("scanner", 90, 1, -1, 0, 0);
1005         movedelta(border, img->crop_y);
1006         iscn->v = x;
1007 
1008         while(x < cx1) {
1009             int cy0 = img->crop_y;
1010             zprintf(128, "img_y+: %04d,%04d @%p\n", x, y, p);
1011             svg_path_start("vedge", 1. / 32, 0, x + 0.5);
1012             iscn->dy = iscn->du = 1;
1013             iscn->umin = cy0;
1014             while(y < cy1) {
1015                 uint8_t d = *p;
1016                 movedelta(0, 1);
1017                 zbar_scan_y(scn, d);
1018             }
1019             ASSERT_POS;
1020             quiet_border(iscn);
1021             svg_path_end();
1022 
1023             movedelta(density, -1);
1024             iscn->v = x;
1025             if(x >= cx1)
1026                 break;
1027 
1028             zprintf(128, "img_y-: %04d,%04d @%p\n", x, y, p);
1029             svg_path_start("vedge", -1. / 32, h, x + 0.5);
1030             iscn->dy = iscn->du = -1;
1031             iscn->umin = cy1;
1032             while(y >= cy0) {
1033                 uint8_t d = *p;
1034                 movedelta(0, -1);
1035                 zbar_scan_y(scn, d);
1036             }
1037             ASSERT_POS;
1038             quiet_border(iscn);
1039             svg_path_end();
1040 
1041             movedelta(density, 1);
1042             iscn->v = x;
1043         }
1044         svg_group_end();
1045     }
1046     iscn->dy = 0;
1047     iscn->img = NULL;
1048 
1049 #if ENABLE_QRCODE == 1
1050     _zbar_qr_decode(iscn->qr, iscn, img);
1051 #endif
1052 
1053 #if ENABLE_SQCODE == 1
1054     sq_handler(iscn);
1055     _zbar_sq_decode(iscn->sq, iscn, img);
1056 #endif
1057 
1058     /* FIXME tmp hack to filter bad EAN results */
1059     /* FIXME tmp hack to merge simple case EAN add-ons */
1060     char filter = (!iscn->enable_cache &&
1061                    (density == 1 || CFG(iscn, ZBAR_CFG_Y_DENSITY) == 1));
1062     int nean = 0, naddon = 0;
1063     if(syms->nsyms) {
1064         zbar_symbol_t **symp;
1065         for(symp = &syms->head; *symp; ) {
1066             zbar_symbol_t *sym = *symp;
1067             if(sym->cache_count <= 0 &&
1068                ((sym->type < ZBAR_COMPOSITE && sym->type > ZBAR_PARTIAL) ||
1069                 sym->type == ZBAR_DATABAR ||
1070                 sym->type == ZBAR_DATABAR_EXP ||
1071                 sym->type == ZBAR_CODABAR))
1072             {
1073 	        if((sym->type == ZBAR_CODABAR || filter) && sym->quality < 4) {
1074                     if(iscn->enable_cache) {
1075                         /* revert cache update */
1076                         zbar_symbol_t *entry = cache_lookup(iscn, sym);
1077                         if(entry)
1078                             entry->cache_count--;
1079                         else
1080                             assert(0);
1081                     }
1082 
1083                     /* recycle */
1084                     *symp = sym->next;
1085                     syms->nsyms--;
1086                     sym->next = NULL;
1087                     _zbar_image_scanner_recycle_syms(iscn, sym);
1088                     continue;
1089                 }
1090                 else if(sym->type < ZBAR_COMPOSITE &&
1091                         sym->type != ZBAR_ISBN10)
1092                 {
1093                     if(sym->type > ZBAR_EAN5)
1094                         nean++;
1095                     else
1096                         naddon++;
1097                 }
1098             }
1099             symp = &sym->next;
1100         }
1101 
1102         if(nean == 1 && naddon == 1 && iscn->ean_config) {
1103             /* create container symbol for composite result */
1104             zbar_symbol_t *ean = NULL, *addon = NULL;
1105             for(symp = &syms->head; *symp; ) {
1106                 zbar_symbol_t *sym = *symp;
1107                 if(sym->type < ZBAR_COMPOSITE && sym->type > ZBAR_PARTIAL) {
1108                     /* move to composite */
1109                     *symp = sym->next;
1110                     syms->nsyms--;
1111                     sym->next = NULL;
1112                     if(sym->type <= ZBAR_EAN5)
1113                         addon = sym;
1114                     else
1115                         ean = sym;
1116                 }
1117                 else
1118                     symp = &sym->next;
1119             }
1120             assert(ean);
1121             assert(addon);
1122 
1123             int datalen = ean->datalen + addon->datalen + 1;
1124             zbar_symbol_t *ean_sym =
1125                 _zbar_image_scanner_alloc_sym(iscn, ZBAR_COMPOSITE, datalen);
1126             ean_sym->orient = ean->orient;
1127             ean_sym->syms = _zbar_symbol_set_create();
1128             memcpy(ean_sym->data, ean->data, ean->datalen);
1129             memcpy(ean_sym->data + ean->datalen,
1130                    addon->data, addon->datalen + 1);
1131             ean_sym->syms->head = ean;
1132             ean->next = addon;
1133             ean_sym->syms->nsyms = 2;
1134             _zbar_image_scanner_add_sym(iscn, ean_sym);
1135         }
1136     }
1137     return syms;
1138 }
1139 
zbar_scan_image(zbar_image_scanner_t * iscn,zbar_image_t * img)1140 int zbar_scan_image(zbar_image_scanner_t *iscn,
1141                     zbar_image_t *img)
1142 {
1143     zbar_symbol_set_t *syms;
1144     zbar_image_t *inv = NULL;
1145 
1146     syms = _zbar_scan_image(iscn, img);
1147     if (!syms)
1148         return -1;
1149 
1150     if(!syms->nsyms && TEST_CFG(iscn, ZBAR_CFG_TEST_INVERTED)) {
1151         inv = _zbar_image_copy (img, 1);
1152         if (inv) {
1153             if(iscn->cache) {
1154                 /* recycle all cached syms, if any */
1155                 _zbar_image_scanner_recycle_syms(iscn, iscn->cache);
1156                 iscn->cache = NULL;
1157             }
1158             syms = _zbar_scan_image(iscn, inv);
1159             _zbar_image_swap_symbols(img, inv);
1160         }
1161     }
1162 
1163     if(syms->nsyms && iscn->handler)
1164         iscn->handler(img, iscn->userdata);
1165 #ifdef HAVE_DBUS
1166     if(iscn->is_dbus_enabled)
1167         zbar_send_code_via_dbus(iscn, img);
1168 #endif
1169 
1170     svg_close();
1171 
1172     if (inv)
1173         zbar_image_destroy(inv);
1174 
1175     return(syms->nsyms);
1176 }
1177 
zbar_image_scanner_request_dbus(zbar_image_scanner_t * scanner,int req_dbus_enabled)1178 int zbar_image_scanner_request_dbus(zbar_image_scanner_t *scanner,
1179                                     int req_dbus_enabled)
1180 {
1181 #ifdef HAVE_DBUS
1182     scanner->is_dbus_enabled = req_dbus_enabled;
1183     return 0;
1184 #else
1185     return 1;
1186 #endif
1187 }
1188 
1189 #ifdef DEBUG_SVG
1190 /* FIXME lame...*/
1191 # include "svg.c"
1192 #endif
1193