Mercurial > geeqie
comparison src/image-load.c @ 9:d907d608745f
Sync to GQview 1.5.9 release.
########
DO NOT BASE ENHANCEMENTS OR TRANSLATION UPDATES ON CODE IN THIS CVS!
This CVS is never up to date with current development and is provided
solely for reference purposes, please use the latest official release
package when making any changes or translation updates.
########
author | gqview |
---|---|
date | Sat, 26 Feb 2005 00:13:35 +0000 |
parents | |
children | 25335c62cd9b |
comparison
equal
deleted
inserted
replaced
8:e0d0593d519e | 9:d907d608745f |
---|---|
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 | |
16 #include "ui_fileops.h" | |
17 | |
18 #include <fcntl.h> | |
19 | |
20 | |
21 /* bytes to read from file per read() */ | |
22 #define IMAGE_LOADER_BUFFER_SIZE 512 | |
23 | |
24 /* the number of bytes to read per idle call (define x IMAGE_LOADER_BUFFER_SIZE) */ | |
25 #define IMAGE_LOADER_BUFFER_DEFAULT_COUNT 1 | |
26 | |
27 static void image_loader_sync_pixbuf(ImageLoader *il) | |
28 { | |
29 GdkPixbuf *pb; | |
30 | |
31 if (!il->loader) return; | |
32 | |
33 pb = gdk_pixbuf_loader_get_pixbuf(il->loader); | |
34 | |
35 if (pb == il->pixbuf) return; | |
36 | |
37 if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf); | |
38 il->pixbuf = pb; | |
39 if (il->pixbuf) gdk_pixbuf_ref(il->pixbuf); | |
40 } | |
41 | |
42 static void image_loader_area_cb(GdkPixbufLoader *loader, | |
43 guint x, guint y, guint w, guint h, | |
44 gpointer data) | |
45 { | |
46 ImageLoader *il = data; | |
47 | |
48 if (il->func_area_ready) | |
49 { | |
50 if (!il->pixbuf) | |
51 { | |
52 image_loader_sync_pixbuf(il); | |
53 if (!il->pixbuf) | |
54 { | |
55 printf("critical: area_ready signal with NULL pixbuf (out of mem?)\n"); | |
56 } | |
57 } | |
58 il->func_area_ready(il, x, y, w, h, il->data_area_ready); | |
59 } | |
60 } | |
61 | |
62 static void image_loader_size_cb(GdkPixbufLoader *loader, | |
63 gint width, gint height, gpointer data) | |
64 { | |
65 ImageLoader *il = data; | |
66 GdkPixbufFormat *format; | |
67 gchar **mime_types; | |
68 gint scale = FALSE; | |
69 gint n; | |
70 | |
71 if (il->requested_width < 1 || il->requested_height < 1) return; | |
72 | |
73 format = gdk_pixbuf_loader_get_format(loader); | |
74 if (!format) return; | |
75 | |
76 mime_types = gdk_pixbuf_format_get_mime_types(format); | |
77 n = 0; | |
78 while (mime_types[n]) | |
79 { | |
80 if (strstr(mime_types[n], "jpeg")) scale = TRUE; | |
81 n++; | |
82 } | |
83 g_strfreev(mime_types); | |
84 | |
85 if (!scale) return; | |
86 | |
87 if (width > il->requested_width || height > il->requested_height) | |
88 { | |
89 gint nw, nh; | |
90 | |
91 if (((gdouble)il->requested_width / width) < ((gdouble)il->requested_height / height)) | |
92 { | |
93 nw = il->requested_width; | |
94 nh = (gdouble)nw / width * height; | |
95 if (nh < 1) nh = 1; | |
96 } | |
97 else | |
98 { | |
99 nh = il->requested_height; | |
100 nw = (gdouble)nh / height * width; | |
101 if (nw < 1) nw = 1; | |
102 } | |
103 | |
104 gdk_pixbuf_loader_set_size(loader, nw, nh); | |
105 } | |
106 } | |
107 | |
108 static void image_loader_stop(ImageLoader *il) | |
109 { | |
110 if (!il) return; | |
111 | |
112 if (il->idle_id != -1) | |
113 { | |
114 g_source_remove(il->idle_id); | |
115 il->idle_id = -1; | |
116 } | |
117 | |
118 if (il->loader) | |
119 { | |
120 /* some loaders do not have a pixbuf till close, order is important here */ | |
121 gdk_pixbuf_loader_close(il->loader, NULL); | |
122 image_loader_sync_pixbuf(il); | |
123 g_object_unref(G_OBJECT(il->loader)); | |
124 il->loader = NULL; | |
125 } | |
126 | |
127 if (il->load_fd != -1) | |
128 { | |
129 close(il->load_fd); | |
130 il->load_fd = -1; | |
131 } | |
132 | |
133 il->done = TRUE; | |
134 } | |
135 | |
136 static void image_loader_done(ImageLoader *il) | |
137 { | |
138 image_loader_stop(il); | |
139 | |
140 if (il->func_done) il->func_done(il, il->data_done); | |
141 } | |
142 | |
143 static gint image_loader_done_delay_cb(gpointer data) | |
144 { | |
145 ImageLoader *il = data; | |
146 | |
147 il->idle_done_id = -1; | |
148 image_loader_done(il); | |
149 return FALSE; | |
150 } | |
151 | |
152 static void image_loader_done_delay(ImageLoader *il) | |
153 { | |
154 if (il->idle_done_id == -1) il->idle_done_id = g_idle_add_full(il->idle_priority, | |
155 image_loader_done_delay_cb, il, NULL); | |
156 } | |
157 | |
158 static void image_loader_error(ImageLoader *il) | |
159 { | |
160 image_loader_stop(il); | |
161 | |
162 if (debug) printf("pixbuf_loader reported load error for: %s\n", il->path); | |
163 | |
164 if (il->func_error) il->func_error(il, il->data_error); | |
165 } | |
166 | |
167 static gint image_loader_idle_cb(gpointer data) | |
168 { | |
169 ImageLoader *il = data; | |
170 guchar buf[IMAGE_LOADER_BUFFER_SIZE]; | |
171 gint b; | |
172 gint c; | |
173 | |
174 if (!il) return FALSE; | |
175 | |
176 if (il->idle_id == -1) return FALSE; | |
177 | |
178 c = il->buffer_size ? il->buffer_size : 1; | |
179 while (c > 0) | |
180 { | |
181 b = read(il->load_fd, &buf, sizeof(buf)); | |
182 | |
183 if (b == 0) | |
184 { | |
185 image_loader_done(il); | |
186 return FALSE; | |
187 } | |
188 | |
189 if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, buf, b, NULL))) | |
190 { | |
191 image_loader_error(il); | |
192 return FALSE; | |
193 } | |
194 | |
195 il->bytes_read += b; | |
196 | |
197 c--; | |
198 } | |
199 | |
200 if (il->func_percent && il->bytes_total > 0) | |
201 { | |
202 il->func_percent(il, (gdouble)il->bytes_read / il->bytes_total, il->data_percent); | |
203 } | |
204 | |
205 return TRUE; | |
206 } | |
207 | |
208 static gint image_loader_begin(ImageLoader *il) | |
209 { | |
210 guchar buf[IMAGE_LOADER_BUFFER_SIZE]; | |
211 int b; | |
212 | |
213 if (!il->loader || il->pixbuf) return FALSE; | |
214 | |
215 b = read(il->load_fd, &buf, sizeof(buf)); | |
216 | |
217 if (b < 1) | |
218 { | |
219 image_loader_stop(il); | |
220 return FALSE; | |
221 } | |
222 | |
223 if (gdk_pixbuf_loader_write(il->loader, buf, b, NULL)) | |
224 { | |
225 il->bytes_read += b; | |
226 | |
227 if (b < sizeof(buf)) | |
228 { | |
229 /* end of file already */ | |
230 | |
231 image_loader_stop(il); | |
232 | |
233 if (!il->pixbuf) return FALSE; | |
234 | |
235 image_loader_done_delay(il); | |
236 return TRUE; | |
237 } | |
238 else | |
239 { | |
240 /* larger file */ | |
241 | |
242 /* read until size is known */ | |
243 while(il->loader && !gdk_pixbuf_loader_get_pixbuf(il->loader) && b > 0) | |
244 { | |
245 b = read(il->load_fd, &buf, sizeof(buf)); | |
246 if (b < 0 || (b > 0 && !gdk_pixbuf_loader_write(il->loader, buf, b, NULL))) | |
247 { | |
248 image_loader_stop(il); | |
249 return FALSE; | |
250 } | |
251 il->bytes_read += b; | |
252 } | |
253 if (!il->pixbuf) image_loader_sync_pixbuf(il); | |
254 | |
255 if (il->bytes_read == il->bytes_total || b < sizeof(buf)) | |
256 { | |
257 /* done, handle (broken) loaders that do not have pixbuf till close */ | |
258 image_loader_stop(il); | |
259 | |
260 if (!il->pixbuf) return FALSE; | |
261 | |
262 image_loader_done_delay(il); | |
263 return TRUE; | |
264 } | |
265 | |
266 if (!il->pixbuf) | |
267 { | |
268 image_loader_stop(il); | |
269 return FALSE; | |
270 } | |
271 | |
272 /* finally, progressive loading :) */ | |
273 il->idle_id = g_idle_add_full(il->idle_priority, image_loader_idle_cb, il, NULL); | |
274 return TRUE; | |
275 } | |
276 } | |
277 else | |
278 { | |
279 image_loader_stop(il); | |
280 return FALSE; | |
281 } | |
282 | |
283 return TRUE; | |
284 } | |
285 | |
286 static gint image_loader_setup(ImageLoader *il) | |
287 { | |
288 struct stat st; | |
289 gchar *pathl; | |
290 | |
291 if (!il || il->load_fd != -1 || il->loader) return FALSE; | |
292 | |
293 pathl = path_from_utf8(il->path); | |
294 il->load_fd = open(pathl, O_RDONLY | O_NONBLOCK); | |
295 g_free(pathl); | |
296 if (il->load_fd == -1) return FALSE; | |
297 | |
298 if (fstat(il->load_fd, &st) == 0) | |
299 { | |
300 il->bytes_total = st.st_size; | |
301 } | |
302 | |
303 il->loader = gdk_pixbuf_loader_new(); | |
304 g_signal_connect(G_OBJECT(il->loader), "area_updated", | |
305 G_CALLBACK(image_loader_area_cb), il); | |
306 g_signal_connect(G_OBJECT(il->loader), "size_prepared", | |
307 G_CALLBACK(image_loader_size_cb), il); | |
308 | |
309 return image_loader_begin(il); | |
310 } | |
311 | |
312 ImageLoader *image_loader_new(const gchar *path) | |
313 { | |
314 ImageLoader *il; | |
315 | |
316 if (!path) return NULL; | |
317 | |
318 il = g_new0(ImageLoader, 1); | |
319 if (path) il->path = g_strdup(path); | |
320 il->pixbuf = NULL; | |
321 il->idle_id = -1; | |
322 il->idle_priority = G_PRIORITY_DEFAULT_IDLE; | |
323 il->done = FALSE; | |
324 il->loader = NULL; | |
325 il->load_fd = -1; | |
326 | |
327 il->bytes_read = 0; | |
328 il->bytes_total = 0; | |
329 | |
330 il->idle_done_id = -1; | |
331 | |
332 il->buffer_size = IMAGE_LOADER_BUFFER_DEFAULT_COUNT; | |
333 | |
334 il->requested_width = 0; | |
335 il->requested_height = 0; | |
336 | |
337 return il; | |
338 } | |
339 | |
340 void image_loader_free(ImageLoader *il) | |
341 { | |
342 if (!il) return; | |
343 | |
344 image_loader_stop(il); | |
345 if (il->idle_done_id != -1) g_source_remove(il->idle_done_id); | |
346 if (il->pixbuf) gdk_pixbuf_unref(il->pixbuf); | |
347 g_free(il->path); | |
348 g_free(il); | |
349 } | |
350 | |
351 /* don't forget to gdk_pixbuf_ref() it if you want to use it after image_loader_free() */ | |
352 GdkPixbuf *image_loader_get_pixbuf(ImageLoader *il) | |
353 { | |
354 if (!il) return NULL; | |
355 | |
356 return il->pixbuf; | |
357 } | |
358 | |
359 gchar *image_loader_get_format(ImageLoader *il) | |
360 { | |
361 GdkPixbufFormat *format; | |
362 gchar **mimev; | |
363 gchar *mime; | |
364 | |
365 if (!il || !il->loader) return NULL; | |
366 | |
367 format = gdk_pixbuf_loader_get_format(il->loader); | |
368 if (!format) return NULL; | |
369 | |
370 mimev = gdk_pixbuf_format_get_mime_types(format); | |
371 if (!mimev) return NULL; | |
372 | |
373 /* return first member of mimev, as GdkPixbufLoader has no way to tell us which exact one ? */ | |
374 mime = g_strdup(mimev[0]); | |
375 g_strfreev(mimev); | |
376 | |
377 return mime; | |
378 } | |
379 | |
380 void image_loader_set_area_ready_func(ImageLoader *il, | |
381 void (*func_area_ready)(ImageLoader *, guint, guint, guint, guint, gpointer), | |
382 gpointer data_area_ready) | |
383 { | |
384 if (!il) return; | |
385 | |
386 il->func_area_ready = func_area_ready; | |
387 il->data_area_ready = data_area_ready; | |
388 } | |
389 | |
390 void image_loader_set_error_func(ImageLoader *il, | |
391 void (*func_error)(ImageLoader *, gpointer), | |
392 gpointer data_error) | |
393 { | |
394 if (!il) return; | |
395 | |
396 il->func_error = func_error; | |
397 il->data_error = data_error; | |
398 } | |
399 | |
400 void image_loader_set_percent_func(ImageLoader *il, | |
401 void (*func_percent)(ImageLoader *, gdouble, gpointer), | |
402 gpointer data_percent) | |
403 { | |
404 if (!il) return; | |
405 | |
406 il->func_percent = func_percent; | |
407 il->data_percent = data_percent; | |
408 } | |
409 | |
410 void image_loader_set_requested_size(ImageLoader *il, gint width, gint height) | |
411 { | |
412 if (!il) return; | |
413 | |
414 il->requested_width = width; | |
415 il->requested_height = height; | |
416 } | |
417 | |
418 void image_loader_set_buffer_size(ImageLoader *il, guint size) | |
419 { | |
420 if (!il) return; | |
421 | |
422 il->buffer_size = size ? size : 1; | |
423 } | |
424 | |
425 void image_loader_set_priority(ImageLoader *il, gint priority) | |
426 { | |
427 if (!il) return; | |
428 | |
429 il->idle_priority = priority; | |
430 } | |
431 | |
432 gint image_loader_start(ImageLoader *il, void (*func_done)(ImageLoader *, gpointer), gpointer data_done) | |
433 { | |
434 if (!il) return FALSE; | |
435 | |
436 if (!il->path) return FALSE; | |
437 | |
438 il->func_done = func_done; | |
439 il->data_done = data_done; | |
440 | |
441 return image_loader_setup(il); | |
442 } | |
443 | |
444 gdouble image_loader_get_percent(ImageLoader *il) | |
445 { | |
446 if (!il || il->bytes_total == 0) return 0.0; | |
447 | |
448 return (gdouble)il->bytes_read / il->bytes_total; | |
449 } | |
450 | |
451 gint image_loader_get_is_done(ImageLoader *il) | |
452 { | |
453 if (!il) return FALSE; | |
454 | |
455 return il->done; | |
456 } | |
457 | |
458 gint image_load_dimensions(const gchar *path, gint *width, gint *height) | |
459 { | |
460 ImageLoader *il; | |
461 gint success; | |
462 | |
463 il = image_loader_new(path); | |
464 | |
465 success = image_loader_start(il, NULL, NULL); | |
466 | |
467 if (success && il->pixbuf) | |
468 { | |
469 if (width) *width = gdk_pixbuf_get_width(il->pixbuf); | |
470 if (height) *height = gdk_pixbuf_get_height(il->pixbuf);; | |
471 } | |
472 else | |
473 { | |
474 if (width) *width = -1; | |
475 if (height) *height = -1; | |
476 } | |
477 | |
478 image_loader_free(il); | |
479 | |
480 return success; | |
481 } | |
482 |