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