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