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