Mercurial > geeqie
annotate src/image-load.c @ 54:b58cac75ad12
Thu Jun 9 22:23:18 2005 John Ellis <johne@verizon.net>
* exif.[ch]: A lot of code clean up, add generic tiff header parser,
remove use of packed structures to interpret tiff file format,
fix possible endless loops in tiff parser with corrupt IFD tables,
and fix possible overflow in jpeg exif parser.
* format_canon.[ch]: Add additional makernote values, plus a few
spelling fixes. Header update.
* format_fuji.[ch]: Header update.
* format_nikon.[ch]: Updates to use new tiff parsing utils in exif.c,
code cleanup. Header update.
* format_raw.[ch]: Add pathname argument to file descriptor version of
raw parser to quickly rule out non-raw files based on file extension.
Add raw header match type to check for tiff "make" field value.
* image-load.c (image_loader_begin): Add image filename for raw parser.
author | gqview |
---|---|
date | Fri, 10 Jun 2005 02:44:36 +0000 |
parents | 7cfa60beda76 |
children | 9c0c402b0ef3 |
rev | line source |
---|---|
9 | 1 /* |
2 * GQview | |
3 * (C) 2004 John Ellis | |
4 * | |
5 * Author: John Ellis | |
6 * | |
7 * This software is released under the GNU General Public License (GNU GPL). | |
8 * Please read the included file COPYING for more information. | |
9 * This software comes with no warranty of any kind, use at your own risk! | |
10 */ | |
11 | |
12 | |
13 #include "gqview.h" | |
14 #include "image-load.h" | |
15 | |
43
ee03f36e9e4b
Sun May 15 21:40:26 2005 John Ellis <johne@verizon.net>
gqview
parents:
14
diff
changeset
|
16 #include "format_raw.h" |
9 | 17 #include "ui_fileops.h" |
18 | |
19 #include <fcntl.h> | |
20 | |
21 | |
22 /* bytes to read from file per read() */ | |
23 #define IMAGE_LOADER_BUFFER_SIZE 512 | |
24 | |
25 /* the number of bytes to read per idle call (define x IMAGE_LOADER_BUFFER_SIZE) */ | |
26 #define IMAGE_LOADER_BUFFER_DEFAULT_COUNT 1 | |
27 | |
28 static void image_loader_sync_pixbuf(ImageLoader *il) | |
29 { | |
30 GdkPixbuf *pb; | |
31 | |
32 if (!il->loader) return; | |
33 | |
34 pb = gdk_pixbuf_loader_get_pixbuf(il->loader); | |
35 | |
36 if (pb == il->pixbuf) return; | |
37 | |
38 if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf); | |
39 il->pixbuf = pb; | |
40 if (il->pixbuf) gdk_pixbuf_ref(il->pixbuf); | |
41 } | |
42 | |
43 static void image_loader_area_cb(GdkPixbufLoader *loader, | |
44 guint x, guint y, guint w, guint h, | |
45 gpointer data) | |
46 { | |
47 ImageLoader *il = data; | |
48 | |
49 if (il->func_area_ready) | |
50 { | |
51 if (!il->pixbuf) | |
52 { | |
53 image_loader_sync_pixbuf(il); | |
54 if (!il->pixbuf) | |
55 { | |
56 printf("critical: area_ready signal with NULL pixbuf (out of mem?)\n"); | |
57 } | |
58 } | |
59 il->func_area_ready(il, x, y, w, h, il->data_area_ready); | |
60 } | |
61 } | |
62 | |
63 static void image_loader_size_cb(GdkPixbufLoader *loader, | |
64 gint width, gint height, gpointer data) | |
65 { | |
66 ImageLoader *il = data; | |
67 GdkPixbufFormat *format; | |
68 gchar **mime_types; | |
69 gint scale = FALSE; | |
70 gint n; | |
71 | |
72 if (il->requested_width < 1 || il->requested_height < 1) return; | |
73 | |
74 format = gdk_pixbuf_loader_get_format(loader); | |
75 if (!format) return; | |
76 | |
77 mime_types = gdk_pixbuf_format_get_mime_types(format); | |
78 n = 0; | |
79 while (mime_types[n]) | |
80 { | |
81 if (strstr(mime_types[n], "jpeg")) scale = TRUE; | |
82 n++; | |
83 } | |
84 g_strfreev(mime_types); | |
85 | |
86 if (!scale) return; | |
87 | |
88 if (width > il->requested_width || height > il->requested_height) | |
89 { | |
90 gint nw, nh; | |
91 | |
92 if (((gdouble)il->requested_width / width) < ((gdouble)il->requested_height / height)) | |
93 { | |
94 nw = il->requested_width; | |
95 nh = (gdouble)nw / width * height; | |
96 if (nh < 1) nh = 1; | |
97 } | |
98 else | |
99 { | |
100 nh = il->requested_height; | |
101 nw = (gdouble)nh / height * width; | |
102 if (nw < 1) nw = 1; | |
103 } | |
104 | |
105 gdk_pixbuf_loader_set_size(loader, nw, nh); | |
14
25335c62cd9b
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
106 il->shrunk = TRUE; |
9 | 107 } |
108 } | |
109 | |
110 static void image_loader_stop(ImageLoader *il) | |
111 { | |
112 if (!il) return; | |
113 | |
114 if (il->idle_id != -1) | |
115 { | |
116 g_source_remove(il->idle_id); | |
117 il->idle_id = -1; | |
118 } | |
119 | |
120 if (il->loader) | |
121 { | |
122 /* some loaders do not have a pixbuf till close, order is important here */ | |
123 gdk_pixbuf_loader_close(il->loader, NULL); | |
124 image_loader_sync_pixbuf(il); | |
125 g_object_unref(G_OBJECT(il->loader)); | |
126 il->loader = NULL; | |
127 } | |
128 | |
129 if (il->load_fd != -1) | |
130 { | |
131 close(il->load_fd); | |
132 il->load_fd = -1; | |
133 } | |
134 | |
135 il->done = TRUE; | |
136 } | |
137 | |
138 static void image_loader_done(ImageLoader *il) | |
139 { | |
140 image_loader_stop(il); | |
141 | |
142 if (il->func_done) il->func_done(il, il->data_done); | |
143 } | |
144 | |
145 static gint image_loader_done_delay_cb(gpointer data) | |
146 { | |
147 ImageLoader *il = data; | |
148 | |
149 il->idle_done_id = -1; | |
150 image_loader_done(il); | |
151 return FALSE; | |
152 } | |
153 | |
154 static void image_loader_done_delay(ImageLoader *il) | |
155 { | |
156 if (il->idle_done_id == -1) il->idle_done_id = g_idle_add_full(il->idle_priority, | |
157 image_loader_done_delay_cb, il, NULL); | |
158 } | |
159 | |
160 static void image_loader_error(ImageLoader *il) | |
161 { | |
162 image_loader_stop(il); | |
163 | |
164 if (debug) printf("pixbuf_loader reported load error for: %s\n", il->path); | |
165 | |
166 if (il->func_error) il->func_error(il, il->data_error); | |
167 } | |
168 | |
169 static gint image_loader_idle_cb(gpointer data) | |
170 { | |
171 ImageLoader *il = data; | |
172 guchar buf[IMAGE_LOADER_BUFFER_SIZE]; | |
173 gint b; | |
174 gint c; | |
175 | |
176 if (!il) return FALSE; | |
177 | |
178 if (il->idle_id == -1) return FALSE; | |
179 | |
180 c = il->buffer_size ? il->buffer_size : 1; | |
181 while (c > 0) | |
182 { | |
183 b = read(il->load_fd, &buf, sizeof(buf)); | |
184 | |
185 if (b == 0) | |
186 { | |
187 image_loader_done(il); | |
188 return FALSE; | |
189 } | |
190 | |
191 if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, buf, b, NULL))) | |
192 { | |
193 image_loader_error(il); | |
194 return FALSE; | |
195 } | |
196 | |
197 il->bytes_read += b; | |
198 | |
199 c--; | |
200 } | |
201 | |
202 if (il->func_percent && il->bytes_total > 0) | |
203 { | |
204 il->func_percent(il, (gdouble)il->bytes_read / il->bytes_total, il->data_percent); | |
205 } | |
206 | |
207 return TRUE; | |
208 } | |
209 | |
210 static gint image_loader_begin(ImageLoader *il) | |
211 { | |
212 guchar buf[IMAGE_LOADER_BUFFER_SIZE]; | |
213 int b; | |
43
ee03f36e9e4b
Sun May 15 21:40:26 2005 John Ellis <johne@verizon.net>
gqview
parents:
14
diff
changeset
|
214 unsigned int offset = 0; |
9 | 215 |
216 if (!il->loader || il->pixbuf) return FALSE; | |
217 | |
218 b = read(il->load_fd, &buf, sizeof(buf)); | |
219 | |
45
7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
gqview
parents:
43
diff
changeset
|
220 if (b > 1 && |
54
b58cac75ad12
Thu Jun 9 22:23:18 2005 John Ellis <johne@verizon.net>
gqview
parents:
45
diff
changeset
|
221 format_raw_img_exif_offsets_fd(il->load_fd, il->path, buf, b, &offset, NULL)) |
45
7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
gqview
parents:
43
diff
changeset
|
222 { |
7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
gqview
parents:
43
diff
changeset
|
223 if (debug) printf("Raw file %s contains embedded image\n", il->path); |
7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
gqview
parents:
43
diff
changeset
|
224 |
7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
gqview
parents:
43
diff
changeset
|
225 b = read(il->load_fd, &buf, sizeof(buf)); |
7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
gqview
parents:
43
diff
changeset
|
226 } |
7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
gqview
parents:
43
diff
changeset
|
227 |
9 | 228 if (b < 1) |
229 { | |
230 image_loader_stop(il); | |
231 return FALSE; | |
232 } | |
233 | |
45
7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
gqview
parents:
43
diff
changeset
|
234 if (gdk_pixbuf_loader_write(il->loader, buf, b, NULL)) |
9 | 235 { |
45
7cfa60beda76
Thu May 26 13:57:19 2005 John Ellis <johne@verizon.net>
gqview
parents:
43
diff
changeset
|
236 il->bytes_read += b + offset; |
9 | 237 |
238 if (b < sizeof(buf)) | |
239 { | |
240 /* end of file already */ | |
241 | |
242 image_loader_stop(il); | |
243 | |
244 if (!il->pixbuf) return FALSE; | |
245 | |
246 image_loader_done_delay(il); | |
247 return TRUE; | |
248 } | |
249 else | |
250 { | |
251 /* larger file */ | |
252 | |
253 /* read until size is known */ | |
254 while(il->loader && !gdk_pixbuf_loader_get_pixbuf(il->loader) && b > 0) | |
255 { | |
256 b = read(il->load_fd, &buf, sizeof(buf)); | |
257 if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, buf, b, NULL))) | |
258 { | |
259 image_loader_stop(il); | |
260 return FALSE; | |
261 } | |
262 il->bytes_read += b; | |
263 } | |
264 if (!il->pixbuf) image_loader_sync_pixbuf(il); | |
265 | |
266 if (il->bytes_read == il->bytes_total || b < sizeof(buf)) | |
267 { | |
268 /* done, handle (broken) loaders that do not have pixbuf till close */ | |
269 image_loader_stop(il); | |
270 | |
271 if (!il->pixbuf) return FALSE; | |
272 | |
273 image_loader_done_delay(il); | |
274 return TRUE; | |
275 } | |
276 | |
277 if (!il->pixbuf) | |
278 { | |
279 image_loader_stop(il); | |
280 return FALSE; | |
281 } | |
282 | |
283 /* finally, progressive loading :) */ | |
284 il->idle_id = g_idle_add_full(il->idle_priority, image_loader_idle_cb, il, NULL); | |
285 return TRUE; | |
286 } | |
287 } | |
288 else | |
289 { | |
290 image_loader_stop(il); | |
291 return FALSE; | |
292 } | |
293 | |
294 return TRUE; | |
295 } | |
296 | |
297 static gint image_loader_setup(ImageLoader *il) | |
298 { | |
299 struct stat st; | |
300 gchar *pathl; | |
301 | |
302 if (!il || il->load_fd != -1 || il->loader) return FALSE; | |
303 | |
304 pathl = path_from_utf8(il->path); | |
305 il->load_fd = open(pathl, O_RDONLY | O_NONBLOCK); | |
306 g_free(pathl); | |
307 if (il->load_fd == -1) return FALSE; | |
308 | |
309 if (fstat(il->load_fd, &st) == 0) | |
310 { | |
311 il->bytes_total = st.st_size; | |
312 } | |
313 | |
314 il->loader = gdk_pixbuf_loader_new(); | |
315 g_signal_connect(G_OBJECT(il->loader), "area_updated", | |
316 G_CALLBACK(image_loader_area_cb), il); | |
317 g_signal_connect(G_OBJECT(il->loader), "size_prepared", | |
318 G_CALLBACK(image_loader_size_cb), il); | |
319 | |
14
25335c62cd9b
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
320 il->shrunk = FALSE; |
25335c62cd9b
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
321 |
9 | 322 return image_loader_begin(il); |
323 } | |
324 | |
325 ImageLoader *image_loader_new(const gchar *path) | |
326 { | |
327 ImageLoader *il; | |
328 | |
329 if (!path) return NULL; | |
330 | |
331 il = g_new0(ImageLoader, 1); | |
332 if (path) il->path = g_strdup(path); | |
333 il->pixbuf = NULL; | |
334 il->idle_id = -1; | |
335 il->idle_priority = G_PRIORITY_DEFAULT_IDLE; | |
336 il->done = FALSE; | |
337 il->loader = NULL; | |
338 il->load_fd = -1; | |
339 | |
340 il->bytes_read = 0; | |
341 il->bytes_total = 0; | |
342 | |
343 il->idle_done_id = -1; | |
344 | |
345 il->buffer_size = IMAGE_LOADER_BUFFER_DEFAULT_COUNT; | |
346 | |
347 il->requested_width = 0; | |
348 il->requested_height = 0; | |
14
25335c62cd9b
##### Note: GQview CVS on sourceforge is not always up to date, please use #####
gqview
parents:
9
diff
changeset
|
349 il->shrunk = FALSE; |
9 | 350 |
351 return il; | |
352 } | |
353 | |
354 void image_loader_free(ImageLoader *il) | |
355 { | |
356 if (!il) return; | |
357 | |
358 image_loader_stop(il); | |
359 if (il->idle_done_id != -1) g_source_remove(il->idle_done_id); | |
360 if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf); | |
361 g_free(il->path); | |
362 g_free(il); | |
363 } | |
364 | |
365 /* don't forget to gdk_pixbuf_ref() it if you want to use it after image_loader_free() */ | |
366 GdkPixbuf *image_loader_get_pixbuf(ImageLoader *il) | |
367 { | |
368 if (!il) return NULL; | |
369 | |
370 return il->pixbuf; | |
371 } | |
372 | |
373 gchar *image_loader_get_format(ImageLoader *il) | |
374 { | |
375 GdkPixbufFormat *format; | |
376 gchar **mimev; | |
377 gchar *mime; | |
378 | |
379 if (!il || !il->loader) return NULL; | |
380 | |
381 format = gdk_pixbuf_loader_get_format(il->loader); | |
382 if (!format) return NULL; | |
383 | |
384 mimev = gdk_pixbuf_format_get_mime_types(format); | |
385 if (!mimev) return NULL; | |
386 | |
387 /* return first member of mimev, as GdkPixbufLoader has no way to tell us which exact one ? */ | |
388 mime = g_strdup(mimev[0]); | |
389 g_strfreev(mimev); | |
390 | |
391 return mime; | |
392 } | |
393 | |
394 void image_loader_set_area_ready_func(ImageLoader *il, | |
395 void (*func_area_ready)(ImageLoader *, guint, guint, guint, guint, gpointer), | |
396 gpointer data_area_ready) | |
397 { | |
398 if (!il) return; | |
399 | |
400 il->func_area_ready = func_area_ready; | |
401 il->data_area_ready = data_area_ready; | |
402 } | |
403 | |
404 void image_loader_set_error_func(ImageLoader *il, | |
405 void (*func_error)(ImageLoader *, gpointer), | |
406 gpointer data_error) | |
407 { | |
408 if (!il) return; | |
409 | |
410 il->func_error = func_error; | |
411 il->data_error = data_error; | |
412 } | |
413 | |
414 void image_loader_set_percent_func(ImageLoader *il, | |
415 void (*func_percent)(ImageLoader *, gdouble, gpointer), | |
416 gpointer data_percent) | |
417 { | |
418 if (!il) return; | |
419 | |
420 il->func_percent = func_percent; | |
421 il->data_percent = data_percent; | |
422 } | |
423 | |
424 void image_loader_set_requested_size(ImageLoader *il, gint width, gint height) | |
425 { | |
426 if (!il) return; | |
427 | |
428 il->requested_width = width; | |
429 il->requested_height = height; | |
430 } | |
431 | |
432 void image_loader_set_buffer_size(ImageLoader *il, guint size) | |
433 { | |
434 if (!il) return; | |
435 | |
436 il->buffer_size = size ? size : 1; | |
437 } | |
438 | |
439 void image_loader_set_priority(ImageLoader *il, gint priority) | |
440 { | |
441 if (!il) return; | |
442 | |
443 il->idle_priority = priority; | |
444 } | |
445 | |
446 gint image_loader_start(ImageLoader *il, void (*func_done)(ImageLoader *, gpointer), gpointer data_done) | |
447 { | |
448 if (!il) return FALSE; | |
449 | |
450 if (!il->path) return FALSE; | |
451 | |
452 il->func_done = func_done; | |
453 il->data_done = data_done; | |
454 | |
455 return image_loader_setup(il); | |
456 } | |
457 | |
458 gdouble image_loader_get_percent(ImageLoader *il) | |
459 { | |
460 if (!il || il->bytes_total == 0) return 0.0; | |
461 | |
462 return (gdouble)il->bytes_read / il->bytes_total; | |
463 } | |
464 | |
465 gint image_loader_get_is_done(ImageLoader *il) | |
466 { | |
467 if (!il) return FALSE; | |
468 | |
469 return il->done; | |
470 } | |
471 | |
472 gint image_load_dimensions(const gchar *path, gint *width, gint *height) | |
473 { | |
474 ImageLoader *il; | |
475 gint success; | |
476 | |
477 il = image_loader_new(path); | |
478 | |
479 success = image_loader_start(il, NULL, NULL); | |
480 | |
481 if (success && il->pixbuf) | |
482 { | |
483 if (width) *width = gdk_pixbuf_get_width(il->pixbuf); | |
484 if (height) *height = gdk_pixbuf_get_height(il->pixbuf);; | |
485 } | |
486 else | |
487 { | |
488 if (width) *width = -1; | |
489 if (height) *height = -1; | |
490 } | |
491 | |
492 image_loader_free(il); | |
493 | |
494 return success; | |
495 } | |
496 |