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 "error.h"
25 #include "image.h"
26 #include "refcnt.h"
27 
zbar_image_create()28 zbar_image_t *zbar_image_create ()
29 {
30     zbar_image_t *img = calloc(1, sizeof(zbar_image_t));
31     _zbar_refcnt_init();
32     _zbar_image_refcnt(img, 1);
33     img->srcidx = -1;
34     return(img);
35 }
36 
_zbar_image_free(zbar_image_t * img)37 void _zbar_image_free (zbar_image_t *img)
38 {
39     if(img->syms) {
40         zbar_symbol_set_ref(img->syms, -1);
41         img->syms = NULL;
42     }
43     free(img);
44 }
45 
zbar_image_destroy(zbar_image_t * img)46 void zbar_image_destroy (zbar_image_t *img)
47 {
48     _zbar_image_refcnt(img, -1);
49 }
50 
zbar_image_ref(zbar_image_t * img,int refs)51 void zbar_image_ref (zbar_image_t *img,
52                      int refs)
53 {
54     _zbar_image_refcnt(img, refs);
55 }
56 
zbar_image_get_format(const zbar_image_t * img)57 unsigned long zbar_image_get_format (const zbar_image_t *img)
58 {
59     return(img->format);
60 }
61 
zbar_image_get_sequence(const zbar_image_t * img)62 unsigned zbar_image_get_sequence (const zbar_image_t *img)
63 {
64     return(img->seq);
65 }
66 
zbar_image_get_width(const zbar_image_t * img)67 unsigned zbar_image_get_width (const zbar_image_t *img)
68 {
69     return(img->width);
70 }
71 
zbar_image_get_height(const zbar_image_t * img)72 unsigned zbar_image_get_height (const zbar_image_t *img)
73 {
74     return(img->height);
75 }
76 
zbar_image_get_size(const zbar_image_t * img,unsigned * w,unsigned * h)77 void zbar_image_get_size (const zbar_image_t *img,
78                           unsigned *w,
79                           unsigned *h)
80 {
81     if(w) *w = img->width;
82     if(h) *h = img->height;
83 }
84 
zbar_image_get_crop(const zbar_image_t * img,unsigned * x,unsigned * y,unsigned * w,unsigned * h)85 void zbar_image_get_crop (const zbar_image_t *img,
86                           unsigned *x,
87                           unsigned *y,
88                           unsigned *w,
89                           unsigned *h)
90 {
91     if(x) *x = img->crop_x;
92     if(y) *y = img->crop_y;
93     if(w) *w = img->crop_w;
94     if(h) *h = img->crop_h;
95 }
96 
zbar_image_get_data(const zbar_image_t * img)97 const void *zbar_image_get_data (const zbar_image_t *img)
98 {
99     return(img->data);
100 }
101 
zbar_image_get_data_length(const zbar_image_t * img)102 unsigned long zbar_image_get_data_length (const zbar_image_t *img)
103 {
104     return(img->datalen);
105 }
106 
zbar_image_set_format(zbar_image_t * img,unsigned long fmt)107 void zbar_image_set_format (zbar_image_t *img,
108                             unsigned long fmt)
109 {
110     img->format = fmt;
111 }
112 
zbar_image_set_sequence(zbar_image_t * img,unsigned seq)113 void zbar_image_set_sequence (zbar_image_t *img,
114                               unsigned seq)
115 {
116     img->seq = seq;
117 }
118 
zbar_image_set_size(zbar_image_t * img,unsigned w,unsigned h)119 void zbar_image_set_size (zbar_image_t *img,
120                           unsigned w,
121                           unsigned h)
122 {
123     img->crop_x = img->crop_y = 0;
124     img->width = img->crop_w = w;
125     img->height = img->crop_h = h;
126 }
127 
zbar_image_set_crop(zbar_image_t * img,unsigned x,unsigned y,unsigned w,unsigned h)128 void zbar_image_set_crop (zbar_image_t *img,
129                           unsigned x,
130                           unsigned y,
131                           unsigned w,
132                           unsigned h)
133 {
134     unsigned img_w = img->width;
135     if(x > img_w) x = img_w;
136     if(x + w > img_w) w = img_w - x;
137     img->crop_x = x;
138     img->crop_w = w;
139 
140     unsigned img_h = img->height;
141     if(y > img_h) y = img_h;
142     if(y + h > img_h) h = img_h - y;
143     img->crop_y = y;
144     img->crop_h = h;
145 }
146 
zbar_image_free_data(zbar_image_t * img)147 inline void zbar_image_free_data (zbar_image_t *img)
148 {
149     if(!img)
150         return;
151     if(img->src) {
152         zbar_image_t *newimg;
153         /* replace video image w/new copy */
154         assert(img->refcnt); /* FIXME needs lock */
155         newimg = zbar_image_create();
156         memcpy(newimg, img, sizeof(zbar_image_t));
157         /* recycle video image */
158         newimg->cleanup(newimg);
159         /* detach old image from src */
160         img->cleanup = NULL;
161         img->src = NULL;
162         img->srcidx = -1;
163     }
164     else if(img->cleanup && img->data) {
165         if(img->cleanup != zbar_image_free_data) {
166             /* using function address to detect this case is a bad idea;
167              * windows link libraries add an extra layer of indirection...
168              * this works around that problem (bug #2796277)
169              */
170             zbar_image_cleanup_handler_t *cleanup = img->cleanup;
171             img->cleanup = zbar_image_free_data;
172             cleanup(img);
173         }
174         else
175             free((void*)img->data);
176     }
177     img->data = NULL;
178 }
179 
zbar_image_set_data(zbar_image_t * img,const void * data,unsigned long len,zbar_image_cleanup_handler_t * cleanup)180 void zbar_image_set_data (zbar_image_t *img,
181                           const void *data,
182                           unsigned long len,
183                           zbar_image_cleanup_handler_t *cleanup)
184 {
185     zbar_image_free_data(img);
186     img->data = data;
187     img->datalen = len;
188     img->cleanup = cleanup;
189 }
190 
zbar_image_set_userdata(zbar_image_t * img,void * userdata)191 void zbar_image_set_userdata (zbar_image_t *img,
192                               void *userdata)
193 {
194     img->userdata = userdata;
195 }
196 
zbar_image_get_userdata(const zbar_image_t * img)197 void *zbar_image_get_userdata (const zbar_image_t *img)
198 {
199     return(img->userdata);
200 }
201 
zbar_image_copy(const zbar_image_t * src)202 zbar_image_t *zbar_image_copy (const zbar_image_t *src)
203 {
204     return _zbar_image_copy(src, 0);
205 }
206 
zbar_image_get_symbols(const zbar_image_t * img)207 const zbar_symbol_set_t *zbar_image_get_symbols (const zbar_image_t *img)
208 {
209     return(img->syms);
210 }
211 
zbar_image_set_symbols(zbar_image_t * img,const zbar_symbol_set_t * syms)212 void zbar_image_set_symbols (zbar_image_t *img,
213                              const zbar_symbol_set_t *syms)
214 {
215     if(syms)
216         zbar_symbol_set_ref(syms, 1);
217     if(img->syms)
218         zbar_symbol_set_ref(img->syms, -1);
219     img->syms = (zbar_symbol_set_t*)syms;
220 }
221 
zbar_image_first_symbol(const zbar_image_t * img)222 const zbar_symbol_t *zbar_image_first_symbol (const zbar_image_t *img)
223 {
224     return((img->syms) ? img->syms->head : NULL);
225 }
226 
227 typedef struct zimg_hdr_s {
228     uint32_t magic, format;
229     uint16_t width, height;
230     uint32_t size;
231 } zimg_hdr_t;
232 
zbar_image_write(const zbar_image_t * img,const char * filebase)233 int zbar_image_write (const zbar_image_t *img,
234                       const char *filebase)
235 {
236     int len = strlen(filebase) + 16;
237     char *filename = malloc(len);
238     int n = 0, rc = 0;
239     FILE *f;
240     zimg_hdr_t hdr;
241     strcpy(filename, filebase);
242     if((img->format & 0xff) >= ' ')
243         n = snprintf(filename, len, "%s.%.4s.zimg",
244                      filebase, (char*)&img->format);
245     else
246         n = snprintf(filename, len, "%s.%08" PRIx32 ".zimg",
247                      filebase, img->format);
248     assert(n < len - 1);
249     filename[len - 1] = '\0';
250 
251     zprintf(1, "dumping %.4s(%08" PRIx32 ") image to %s\n",
252             (char*)&img->format, img->format, filename);
253 
254     f = fopen(filename, "w");
255     if(!f) {
256 #ifdef HAVE_ERRNO_H
257         rc = errno;
258         zprintf(1, "ERROR opening %s: %s\n", filename, strerror(rc));
259 #else
260         rc = 1;
261 #endif
262         goto error;
263     }
264 
265     hdr.magic = 0x676d697a;
266     hdr.format = img->format;
267     hdr.width = img->width;
268     hdr.height = img->height;
269     hdr.size = img->datalen;
270 
271     if(fwrite(&hdr, sizeof(hdr), 1, f) != 1 ||
272        fwrite(img->data, 1, img->datalen, f) != img->datalen) {
273 #ifdef HAVE_ERRNO_H
274         rc = errno;
275         zprintf(1, "ERROR writing %s: %s\n", filename, strerror(rc));
276 #else
277         rc = 1;
278 #endif
279         fclose(f);
280         goto error;
281     }
282 
283     rc = fclose(f);
284 
285 error:
286     free(filename);
287     return(rc);
288 }
289 
290 #ifdef DEBUG_SVG
291 # include <png.h>
292 
zbar_image_write_png(const zbar_image_t * img,const char * filename)293 int zbar_image_write_png (const zbar_image_t *img,
294                           const char *filename)
295 {
296     int rc = -1;
297     FILE *file = NULL;
298     png_struct *png = NULL;
299     png_info *info = NULL;
300     const uint8_t **rows = NULL;
301 
302     rows = malloc(img->height * sizeof(*rows));
303     if(!rows)
304         goto done;
305 
306     rows[0] = img->data;
307     int y;
308     for(y = 1; y < img->height; y++)
309         rows[y] = rows[y - 1] + img->width;
310 
311     file = fopen(filename, "wb");
312     if(!file)
313         goto done;
314 
315     png = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
316     if(!png)
317         goto done;
318 
319     info = png_create_info_struct(png);
320     if(!info)
321         goto done;
322 
323     if(setjmp(png_jmpbuf(png)))
324         goto done;
325 
326     png_init_io(png, file);
327     png_set_compression_level(png, 9);
328     png_set_IHDR(png, info, img->width, img->height, 8, PNG_COLOR_TYPE_GRAY,
329                  PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
330                  PNG_FILTER_TYPE_DEFAULT);
331 
332     png_set_rows(png, info, (void*)rows);
333     png_write_png(png, info, PNG_TRANSFORM_IDENTITY, NULL);
334 
335     png_write_end(png,info);
336     rc = 0;
337 
338 done:
339     if(png)
340         png_destroy_write_struct(&png, &info);
341     if(rows)
342         free(rows);
343     if(file)
344         fclose(file);
345     return(rc);
346 }
347 
348 #endif
349