Mercurial > geeqie.yaz
comparison src/thumb.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 | c0e337a01cb7 |
children | 25335c62cd9b |
comparison
equal
deleted
inserted
replaced
8:e0d0593d519e | 9:d907d608745f |
---|---|
1 /* | 1 /* |
2 * GQview image viewer | 2 * GQview |
3 * (C)2000 John Ellis | 3 * (C) 2004 John Ellis |
4 * | 4 * |
5 * Author: John Ellis | 5 * Author: John Ellis |
6 * | 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! | |
7 */ | 10 */ |
8 | 11 |
12 | |
9 #include "gqview.h" | 13 #include "gqview.h" |
10 #include "icons/img_unknown.xpm" /* fixme! duplicate, included in image.c too */ | 14 #include "thumb.h" |
11 | 15 |
12 #define THUMBNAIL_CACHE_DIR "/.gqview_thmb" | 16 #include "cache.h" |
13 | 17 #include "image-load.h" |
14 static guchar *load_xv_thumbnail(gchar *filename, gint *widthp, gint *heightp); | 18 #include "pixbuf_util.h" |
15 static void normalize_thumb(gint *width, gint *height); | 19 #include "thumb_standard.h" |
16 static gint get_xv_thumbnail(gchar *thumb_filename, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask); | 20 #include "ui_fileops.h" |
21 | |
22 #include <utime.h> | |
23 | |
24 | |
25 static void thumb_loader_error_cb(ImageLoader *il, gpointer data); | |
26 static void thumb_loader_setup(ThumbLoader *tl, gchar *path); | |
27 | |
28 static gint normalize_thumb(gint *width, gint *height, gint max_w, gint max_h); | |
29 static GdkPixbuf *get_xv_thumbnail(gchar *thumb_filename, gint max_w, gint max_h); | |
30 | |
17 | 31 |
18 /* | 32 /* |
19 *----------------------------------------------------------------------------- | 33 *----------------------------------------------------------------------------- |
20 * thumbnail routines: creation, caching, and maintenance (public) | 34 * thumbnail routines: creation, caching, and maintenance (public) |
21 *----------------------------------------------------------------------------- | 35 *----------------------------------------------------------------------------- |
22 */ | 36 */ |
23 | 37 |
24 gint create_thumbnail(gchar *path, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask) | 38 static gint thumb_loader_save_to_cache(ThumbLoader *tl) |
25 { | 39 { |
26 gint width, height; | 40 gchar *cache_dir; |
27 gint space; | 41 gint success = FALSE; |
28 GdkImlibImage *thumb = NULL; | 42 mode_t mode = 0755; |
29 GdkImlibImage *image = NULL; | 43 |
30 gint cached = FALSE; | 44 if (!tl || !tl->pixbuf) return FALSE; |
31 | 45 |
32 if (debug) printf("Gen thumbnail:%s\n",path); | 46 cache_dir = cache_get_location(CACHE_TYPE_THUMB, tl->path, FALSE, &mode); |
33 | 47 |
34 /* if xvpics enabled, check for that first */ | 48 if (cache_ensure_dir_exists(cache_dir, mode)) |
35 if (use_xvpics_thumbnails) | |
36 { | |
37 space = get_xv_thumbnail(path, thumb_pixmap, thumb_mask); | |
38 if (space != -1) | |
39 { | |
40 if (debug) printf("XV thumbnail found, loaded\n"); | |
41 return space; | |
42 } | |
43 } | |
44 | |
45 /* start load from cache */ | |
46 | |
47 if (enable_thumb_caching) | |
48 { | 49 { |
49 gchar *cache_path; | 50 gchar *cache_path; |
50 cache_path = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, path, ".png", NULL); | 51 gchar *pathl; |
51 | 52 |
52 if (isfile(cache_path) && filetime(cache_path) >= filetime(path)) | 53 cache_path = g_strconcat(cache_dir, "/", filename_from_path(tl->path), |
53 { | 54 GQVIEW_CACHE_EXT_THUMB, NULL); |
54 if (debug) printf("Found in cache:%s\n", path); | 55 |
55 image = gdk_imlib_load_image(cache_path); | 56 if (debug) printf("Saving thumb: %s\n", cache_path); |
56 if (image && image->rgb_width != thumb_max_width && image->rgb_height != thumb_max_height) | 57 |
58 pathl = path_from_utf8(cache_path); | |
59 success = pixbuf_to_file_as_png(tl->pixbuf, pathl); | |
60 if (success) | |
61 { | |
62 struct utimbuf ut; | |
63 /* set thumb time to that of source file */ | |
64 | |
65 ut.actime = ut.modtime = filetime(tl->path); | |
66 if (ut.modtime > 0) | |
57 { | 67 { |
58 if (debug) printf("Thumbnail size may have changed, reloading:%s\n", path); | 68 utime(pathl, &ut); |
59 unlink(cache_path); | 69 } |
60 gdk_imlib_destroy_image(image); | 70 } |
61 image = gdk_imlib_load_image(path); | 71 else |
72 { | |
73 if (debug) printf("Saving failed: %s\n", pathl); | |
74 } | |
75 | |
76 g_free(pathl); | |
77 g_free(cache_path); | |
78 } | |
79 | |
80 g_free(cache_dir); | |
81 | |
82 return success; | |
83 } | |
84 | |
85 static gint thumb_loader_mark_failure(ThumbLoader *tl) | |
86 { | |
87 gchar *cache_dir; | |
88 gint success = FALSE; | |
89 mode_t mode = 0755; | |
90 | |
91 if (!tl) return FALSE; | |
92 | |
93 cache_dir = cache_get_location(CACHE_TYPE_THUMB, tl->path, FALSE, &mode); | |
94 | |
95 if (cache_ensure_dir_exists(cache_dir, mode)) | |
96 { | |
97 gchar *cache_path; | |
98 gchar *pathl; | |
99 FILE *f; | |
100 | |
101 cache_path = g_strconcat(cache_dir, "/", filename_from_path(tl->path), | |
102 GQVIEW_CACHE_EXT_THUMB, NULL); | |
103 | |
104 if (debug) printf("marking thumb failure: %s\n", cache_path); | |
105 | |
106 pathl = path_from_utf8(cache_path); | |
107 f = fopen(pathl, "w"); | |
108 if (f) | |
109 { | |
110 struct utimbuf ut; | |
111 | |
112 fclose (f); | |
113 | |
114 ut.actime = ut.modtime = filetime(tl->path); | |
115 if (ut.modtime > 0) | |
116 { | |
117 utime(pathl, &ut); | |
118 } | |
119 | |
120 success = TRUE; | |
121 } | |
122 | |
123 g_free(pathl); | |
124 g_free(cache_path); | |
125 } | |
126 | |
127 g_free(cache_dir); | |
128 return success; | |
129 } | |
130 | |
131 static void thumb_loader_percent_cb(ImageLoader *il, gdouble percent, gpointer data) | |
132 { | |
133 ThumbLoader *tl = data; | |
134 | |
135 tl->percent_done = percent; | |
136 | |
137 if (tl->func_progress) tl->func_progress(tl, tl->data); | |
138 } | |
139 | |
140 static void thumb_loader_done_cb(ImageLoader *il, gpointer data) | |
141 { | |
142 ThumbLoader *tl = data; | |
143 GdkPixbuf *pixbuf; | |
144 gint pw, ph; | |
145 gint save; | |
146 | |
147 if (debug) printf("thumb done: %s\n", tl->path); | |
148 | |
149 pixbuf = image_loader_get_pixbuf(tl->il); | |
150 if (!pixbuf) | |
151 { | |
152 if (debug) printf("...but no pixbuf: %s\n", tl->path); | |
153 thumb_loader_error_cb(tl->il, tl); | |
154 return; | |
155 } | |
156 | |
157 pw = gdk_pixbuf_get_width(pixbuf); | |
158 ph = gdk_pixbuf_get_height(pixbuf); | |
159 | |
160 if (tl->cache_hit && pw != tl->max_w && ph != tl->max_h) | |
161 { | |
162 /* requested thumbnail size may have changed, load original */ | |
163 if (debug) printf("thumbnail size mismatch, regenerating: %s\n", tl->path); | |
164 tl->cache_hit = FALSE; | |
165 | |
166 thumb_loader_setup(tl, tl->path); | |
167 | |
168 if (!image_loader_start(tl->il, thumb_loader_done_cb, tl)) | |
169 { | |
170 image_loader_free(tl->il); | |
171 tl->il = NULL; | |
172 | |
173 if (debug) printf("regeneration failure: %s\n", tl->path); | |
174 thumb_loader_error_cb(tl->il, tl); | |
175 } | |
176 return; | |
177 } | |
178 | |
179 /* scale ?? */ | |
180 | |
181 if (pw > tl->max_w || ph > tl->max_h) | |
182 { | |
183 gint w, h; | |
184 | |
185 if (((float)tl->max_w / pw) < ((float)tl->max_h / ph)) | |
186 { | |
187 w = tl->max_w; | |
188 h = (float)w / pw * ph; | |
189 if (h < 1) h = 1; | |
190 } | |
191 else | |
192 { | |
193 h = tl->max_h; | |
194 w = (float)h / ph * pw; | |
195 if (w < 1) w = 1; | |
196 } | |
197 | |
198 tl->pixbuf = gdk_pixbuf_scale_simple(pixbuf, w, h, (GdkInterpType)thumbnail_quality); | |
199 save = TRUE; | |
200 } | |
201 else | |
202 { | |
203 tl->pixbuf = pixbuf; | |
204 gdk_pixbuf_ref(tl->pixbuf); | |
205 save = FALSE; | |
206 } | |
207 | |
208 /* save it ? */ | |
209 if (tl->cache_enable && save) | |
210 { | |
211 thumb_loader_save_to_cache(tl); | |
212 } | |
213 | |
214 if (tl->func_done) tl->func_done(tl, tl->data); | |
215 } | |
216 | |
217 static void thumb_loader_error_cb(ImageLoader *il, gpointer data) | |
218 { | |
219 ThumbLoader *tl = data; | |
220 | |
221 /* if at least some of the image is available, go to done_cb */ | |
222 if (image_loader_get_pixbuf(tl->il) != NULL) | |
223 { | |
224 thumb_loader_done_cb(il, data); | |
225 return; | |
226 } | |
227 | |
228 if (debug) printf("thumb error: %s\n", tl->path); | |
229 | |
230 image_loader_free(tl->il); | |
231 tl->il = NULL; | |
232 | |
233 if (tl->func_error) tl->func_error(tl, tl->data); | |
234 } | |
235 | |
236 static gint thumb_loader_done_delay_cb(gpointer data) | |
237 { | |
238 ThumbLoader *tl = data; | |
239 | |
240 tl->idle_done_id = -1; | |
241 | |
242 if (tl->func_done) tl->func_done(tl, tl->data); | |
243 | |
244 return FALSE; | |
245 } | |
246 | |
247 static void thumb_loader_delay_done(ThumbLoader *tl) | |
248 { | |
249 if (tl->idle_done_id == -1) tl->idle_done_id = g_idle_add(thumb_loader_done_delay_cb, tl); | |
250 } | |
251 | |
252 static void thumb_loader_setup(ThumbLoader *tl, gchar *path) | |
253 { | |
254 image_loader_free(tl->il); | |
255 tl->il = image_loader_new(path); | |
256 | |
257 #if 0 | |
258 /* this will speed up jpegs by up to 3x in some cases */ | |
259 image_loader_set_requested_size(tl->max_w, tl->max_h); | |
260 #endif | |
261 | |
262 image_loader_set_error_func(tl->il, thumb_loader_error_cb, tl); | |
263 if (tl->func_progress) image_loader_set_percent_func(tl->il, thumb_loader_percent_cb, tl); | |
264 } | |
265 | |
266 void thumb_loader_set_callbacks(ThumbLoader *tl, | |
267 ThumbLoaderFunc func_done, | |
268 ThumbLoaderFunc func_error, | |
269 ThumbLoaderFunc func_progress, | |
270 gpointer data) | |
271 { | |
272 if (!tl) return; | |
273 | |
274 if (tl->standard_loader) | |
275 { | |
276 thumb_loader_std_set_callbacks((ThumbLoaderStd *)tl, | |
277 (ThumbLoaderStdFunc) func_done, | |
278 (ThumbLoaderStdFunc) func_error, | |
279 (ThumbLoaderStdFunc) func_progress, | |
280 data); | |
281 return; | |
282 } | |
283 | |
284 tl->func_done = func_done; | |
285 tl->func_error = func_error; | |
286 tl->func_progress = func_progress; | |
287 | |
288 tl->data = data; | |
289 } | |
290 | |
291 void thumb_loader_set_cache(ThumbLoader *tl, gint enable_cache, gint local, gint retry_failed) | |
292 { | |
293 if (!tl) return; | |
294 | |
295 if (tl->standard_loader) | |
296 { | |
297 thumb_loader_std_set_cache((ThumbLoaderStd *)tl, enable_cache, local, retry_failed); | |
298 return; | |
299 } | |
300 | |
301 tl->cache_enable = enable_cache; | |
302 #if 0 | |
303 tl->cache_local = local; | |
304 tl->cache_retry = retry_failed; | |
305 #endif | |
306 } | |
307 | |
308 | |
309 gint thumb_loader_start(ThumbLoader *tl, const gchar *path) | |
310 { | |
311 gchar *cache_path = NULL; | |
312 | |
313 if (!tl) return FALSE; | |
314 | |
315 if (tl->standard_loader) | |
316 { | |
317 return thumb_loader_std_start((ThumbLoaderStd *)tl, path); | |
318 } | |
319 | |
320 if (!tl->path && !path) return FALSE; | |
321 | |
322 if (!tl->path) tl->path = g_strdup(path); | |
323 | |
324 if (tl->cache_enable) | |
325 { | |
326 cache_path = cache_find_location(CACHE_TYPE_THUMB, tl->path); | |
327 | |
328 if (cache_path) | |
329 { | |
330 if (cache_time_valid(cache_path, tl->path)) | |
331 { | |
332 if (debug) printf("Found in cache:%s\n", tl->path); | |
333 | |
334 if (filesize(cache_path) == 0) | |
335 { | |
336 if (debug) printf("Broken image mark found:%s\n", cache_path); | |
337 g_free(cache_path); | |
338 return FALSE; | |
339 } | |
340 | |
341 if (debug) printf("Cache location:%s\n", cache_path); | |
62 } | 342 } |
63 else | 343 else |
64 { | 344 { |
65 cached = TRUE; | 345 g_free(cache_path); |
346 cache_path = NULL; | |
66 } | 347 } |
67 } | 348 } |
68 else | 349 } |
69 image = gdk_imlib_load_image(path); | 350 |
351 if (!cache_path && use_xvpics_thumbnails) | |
352 { | |
353 tl->pixbuf = get_xv_thumbnail(tl->path, tl->max_w, tl->max_h); | |
354 if (tl->pixbuf) | |
355 { | |
356 thumb_loader_delay_done(tl); | |
357 return TRUE; | |
358 } | |
359 } | |
360 | |
361 if (cache_path) | |
362 { | |
363 thumb_loader_setup(tl, cache_path); | |
364 g_free(cache_path); | |
365 tl->cache_hit = TRUE; | |
366 } | |
367 else | |
368 { | |
369 thumb_loader_setup(tl, tl->path); | |
370 } | |
371 | |
372 if (!image_loader_start(tl->il, thumb_loader_done_cb, tl)) | |
373 { | |
374 /* try from original if cache attempt */ | |
375 if (tl->cache_hit) | |
376 { | |
377 tl->cache_hit = FALSE; | |
378 print_term(_("Thumbnail image in cache failed to load, trying to recreate.\n")); | |
379 | |
380 thumb_loader_setup(tl, tl->path); | |
381 if (image_loader_start(tl->il, thumb_loader_done_cb, tl)) return TRUE; | |
382 } | |
383 /* mark failed thumbnail in cache with 0 byte file */ | |
384 if (tl->cache_enable) | |
385 { | |
386 thumb_loader_mark_failure(tl); | |
387 } | |
70 | 388 |
389 image_loader_free(tl->il); | |
390 tl->il = NULL; | |
391 return FALSE; | |
392 } | |
393 | |
394 return TRUE; | |
395 } | |
396 | |
397 #if 0 | |
398 gint thumb_loader_to_pixmap(ThumbLoader *tl, GdkPixmap **pixmap, GdkBitmap **mask) | |
399 { | |
400 if (!tl || !tl->pixbuf) return -1; | |
401 | |
402 gdk_pixbuf_render_pixmap_and_mask(tl->pixbuf, pixmap, mask, 128); | |
403 | |
404 return thumb_loader_get_space(tl); | |
405 } | |
406 #endif | |
407 | |
408 GdkPixbuf *thumb_loader_get_pixbuf(ThumbLoader *tl, gint with_fallback) | |
409 { | |
410 GdkPixbuf *pixbuf; | |
411 | |
412 if (tl && tl->standard_loader) | |
413 { | |
414 return thumb_loader_std_get_pixbuf((ThumbLoaderStd *)tl, with_fallback); | |
415 } | |
416 | |
417 if (tl && tl->pixbuf) | |
418 { | |
419 pixbuf = tl->pixbuf; | |
420 g_object_ref(pixbuf); | |
421 } | |
422 else if (with_fallback) | |
423 { | |
424 gint w, h; | |
425 | |
426 pixbuf = pixbuf_inline(PIXBUF_INLINE_BROKEN); | |
427 w = gdk_pixbuf_get_width(pixbuf); | |
428 h = gdk_pixbuf_get_height(pixbuf); | |
429 if ((w > tl->max_w || h > tl->max_h) && | |
430 normalize_thumb(&w, &h, tl->max_w, tl->max_h)) | |
431 { | |
432 GdkPixbuf *tmp; | |
433 | |
434 tmp = pixbuf; | |
435 pixbuf = gdk_pixbuf_scale_simple(tmp, w, h, GDK_INTERP_NEAREST); | |
436 gdk_pixbuf_unref(tmp); | |
437 } | |
71 } | 438 } |
72 else | 439 else |
73 image = gdk_imlib_load_image(path); | 440 { |
74 | 441 pixbuf = NULL; |
75 if (!image) | 442 } |
76 { | 443 |
77 image = gdk_imlib_create_image_from_xpm_data((gchar **)img_unknown_xpm); | 444 return pixbuf; |
78 cached = TRUE; /* no need to save a thumbnail of the unknown pixmap */ | 445 } |
79 } | 446 |
80 | 447 #if 0 |
81 if (image) | 448 gint thumb_loader_get_space(ThumbLoader *tl) |
82 { | 449 { |
83 if (image->rgb_width > thumb_max_width || image->rgb_height > thumb_max_height) | 450 if (!tl) return 0; |
84 { | 451 |
85 if (((float)thumb_max_width / image->rgb_width) < ((float)thumb_max_height / image->rgb_height)) | 452 if (tl->pixbuf) return (tl->max_w - gdk_pixbuf_get_width(tl->pixbuf)); |
86 { | 453 |
87 width = thumb_max_width; | 454 return tl->max_w; |
88 height = (float)width / image->rgb_width * image->rgb_height; | 455 } |
89 if (height < 1) height = 1; | 456 #endif |
90 } | 457 |
91 else | 458 ThumbLoader *thumb_loader_new(gint width, gint height) |
92 { | 459 { |
93 height = thumb_max_height; | 460 ThumbLoader *tl; |
94 width = (float)height / image->rgb_height * image->rgb_width; | 461 |
95 if (width < 1) width = 1; | 462 if (thumbnail_spec_standard) |
96 } | 463 { |
97 } | 464 return (ThumbLoader *)thumb_loader_std_new(width, height); |
98 else | 465 } |
99 { | 466 |
100 width = image->rgb_width; | 467 tl = g_new0(ThumbLoader, 1); |
101 height = image->rgb_height; | 468 tl->standard_loader = FALSE; |
102 cached = TRUE; /* don't cache images smaller than thumbnail size */ | 469 tl->path = NULL; |
103 } | 470 tl->cache_enable = enable_thumb_caching; |
104 if (*thumb_pixmap) gdk_imlib_free_pixmap(*thumb_pixmap); | 471 tl->cache_hit = FALSE; |
105 *thumb_pixmap = NULL; | 472 tl->percent_done = 0.0; |
106 *thumb_mask = NULL; | 473 tl->max_w = width; |
107 | 474 tl->max_h = height; |
108 /* start save cache */ | 475 |
109 | 476 tl->il = NULL; |
110 if (enable_thumb_caching && !cached) | 477 |
111 { | 478 tl->idle_done_id = -1; |
112 gchar *thumb_path; | 479 |
113 gchar *base_dir; | 480 return tl; |
114 gchar *thumb_dir; | 481 } |
115 gchar *image_dir; | 482 |
116 | 483 void thumb_loader_free(ThumbLoader *tl) |
117 /* attempt at speed-up? move this here */ | 484 { |
118 thumb = gdk_imlib_clone_scaled_image(image, width, height); | 485 if (!tl) return; |
119 gdk_imlib_destroy_image(image); | 486 |
120 image = NULL; | 487 if (tl->standard_loader) |
121 | 488 { |
122 base_dir = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, NULL); | 489 thumb_loader_std_free((ThumbLoaderStd *)tl); |
123 if (!isdir(base_dir)) | 490 return; |
124 { | 491 } |
125 if (debug) printf("creating thumbnail dir:%s\n", base_dir); | 492 |
126 if (mkdir(base_dir, 0755) < 0) | 493 if (tl->pixbuf) gdk_pixbuf_unref(tl->pixbuf); |
127 printf(_("create dir failed: %s\n"), base_dir); | 494 image_loader_free(tl->il); |
128 } | 495 g_free(tl->path); |
129 | 496 |
130 image_dir = remove_level_from_path(path); | 497 if (tl->idle_done_id != -1) g_source_remove(tl->idle_done_id); |
131 thumb_dir = g_strconcat(base_dir, image_dir, NULL); | 498 |
132 g_free(image_dir); | 499 g_free(tl); |
133 if (!isdir(thumb_dir)) | 500 } |
134 { | 501 |
135 gchar *p = thumb_dir; | 502 #if 0 |
136 while (p[0] != '\0') | 503 gint thumb_from_xpm_d(const char **data, gint max_w, gint max_h, GdkPixmap **pixmap, GdkBitmap **mask) |
137 { | 504 { |
138 p++; | 505 GdkPixbuf *pixbuf; |
139 if (p[0] == '/' || p[0] == '\0') | 506 gint w, h; |
140 { | 507 |
141 gint end = TRUE; | 508 pixbuf = gdk_pixbuf_new_from_xpm_data(data); |
142 if (p[0] != '\0') | 509 w = gdk_pixbuf_get_width(pixbuf); |
143 { | 510 h = gdk_pixbuf_get_height(pixbuf); |
144 p[0] = '\0'; | 511 |
145 end = FALSE; | 512 if ((w > max_w || h > max_h) && |
146 } | 513 normalize_thumb(&w, &h, max_w, max_h)) |
147 if (!isdir(thumb_dir)) | 514 { |
148 { | 515 /* scale */ |
149 if (debug) printf("creating sub dir:%s\n",thumb_dir); | 516 GdkPixbuf *tmp; |
150 if (mkdir(thumb_dir, 0755) < 0) | 517 |
151 printf(_("create dir failed: %s\n"), thumb_dir); | 518 tmp = pixbuf; |
152 } | 519 pixbuf = gdk_pixbuf_scale_simple(tmp, w, h, GDK_INTERP_NEAREST); |
153 if (!end) p[0] = '/'; | 520 gdk_pixbuf_unref(tmp); |
154 } | 521 } |
155 } | 522 |
156 } | 523 gdk_pixbuf_render_pixmap_and_mask(pixbuf, pixmap, mask, 128); |
157 g_free(thumb_dir); | 524 gdk_pixbuf_unref(pixbuf); |
158 | 525 |
159 thumb_path = g_strconcat(base_dir, path, ".png", NULL); | 526 return w; |
160 if (debug) printf("Saving thumb: %s\n",thumb_path); | 527 } |
161 | 528 #endif |
162 gdk_imlib_save_image(thumb, thumb_path, NULL); | |
163 | |
164 g_free(base_dir); | |
165 g_free(thumb_path); | |
166 } | |
167 else | |
168 { | |
169 thumb = image; | |
170 } | |
171 | |
172 /* end save cache */ | |
173 | |
174 gdk_imlib_render(thumb, width, height); | |
175 *thumb_pixmap = gdk_imlib_move_image(thumb); | |
176 *thumb_mask = gdk_imlib_move_mask(thumb); | |
177 if (*thumb_pixmap) | |
178 space = thumb_max_width - width; | |
179 gdk_imlib_destroy_image(thumb); | |
180 thumb = NULL; | |
181 } | |
182 else | |
183 { | |
184 space = -1; | |
185 } | |
186 return space; | |
187 } | |
188 | |
189 gint maintain_thumbnail_dir(gchar *dir, gint recursive) | |
190 { | |
191 gchar *thumb_dir; | |
192 gint base_length; | |
193 gint still_have_a_file = FALSE; | |
194 | |
195 if (debug) printf("maintainance check: %s\n", dir); | |
196 | |
197 base_length = strlen(homedir()) + strlen(THUMBNAIL_CACHE_DIR); | |
198 thumb_dir = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, dir, NULL); | |
199 | |
200 if (isdir(thumb_dir)) | |
201 { | |
202 DIR *dp; | |
203 struct dirent *dirent; | |
204 struct stat ent_sbuf; | |
205 | |
206 if((dp = opendir(thumb_dir))==NULL) | |
207 { | |
208 /* dir not found */ | |
209 g_free(thumb_dir); | |
210 return FALSE; | |
211 } | |
212 | |
213 while ((dirent = readdir(dp)) != NULL) | |
214 { | |
215 /* skips removed files */ | |
216 if (dirent->d_ino > 0) | |
217 { | |
218 int l = 0; | |
219 gchar *path_buf; | |
220 if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0) | |
221 continue; | |
222 path_buf = g_strconcat(thumb_dir, "/", dirent->d_name, NULL); | |
223 if (strlen(path_buf) > 4) l = strlen(path_buf) - 4; | |
224 | |
225 if (stat(path_buf,&ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode)) | |
226 { | |
227 /* recurse dir then delete it */ | |
228 gchar *rdir = g_strconcat(dir, "/", dirent->d_name, NULL); | |
229 if (recursive && !maintain_thumbnail_dir(rdir, TRUE)) | |
230 { | |
231 if (debug) printf("Deleting thumb dir: %s\n",path_buf); | |
232 if ( (rmdir (path_buf) < 0) ) | |
233 printf(_("Unable to delete dir: %s\n"), path_buf); | |
234 } | |
235 else | |
236 still_have_a_file = TRUE; | |
237 g_free(rdir); | |
238 } | |
239 else | |
240 { | |
241 gchar *fp = path_buf + l; | |
242 fp[0] = '\0'; | |
243 if (strlen(path_buf) > base_length && | |
244 !isfile(path_buf + base_length)) | |
245 { | |
246 fp[0] = '.'; | |
247 if (debug) printf("Deleting thumb: %s\n",path_buf); | |
248 if ( (unlink (path_buf) < 0) ) | |
249 printf(_("failed to delete:%s\n"),path_buf); | |
250 } | |
251 else | |
252 still_have_a_file = TRUE; | |
253 } | |
254 g_free(path_buf); | |
255 } | |
256 } | |
257 closedir(dp); | |
258 } | |
259 g_free(thumb_dir); | |
260 return still_have_a_file; | |
261 } | |
262 | 529 |
263 /* | 530 /* |
264 *----------------------------------------------------------------------------- | 531 *----------------------------------------------------------------------------- |
265 * xvpics thumbnail support, read-only (private) | 532 * xvpics thumbnail support, read-only (private) |
266 *----------------------------------------------------------------------------- | 533 *----------------------------------------------------------------------------- |
270 * xvpics code originally supplied by: | 537 * xvpics code originally supplied by: |
271 * "Diederen Damien" <D.Diederen@student.ulg.ac.be> | 538 * "Diederen Damien" <D.Diederen@student.ulg.ac.be> |
272 * | 539 * |
273 * Note: Code has been modified to fit the style of the other code, and to use | 540 * Note: Code has been modified to fit the style of the other code, and to use |
274 * a few more glib-isms. | 541 * a few more glib-isms. |
542 * 08-28-2000: Updated to return a gdk_pixbuf, Imlib is dieing a death here. | |
275 */ | 543 */ |
276 | 544 |
277 #define XV_BUFFER 2048 | 545 #define XV_BUFFER 2048 |
278 static guchar *load_xv_thumbnail(gchar *filename, gint *widthp, gint *heightp) | 546 static guchar *load_xv_thumbnail(gchar *filename, gint *widthp, gint *heightp) |
279 { | 547 { |
308 *heightp = height; | 576 *heightp = height; |
309 return data; | 577 return data; |
310 } | 578 } |
311 #undef XV_BUFFER | 579 #undef XV_BUFFER |
312 | 580 |
313 static void normalize_thumb(gint *width, gint *height) | 581 static gint normalize_thumb(gint *width, gint *height, gint max_w, gint max_h) |
314 { | 582 { |
315 if(*width > thumb_max_width || *height > thumb_max_height) | 583 gdouble scale; |
316 { | 584 gint new_w, new_h; |
317 gfloat factor = MAX((gfloat) *width / thumb_max_width, (gfloat) *height / thumb_max_height); | 585 |
318 *width = (gfloat) *width / factor; | 586 scale = MIN((gdouble) max_w / *width, (gdouble) max_h / *height); |
319 *height = (gfloat) *height / factor; | 587 new_w = *width * scale; |
320 } | 588 new_h = *height * scale; |
321 } | 589 |
322 | 590 if (new_w != *width || new_h != *height) |
323 static gint get_xv_thumbnail(gchar *thumb_filename, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask) | 591 { |
592 *width = new_w; | |
593 *height = new_h; | |
594 return TRUE; | |
595 } | |
596 | |
597 return FALSE; | |
598 } | |
599 | |
600 static void free_rgb_buffer(guchar *pixels, gpointer data) | |
601 { | |
602 g_free(pixels); | |
603 } | |
604 | |
605 static GdkPixbuf *get_xv_thumbnail(gchar *thumb_filename, gint max_w, gint max_h) | |
324 { | 606 { |
325 gint width, height; | 607 gint width, height; |
326 gchar *thumb_name; | 608 gchar *thumb_name; |
327 gchar *tmp_string; | 609 gchar *tmp_string; |
328 gchar *last_slash; | 610 gchar *last_slash; |
329 guchar *packed_data; | 611 guchar *packed_data; |
330 | 612 |
331 tmp_string = g_strdup(thumb_filename); | 613 tmp_string = path_from_utf8(thumb_filename); |
332 last_slash = strrchr(tmp_string, '/'); | 614 last_slash = strrchr(tmp_string, '/'); |
333 if(!last_slash) return -1; | 615 if(!last_slash) return NULL; |
334 *last_slash++ = '\0'; | 616 *last_slash++ = '\0'; |
335 | 617 |
336 thumb_name = g_strconcat(tmp_string, "/.xvpics/", last_slash, NULL); | 618 thumb_name = g_strconcat(tmp_string, "/.xvpics/", last_slash, NULL); |
337 packed_data = load_xv_thumbnail(thumb_name, &width, &height); | 619 packed_data = load_xv_thumbnail(thumb_name, &width, &height); |
338 g_free(tmp_string); | 620 g_free(tmp_string); |
339 g_free(thumb_name); | 621 g_free(thumb_name); |
340 | 622 |
341 if(packed_data) | 623 if(packed_data) |
342 { | 624 { |
343 guchar *rgb_data; | 625 guchar *rgb_data; |
344 GdkImlibImage *image; | 626 GdkPixbuf *pixbuf; |
345 gint i; | 627 gint i; |
346 | 628 |
347 rgb_data = g_new(guchar, width * height * 3); | 629 rgb_data = g_new(guchar, width * height * 3); |
348 for(i = 0; i < width * height; i++) | 630 for(i = 0; i < width * height; i++) |
349 { | 631 { |
350 rgb_data[i * 3 + 0] = (packed_data[i] >> 5) * 36; | 632 rgb_data[i * 3 + 0] = (packed_data[i] >> 5) * 36; |
351 rgb_data[i * 3 + 1] = ((packed_data[i] & 28) >> 2) * 36; | 633 rgb_data[i * 3 + 1] = ((packed_data[i] & 28) >> 2) * 36; |
352 rgb_data[i * 3 + 2] = (packed_data[i] & 3) * 85; | 634 rgb_data[i * 3 + 2] = (packed_data[i] & 3) * 85; |
353 } | 635 } |
354 | |
355 g_free(packed_data); | 636 g_free(packed_data); |
356 image = gdk_imlib_create_image_from_data(rgb_data, NULL, width, height); | 637 |
357 g_free(rgb_data); | 638 pixbuf = gdk_pixbuf_new_from_data(rgb_data, GDK_COLORSPACE_RGB, FALSE, 8, |
358 normalize_thumb(&width, &height); | 639 width, height, 3 * width, free_rgb_buffer, NULL); |
359 gdk_imlib_render(image, width, height); | 640 |
641 if (normalize_thumb(&width, &height, max_w, max_h)) | |
642 { | |
643 /* scale */ | |
644 GdkPixbuf *tmp; | |
645 | |
646 tmp = pixbuf; | |
647 pixbuf = gdk_pixbuf_scale_simple(tmp, width, height, GDK_INTERP_NEAREST); | |
648 gdk_pixbuf_unref(tmp); | |
649 } | |
360 | 650 |
361 if(*thumb_pixmap) gdk_imlib_free_pixmap(*thumb_pixmap); | 651 return pixbuf; |
362 | 652 } |
363 *thumb_pixmap = gdk_imlib_move_image(image); | 653 |
364 *thumb_mask = gdk_imlib_move_mask(image); | 654 return NULL; |
365 gdk_imlib_destroy_image(image); | 655 } |
366 return thumb_max_width - width; | 656 |
367 } | 657 |
368 | 658 |
369 return -1; | |
370 } | |
371 |