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