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 "window.h"
25 #include "image.h"
26 #include "timer.h"
27 #include <time.h>       /* clock_gettime */
28 #ifdef HAVE_SYS_TIME_H
29 # include <sys/time.h>   /* gettimeofday */
30 #endif
31 
zbar_window_create()32 zbar_window_t *zbar_window_create ()
33 {
34     zbar_window_t *w = calloc(1, sizeof(zbar_window_t));
35     if(!w)
36         return(NULL);
37     err_init(&w->err, ZBAR_MOD_WINDOW);
38     w->overlay = 1;
39     (void)_zbar_mutex_init(&w->imglock);
40     return(w);
41 }
42 
zbar_window_destroy(zbar_window_t * w)43 void zbar_window_destroy (zbar_window_t *w)
44 {
45     /* detach */
46     zbar_window_attach(w, NULL, 0);
47     err_cleanup(&w->err);
48     _zbar_mutex_destroy(&w->imglock);
49     free(w);
50 }
51 
zbar_window_attach(zbar_window_t * w,void * display,unsigned long drawable)52 int zbar_window_attach (zbar_window_t *w,
53                         void *display,
54                         unsigned long drawable)
55 {
56     /* release image */
57     zbar_window_draw(w, NULL);
58     if(w->cleanup) {
59         w->cleanup(w);
60         w->cleanup = NULL;
61         w->draw_image = NULL;
62     }
63     if(w->formats) {
64         free(w->formats);
65         w->formats = NULL;
66     }
67     w->src_format = 0;
68     w->src_width = w->src_height = 0;
69     w->scaled_size.x = w->scaled_size.y = 0;
70     w->dst_width = w->dst_height = 0;
71     w->max_width = w->max_height = 1 << 15;
72     w->scale_num = w->scale_den = 1;
73     return(_zbar_window_attach(w, display, drawable));
74 }
75 
window_outline_symbol(zbar_window_t * w,uint32_t color,const zbar_symbol_t * sym)76 static void window_outline_symbol (zbar_window_t *w,
77                                    uint32_t color,
78                                    const zbar_symbol_t *sym)
79 {
80     if(sym->syms) {
81         const zbar_symbol_t *s;
82         for(s = sym->syms->head; s; s = s->next)
83             window_outline_symbol(w, 1, s);
84     }
85     _zbar_window_draw_polygon(w, color, sym->pts, sym->npts);
86 }
87 
window_draw_overlay(zbar_window_t * w)88 static inline int window_draw_overlay (zbar_window_t *w)
89 {
90     if(!w->overlay)
91         return(0);
92     if(w->overlay >= 1 && w->image && w->image->syms) {
93         /* FIXME outline each symbol */
94         const zbar_symbol_t *sym = w->image->syms->head;
95         for(; sym; sym = sym->next) {
96             uint32_t color = ((sym->cache_count < 0) ? 4 : 2);
97             if(sym->type == ZBAR_QRCODE || sym->type == ZBAR_SQCODE)
98                 window_outline_symbol(w, color, sym);
99             else {
100                 /* FIXME linear bbox broken */
101                 point_t org = w->scaled_offset;
102                 int i;
103                 for(i = 0; i < sym->npts; i++) {
104                     point_t p = window_scale_pt(w, sym->pts[i]);
105                     p.x += org.x;
106                     p.y += org.y;
107                     if(p.x < 3)
108                         p.x = 3;
109                     else if(p.x > w->width - 4)
110                         p.x = w->width - 4;
111                     if(p.y < 3)
112                         p.y = 3;
113                     else if(p.y > w->height - 4)
114                         p.y = w->height - 4;
115                     _zbar_window_draw_marker(w, color, p);
116                 }
117             }
118         }
119     }
120 
121     if(w->overlay >= 2) {
122         /* calculate/display frame rate */
123         unsigned long time = _zbar_timer_now();
124         if(w->time) {
125             int avg = w->time_avg = (w->time_avg + time - w->time) / 2;
126             point_t p = { -8, -1 };
127             char text[32];
128             sprintf(text, "%d.%01d fps", 1000 / avg, (10000 / avg) % 10);
129             _zbar_window_draw_text(w, 3, p, text);
130         }
131         w->time = time;
132     }
133     return(0);
134 }
135 
zbar_window_redraw(zbar_window_t * w)136 inline int zbar_window_redraw (zbar_window_t *w)
137 {
138     int rc = 0;
139     zbar_image_t *img;
140     if(window_lock(w))
141         return(-1);
142     if(!w->display || _zbar_window_begin(w)) {
143         (void)window_unlock(w);
144         return(-1);
145     }
146 
147     img = w->image;
148     if(w->init && w->draw_image && img) {
149         int format_change = (w->src_format != img->format &&
150                              w->format != img->format);
151         if(format_change) {
152             _zbar_best_format(img->format, &w->format, w->formats);
153             if(!w->format)
154                 rc = err_capture_int(w, SEV_ERROR, ZBAR_ERR_UNSUPPORTED, __func__,
155                                      "no conversion from %x to supported formats",
156                                      img->format);
157             w->src_format = img->format;
158         }
159 
160         if(!rc && (format_change || !w->scaled_size.x || !w->dst_width)) {
161             point_t size = { w->width, w->height };
162             zprintf(24, "init: src=%.4s(%08x) %dx%d dst=%.4s(%08x) %dx%d\n",
163                     (char*)&w->src_format, w->src_format,
164                     w->src_width, w->src_height,
165                     (char*)&w->format, w->format,
166                     w->dst_width, w->dst_height);
167             if(!w->dst_width) {
168                 w->src_width = img->width;
169                 w->src_height = img->height;
170             }
171 
172             if(size.x > w->max_width)
173                 size.x = w->max_width;
174             if(size.y > w->max_height)
175                 size.y = w->max_height;
176 
177             if(size.x * w->src_height < size.y * w->src_width) {
178                 w->scale_num = size.x;
179                 w->scale_den = w->src_width;
180             }
181             else {
182                 w->scale_num = size.y;
183                 w->scale_den = w->src_height;
184             }
185 
186             rc = w->init(w, img, format_change);
187 
188             if(!rc) {
189                 size.x = w->src_width;
190                 size.y = w->src_height;
191                 w->scaled_size = size = window_scale_pt(w, size);
192                 w->scaled_offset.x = ((int)w->width - size.x) / 2;
193                 w->scaled_offset.y = ((int)w->height - size.y) / 2;
194                 zprintf(24, "scale: src=%dx%d win=%dx%d by %d/%d => %dx%d @%d,%d\n",
195                         w->src_width, w->src_height, w->width, w->height,
196                         w->scale_num, w->scale_den,
197                         size.x, size.y, w->scaled_offset.x, w->scaled_offset.y);
198             }
199             else {
200                 /* unable to display this image */
201                 _zbar_image_refcnt(img, -1);
202                 w->image = img = NULL;
203             }
204         }
205 
206         if(!rc &&
207            (img->format != w->format ||
208             img->width != w->dst_width ||
209             img->height != w->dst_height)) {
210             /* save *converted* image for redraw */
211             zprintf(48, "convert: %.4s(%08x) %dx%d => %.4s(%08x) %dx%d\n",
212                     (char*)&img->format, img->format, img->width, img->height,
213                     (char*)&w->format, w->format, w->dst_width, w->dst_height);
214             w->image = zbar_image_convert_resize(img, w->format,
215                                                  w->dst_width, w->dst_height);
216             w->image->syms = img->syms;
217             if(img->syms)
218                 zbar_symbol_set_ref(img->syms, 1);
219             zbar_image_destroy(img);
220             img = w->image;
221         }
222 
223         if(!rc) {
224             point_t org;
225             rc = w->draw_image(w, img);
226 
227             org = w->scaled_offset;
228             if(org.x > 0) {
229                 point_t p = { 0, org.y };
230                 point_t s = { org.x, w->scaled_size.y };
231                 _zbar_window_fill_rect(w, 0, p, s);
232                 s.x = w->width - w->scaled_size.x - s.x;
233                 if(s.x > 0) {
234                     p.x = w->width - s.x;
235                     _zbar_window_fill_rect(w, 0, p, s);
236                 }
237             }
238             if(org.y > 0) {
239                 point_t p = { 0, 0 };
240                 point_t s = { w->width, org.y };
241                 _zbar_window_fill_rect(w, 0, p, s);
242                 s.y = w->height - w->scaled_size.y - s.y;
243                 if(s.y > 0) {
244                     p.y = w->height - s.y;
245                     _zbar_window_fill_rect(w, 0, p, s);
246                 }
247             }
248         }
249         if(!rc)
250             rc = window_draw_overlay(w);
251     }
252     else
253         rc = 1;
254 
255     if(rc)
256         rc = _zbar_window_draw_logo(w);
257 
258     _zbar_window_end(w);
259     (void)window_unlock(w);
260     return(rc);
261 }
262 
zbar_window_draw(zbar_window_t * w,zbar_image_t * img)263 int zbar_window_draw (zbar_window_t *w,
264                       zbar_image_t *img)
265 {
266     if(window_lock(w))
267         return(-1);
268     if(!w->draw_image)
269         img = NULL;
270     if(img) {
271         _zbar_image_refcnt(img, 1);
272         if(img->width != w->src_width ||
273            img->height != w->src_height)
274             w->dst_width = 0;
275     }
276     if(w->image)
277         _zbar_image_refcnt(w->image, -1);
278     w->image = img;
279     return(window_unlock(w));
280 }
281 
zbar_window_set_overlay(zbar_window_t * w,int lvl)282 void zbar_window_set_overlay (zbar_window_t *w,
283                               int lvl)
284 {
285     if(lvl < 0)
286         lvl = 0;
287     if(lvl > 2)
288         lvl = 2;
289     if(window_lock(w))
290         return;
291     if(w->overlay != lvl)
292         w->overlay = lvl;
293     (void)window_unlock(w);
294 }
295 
zbar_window_get_overlay(const zbar_window_t * w)296 int zbar_window_get_overlay (const zbar_window_t *w)
297 {
298     zbar_window_t *ncw = (zbar_window_t*)w;
299     int lvl;
300     if(window_lock(ncw))
301         return(-1);
302     lvl = w->overlay;
303     (void)window_unlock(ncw);
304     return(lvl);
305 }
306 
zbar_window_resize(zbar_window_t * w,unsigned width,unsigned height)307 int zbar_window_resize (zbar_window_t *w,
308                         unsigned width,
309                         unsigned height)
310 {
311     if(window_lock(w))
312         return(-1);
313     w->width = width;
314     w->height = height;
315     w->scaled_size.x = 0;
316     _zbar_window_resize(w);
317     return(window_unlock(w));
318 }
319