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