/*
- * GQview image viewer
- * (C)2000 John Ellis
+ * Geeqie
+ * (C) 2004 John Ellis
+ * Copyright (C) 2008 - 2012 The Geeqie Team
*
* Author: John Ellis
*
+ * This software is released under the GNU General Public License (GNU GPL).
+ * Please read the included file COPYING for more information.
+ * This software comes with no warranty of any kind, use at your own risk!
*/
-#include "gqview.h"
-#include "icons/img_unknown.xpm" /* fixme! duplicate, included in image.c too */
-#define THUMBNAIL_CACHE_DIR "/.gqview_thmb"
+#include "main.h"
+#include "thumb.h"
+
+#include "cache.h"
+#include "image-load.h"
+#include "filedata.h"
+#include "pixbuf_util.h"
+#include "thumb_standard.h"
+#include "ui_fileops.h"
+#include "exif.h"
+#include "metadata.h"
+
+#include <utime.h>
+
+
+static void thumb_loader_error_cb(ImageLoader *il, gpointer data);
+static void thumb_loader_setup(ThumbLoader *tl, FileData *fd);
+
+static GdkPixbuf *get_xv_thumbnail(gchar *thumb_filename, gint max_w, gint max_h);
-static guchar *load_xv_thumbnail(gchar *filename, gint *widthp, gint *heightp);
-static void normalize_thumb(gint *width, gint *height);
-static gint get_xv_thumbnail(gchar *thumb_filename, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask);
/*
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
*/
-gint create_thumbnail(gchar *path, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask)
+/* Save thumbnail to disk
+ * or just mark failed thumbnail with 0 byte file (mark_failure = TRUE) */
+static gboolean thumb_loader_save_thumbnail(ThumbLoader *tl, gboolean mark_failure)
{
- gint width, height;
- gint space;
- GdkImlibImage *thumb = NULL;
- GdkImlibImage *image = NULL;
- gint cached = FALSE;
+ gchar *cache_dir;
+ gboolean success = FALSE;
+ mode_t mode = 0755;
- if (debug) printf("Gen thumbnail:%s\n",path);
+ if (!tl || !tl->fd) return FALSE;
+ if (!mark_failure && !tl->fd->thumb_pixbuf) return FALSE;
- /* if xvpics enabled, check for that first */
- if (use_xvpics_thumbnails)
- {
- space = get_xv_thumbnail(path, thumb_pixmap, thumb_mask);
- if (space != -1)
- {
- if (debug) printf("XV thumbnail found, loaded\n");
- return space;
- }
- }
+ cache_dir = cache_get_location(CACHE_TYPE_THUMB, tl->fd->path, FALSE, &mode);
- /* start load from cache */
-
- if (enable_thumb_caching)
+ if (recursive_mkdir_if_not_exists(cache_dir, mode))
{
gchar *cache_path;
- cache_path = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, path, ".png", NULL);
+ gchar *pathl;
+ gchar *name = g_strconcat(filename_from_path(tl->fd->path), GQ_CACHE_EXT_THUMB, NULL);
+
+ cache_path = g_build_filename(cache_dir, name, NULL);
+ g_free(name);
+
+ pathl = path_from_utf8(cache_path);
- if (isfile(cache_path) && filetime(cache_path) >= filetime(path))
+ if (mark_failure)
{
- if (debug) printf("Found in cache:%s\n", path);
- image = gdk_imlib_load_image(cache_path);
- if (image && image->rgb_width != thumb_max_width && image->rgb_height != thumb_max_height)
+ FILE *f = fopen(pathl, "w"); ;
+
+ DEBUG_1("Marking thumb failure: %s", cache_path);
+ if (f)
{
- if (debug) printf("Thumbnail size may have changed, reloading:%s\n", path);
- unlink(cache_path);
- gdk_imlib_destroy_image(image);
- image = gdk_imlib_load_image(path);
+ fclose(f);
+ success = TRUE;
}
- else
+ }
+ else
+ {
+ DEBUG_1("Saving thumb: %s", cache_path);
+ success = pixbuf_to_file_as_png(tl->fd->thumb_pixbuf, pathl);
+ }
+
+ if (success)
+ {
+ struct utimbuf ut;
+ /* set thumb time to that of source file */
+
+ ut.actime = ut.modtime = filetime(tl->fd->path);
+ if (ut.modtime > 0)
{
- cached = TRUE;
+ utime(pathl, &ut);
}
}
else
- image = gdk_imlib_load_image(path);
-
+ {
+ DEBUG_1("Saving failed: %s", pathl);
+ }
+
+ g_free(pathl);
+ g_free(cache_path);
}
- else
- image = gdk_imlib_load_image(path);
- if (!image)
+ g_free(cache_dir);
+
+ return success;
+}
+
+static void thumb_loader_percent_cb(ImageLoader *il, gdouble percent, gpointer data)
+{
+ ThumbLoader *tl = data;
+
+ tl->percent_done = percent;
+
+ if (tl->func_progress) tl->func_progress(tl, tl->data);
+}
+
+static void thumb_loader_set_fallback(ThumbLoader *tl)
+{
+ if (tl->fd->thumb_pixbuf) g_object_unref(tl->fd->thumb_pixbuf);
+ tl->fd->thumb_pixbuf = pixbuf_fallback(tl->fd, tl->max_w, tl->max_h);
+}
+
+static void thumb_loader_done_cb(ImageLoader *il, gpointer data)
+{
+ ThumbLoader *tl = data;
+ GdkPixbuf *pixbuf;
+ gint pw, ph;
+ gint save;
+ GdkPixbuf *rotated = NULL;
+
+ DEBUG_1("thumb done: %s", tl->fd->path);
+
+ pixbuf = image_loader_get_pixbuf(tl->il);
+ if (!pixbuf)
{
- image = gdk_imlib_create_image_from_xpm_data((gchar **)img_unknown_xpm);
- cached = TRUE; /* no need to save a thumbnail of the unknown pixmap */
+ DEBUG_1("...but no pixbuf: %s", tl->fd->path);
+ thumb_loader_error_cb(tl->il, tl);
+ return;
}
- if (image)
+
+ if (!tl->cache_hit && options->image.exif_rotate_enable)
{
- if (image->rgb_width > thumb_max_width || image->rgb_height > thumb_max_height)
+ if (!tl->fd->exif_orientation)
{
- if (((float)thumb_max_width / image->rgb_width) < ((float)thumb_max_height / image->rgb_height))
- {
- width = thumb_max_width;
- height = (float)width / image->rgb_width * image->rgb_height;
- if (height < 1) height = 1;
- }
- else
- {
- height = thumb_max_height;
- width = (float)height / image->rgb_height * image->rgb_width;
- if (width < 1) width = 1;
- }
+ tl->fd->exif_orientation = metadata_read_int(tl->fd, ORIENTATION_KEY, EXIF_ORIENTATION_TOP_LEFT);
}
- else
+
+ if (tl->fd->exif_orientation != EXIF_ORIENTATION_TOP_LEFT)
{
- width = image->rgb_width;
- height = image->rgb_height;
- cached = TRUE; /* don't cache images smaller than thumbnail size */
+ rotated = pixbuf_apply_orientation(pixbuf, tl->fd->exif_orientation);
+ pixbuf = rotated;
}
- if (*thumb_pixmap) gdk_imlib_free_pixmap(*thumb_pixmap);
- *thumb_pixmap = NULL;
- *thumb_mask = NULL;
+ }
+
+ pw = gdk_pixbuf_get_width(pixbuf);
+ ph = gdk_pixbuf_get_height(pixbuf);
+
+ if (tl->cache_hit && pw != tl->max_w && ph != tl->max_h)
+ {
+ /* requested thumbnail size may have changed, load original */
+ DEBUG_1("thumbnail size mismatch, regenerating: %s", tl->fd->path);
+ tl->cache_hit = FALSE;
- /* start save cache */
+ thumb_loader_setup(tl, tl->fd);
- if (enable_thumb_caching && !cached)
+ g_signal_connect(G_OBJECT(tl->il), "done", (GCallback)thumb_loader_done_cb, tl);
+
+ if (!image_loader_start(tl->il))
{
- gchar *thumb_path;
- gchar *base_dir;
- gchar *thumb_dir;
- gchar *image_dir;
-
- /* attempt at speed-up? move this here */
- thumb = gdk_imlib_clone_scaled_image(image, width, height);
- gdk_imlib_destroy_image(image);
- image = NULL;
-
- base_dir = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, NULL);
- if (!isdir(base_dir))
- {
- if (debug) printf("creating thumbnail dir:%s\n", base_dir);
- if (mkdir(base_dir, 0755) < 0)
- printf(_("create dir failed: %s\n"), base_dir);
- }
+ image_loader_free(tl->il);
+ tl->il = NULL;
- image_dir = remove_level_from_path(path);
- thumb_dir = g_strconcat(base_dir, image_dir, NULL);
- g_free(image_dir);
- if (!isdir(thumb_dir))
- {
- gchar *p = thumb_dir;
- while (p[0] != '\0')
- {
- p++;
- if (p[0] == '/' || p[0] == '\0')
- {
- gint end = TRUE;
- if (p[0] != '\0')
- {
- p[0] = '\0';
- end = FALSE;
- }
- if (!isdir(thumb_dir))
- {
- if (debug) printf("creating sub dir:%s\n",thumb_dir);
- if (mkdir(thumb_dir, 0755) < 0)
- printf(_("create dir failed: %s\n"), thumb_dir);
- }
- if (!end) p[0] = '/';
- }
- }
- }
- g_free(thumb_dir);
+ DEBUG_1("regeneration failure: %s", tl->fd->path);
+ thumb_loader_error_cb(tl->il, tl);
+ }
+ return;
+ }
- thumb_path = g_strconcat(base_dir, path, ".png", NULL);
- if (debug) printf("Saving thumb: %s\n",thumb_path);
+ /* scale ?? */
- gdk_imlib_save_image(thumb, thumb_path, NULL);
+ if (pw > tl->max_w || ph > tl->max_h)
+ {
+ gint w, h;
- g_free(base_dir);
- g_free(thumb_path);
+ if (((gdouble)tl->max_w / pw) < ((gdouble)tl->max_h / ph))
+ {
+ w = tl->max_w;
+ h = (gdouble)w / pw * ph;
+ if (h < 1) h = 1;
}
else
{
- thumb = image;
+ h = tl->max_h;
+ w = (gdouble)h / ph * pw;
+ if (w < 1) w = 1;
}
- /* end save cache */
-
- gdk_imlib_render(thumb, width, height);
- *thumb_pixmap = gdk_imlib_move_image(thumb);
- *thumb_mask = gdk_imlib_move_mask(thumb);
- if (*thumb_pixmap)
- space = thumb_max_width - width;
- gdk_imlib_destroy_image(thumb);
- thumb = NULL;
+ if (tl->fd)
+ {
+ if (tl->fd->thumb_pixbuf) g_object_unref(tl->fd->thumb_pixbuf);
+ tl->fd->thumb_pixbuf = gdk_pixbuf_scale_simple(pixbuf, w, h, (GdkInterpType)options->thumbnails.quality);
+ }
+ save = TRUE;
}
else
{
- space = -1;
+ if (tl->fd)
+ {
+ if (tl->fd->thumb_pixbuf) g_object_unref(tl->fd->thumb_pixbuf);
+ tl->fd->thumb_pixbuf = pixbuf;
+
+ g_object_ref(tl->fd->thumb_pixbuf);
+ }
+ save = image_loader_get_shrunk(il);
}
- return space;
+
+ if (rotated) g_object_unref(rotated);
+
+ /* save it ? */
+ if (tl->cache_enable && save)
+ {
+ thumb_loader_save_thumbnail(tl, FALSE);
+ }
+
+ if (tl->func_done) tl->func_done(tl, tl->data);
}
-gint maintain_thumbnail_dir(gchar *dir, gint recursive)
+static void thumb_loader_error_cb(ImageLoader *il, gpointer data)
{
- gchar *thumb_dir;
- gint base_length;
- gint still_have_a_file = FALSE;
+ ThumbLoader *tl = data;
+
+ /* if at least some of the image is available, go to done_cb */
+ if (image_loader_get_pixbuf(tl->il) != NULL)
+ {
+ thumb_loader_done_cb(il, data);
+ return;
+ }
+
+ DEBUG_1("thumb error: %s", tl->fd->path);
- if (debug) printf("maintainance check: %s\n", dir);
+ image_loader_free(tl->il);
+ tl->il = NULL;
- base_length = strlen(homedir()) + strlen(THUMBNAIL_CACHE_DIR);
- thumb_dir = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, dir, NULL);
+ thumb_loader_set_fallback(tl);
- if (isdir(thumb_dir))
+ if (tl->func_error) tl->func_error(tl, tl->data);
+}
+
+static gboolean thumb_loader_done_delay_cb(gpointer data)
+{
+ ThumbLoader *tl = data;
+
+ tl->idle_done_id = 0;
+
+ if (tl->func_done) tl->func_done(tl, tl->data);
+
+ return FALSE;
+}
+
+static void thumb_loader_delay_done(ThumbLoader *tl)
+{
+ if (!tl->idle_done_id) tl->idle_done_id = g_idle_add(thumb_loader_done_delay_cb, tl);
+}
+
+static void thumb_loader_setup(ThumbLoader *tl, FileData *fd)
+{
+ image_loader_free(tl->il);
+ tl->il = image_loader_new(fd);
+ image_loader_set_priority(tl->il, G_PRIORITY_LOW);
+
+ /* this will speed up jpegs by up to 3x in some cases */
+ image_loader_set_requested_size(tl->il, tl->max_w, tl->max_h);
+
+ g_signal_connect(G_OBJECT(tl->il), "error", (GCallback)thumb_loader_error_cb, tl);
+ if (tl->func_progress) g_signal_connect(G_OBJECT(tl->il), "percent", (GCallback)thumb_loader_percent_cb, tl);
+}
+
+void thumb_loader_set_callbacks(ThumbLoader *tl,
+ ThumbLoaderFunc func_done,
+ ThumbLoaderFunc func_error,
+ ThumbLoaderFunc func_progress,
+ gpointer data)
+{
+ if (!tl) return;
+
+ if (tl->standard_loader)
{
- DIR *dp;
- struct dirent *dirent;
- struct stat ent_sbuf;
+ thumb_loader_std_set_callbacks((ThumbLoaderStd *)tl,
+ (ThumbLoaderStdFunc) func_done,
+ (ThumbLoaderStdFunc) func_error,
+ (ThumbLoaderStdFunc) func_progress,
+ data);
+ return;
+ }
- if((dp = opendir(thumb_dir))==NULL)
- {
- /* dir not found */
- g_free(thumb_dir);
- return FALSE;
- }
+ tl->func_done = func_done;
+ tl->func_error = func_error;
+ tl->func_progress = func_progress;
+
+ tl->data = data;
+}
+
+void thumb_loader_set_cache(ThumbLoader *tl, gboolean enable_cache, gboolean local, gboolean retry_failed)
+{
+ if (!tl) return;
- while ((dirent = readdir(dp)) != NULL)
+ if (tl->standard_loader)
+ {
+ thumb_loader_std_set_cache((ThumbLoaderStd *)tl, enable_cache, local, retry_failed);
+ return;
+ }
+
+ tl->cache_enable = enable_cache;
+}
+
+
+gboolean thumb_loader_start(ThumbLoader *tl, FileData *fd)
+{
+ gchar *cache_path = NULL;
+
+ if (!tl) return FALSE;
+
+ if (tl->standard_loader)
+ {
+ return thumb_loader_std_start((ThumbLoaderStd *)tl, fd);
+ }
+
+ if (!tl->fd && !fd) return FALSE;
+
+ if (!tl->fd) tl->fd = file_data_ref(fd);
+
+
+ if (tl->cache_enable)
+ {
+ cache_path = cache_find_location(CACHE_TYPE_THUMB, tl->fd->path);
+
+ if (cache_path)
{
- /* skips removed files */
- if (dirent->d_ino > 0)
- {
- int l = 0;
- gchar *path_buf;
- if (strcmp(dirent->d_name, ".") == 0 || strcmp(dirent->d_name, "..") == 0)
- continue;
- path_buf = g_strconcat(thumb_dir, "/", dirent->d_name, NULL);
- if (strlen(path_buf) > 4) l = strlen(path_buf) - 4;
-
- if (stat(path_buf,&ent_sbuf) >= 0 && S_ISDIR(ent_sbuf.st_mode))
- {
- /* recurse dir then delete it */
- gchar *rdir = g_strconcat(dir, "/", dirent->d_name, NULL);
- if (recursive && !maintain_thumbnail_dir(rdir, TRUE))
- {
- if (debug) printf("Deleting thumb dir: %s\n",path_buf);
- if ( (rmdir (path_buf) < 0) )
- printf(_("Unable to delete dir: %s\n"), path_buf);
- }
- else
- still_have_a_file = TRUE;
- g_free(rdir);
- }
- else
+ if (cache_time_valid(cache_path, tl->fd->path))
+ {
+ DEBUG_1("Found in cache:%s", tl->fd->path);
+
+ if (filesize(cache_path) == 0)
{
- gchar *fp = path_buf + l;
- fp[0] = '\0';
- if (strlen(path_buf) > base_length &&
- !isfile(path_buf + base_length))
- {
- fp[0] = '.';
- if (debug) printf("Deleting thumb: %s\n",path_buf);
- if ( (unlink (path_buf) < 0) )
- printf(_("failed to delete:%s\n"),path_buf);
- }
- else
- still_have_a_file = TRUE;
+ DEBUG_1("Broken image mark found:%s", cache_path);
+ g_free(cache_path);
+ thumb_loader_set_fallback(tl);
+ return FALSE;
}
- g_free(path_buf);
+
+ DEBUG_1("Cache location:%s", cache_path);
+ }
+ else
+ {
+ g_free(cache_path);
+ cache_path = NULL;
}
}
- closedir(dp);
}
- g_free(thumb_dir);
- return still_have_a_file;
+
+ if (!cache_path && options->thumbnails.use_xvpics)
+ {
+ if (tl->fd->thumb_pixbuf) g_object_unref(tl->fd->thumb_pixbuf);
+ tl->fd->thumb_pixbuf = get_xv_thumbnail(tl->fd->path, tl->max_w, tl->max_h);
+ if (tl->fd->thumb_pixbuf)
+ {
+ thumb_loader_delay_done(tl);
+ return TRUE;
+ }
+ }
+
+ if (cache_path)
+ {
+ FileData *fd = file_data_new_no_grouping(cache_path);
+ thumb_loader_setup(tl, fd);
+ file_data_unref(fd);
+ g_free(cache_path);
+ tl->cache_hit = TRUE;
+ }
+ else
+ {
+ thumb_loader_setup(tl, tl->fd);
+ }
+
+ g_signal_connect(G_OBJECT(tl->il), "done", (GCallback)thumb_loader_done_cb, tl);
+ if (!image_loader_start(tl->il))
+ {
+ /* try from original if cache attempt */
+ if (tl->cache_hit)
+ {
+ tl->cache_hit = FALSE;
+ log_printf("%s", _("Thumbnail image in cache failed to load, trying to recreate.\n"));
+
+ thumb_loader_setup(tl, tl->fd);
+ g_signal_connect(G_OBJECT(tl->il), "done", (GCallback)thumb_loader_done_cb, tl);
+ if (image_loader_start(tl->il)) return TRUE;
+ }
+ /* mark failed thumbnail in cache with 0 byte file */
+ if (tl->cache_enable)
+ {
+ thumb_loader_save_thumbnail(tl, TRUE);
+ }
+
+ image_loader_free(tl->il);
+ tl->il = NULL;
+ thumb_loader_set_fallback(tl);
+ return FALSE;
+ }
+
+ return TRUE;
}
+GdkPixbuf *thumb_loader_get_pixbuf(ThumbLoader *tl)
+{
+ GdkPixbuf *pixbuf;
+
+ if (tl && tl->standard_loader)
+ {
+ return thumb_loader_std_get_pixbuf((ThumbLoaderStd *)tl);
+ }
+
+ if (tl && tl->fd && tl->fd->thumb_pixbuf)
+ {
+ pixbuf = tl->fd->thumb_pixbuf;
+ g_object_ref(pixbuf);
+ }
+ else
+ {
+ pixbuf = pixbuf_fallback(NULL, tl->max_w, tl->max_h);
+ }
+
+ return pixbuf;
+}
+
+ThumbLoader *thumb_loader_new(gint width, gint height)
+{
+ ThumbLoader *tl;
+
+ /* non-std thumb loader is more effective for configurations with disabled caching
+ because it loads the thumbnails at the required size. loader_std loads
+ the thumbnails at the sizes appropriate for standard cache (typically 256x256 pixels)
+ and then performs one additional scaling */
+ if (options->thumbnails.spec_standard && options->thumbnails.enable_caching)
+ {
+ return (ThumbLoader *)thumb_loader_std_new(width, height);
+ }
+
+ tl = g_new0(ThumbLoader, 1);
+
+ tl->cache_enable = options->thumbnails.enable_caching;
+ tl->percent_done = 0.0;
+ tl->max_w = width;
+ tl->max_h = height;
+
+ return tl;
+}
+
+void thumb_loader_free(ThumbLoader *tl)
+{
+ if (!tl) return;
+
+ if (tl->standard_loader)
+ {
+ thumb_loader_std_free((ThumbLoaderStd *)tl);
+ return;
+ }
+
+ image_loader_free(tl->il);
+ file_data_unref(tl->fd);
+
+ if (tl->idle_done_id) g_source_remove(tl->idle_done_id);
+
+ g_free(tl);
+}
+
+/* release thumb_pixbuf on file change - this forces reload. */
+void thumb_notify_cb(FileData *fd, NotifyType type, gpointer data)
+{
+ if ((type & (NOTIFY_REREAD | NOTIFY_CHANGE)) && fd->thumb_pixbuf)
+ {
+ DEBUG_1("Notify thumb: %s %04x", fd->path, type);
+ g_object_unref(fd->thumb_pixbuf);
+ fd->thumb_pixbuf = NULL;
+ }
+}
+
+
/*
*-----------------------------------------------------------------------------
* xvpics thumbnail support, read-only (private)
*
* Note: Code has been modified to fit the style of the other code, and to use
* a few more glib-isms.
+ * 08-28-2000: Updated to return a gdk_pixbuf, Imlib is dieing a death here.
*/
#define XV_BUFFER 2048
{
FILE *file;
gchar buffer[XV_BUFFER];
- guchar *data;
- gint width, height, depth;
+ guchar *data = NULL;
file = fopen(filename, "rt");
- if(!file) return NULL;
+ if (!file) return NULL;
- fgets(buffer, XV_BUFFER, file);
- if(strncmp(buffer, "P7 332", 6) != 0)
+ if (fgets(buffer, XV_BUFFER, file) != NULL
+ && strncmp(buffer, "P7 332", 6) == 0)
{
- fclose(file);
- return NULL;
- }
+ gint width, height, depth;
- while(fgets(buffer, XV_BUFFER, file) && buffer[0] == '#') /* do_nothing() */;
+ while (fgets(buffer, XV_BUFFER, file) && buffer[0] == '#') /* do_nothing() */;
- if(sscanf(buffer, "%d %d %d", &width, &height, &depth) != 3)
- {
- fclose(file);
- return NULL;
- }
+ if (sscanf(buffer, "%d %d %d", &width, &height, &depth) == 3)
+ {
+ gsize size = width * height;
- data = g_new(guchar, width * height);
- fread(data, 1, width * height, file);
+ data = g_new(guchar, size);
+ if (data && fread(data, 1, size, file) == size)
+ {
+ *widthp = width;
+ *heightp = height;
+ }
+ }
+ }
fclose(file);
- *widthp = width;
- *heightp = height;
return data;
}
#undef XV_BUFFER
-static void normalize_thumb(gint *width, gint *height)
+static void free_rgb_buffer(guchar *pixels, gpointer data)
{
- if(*width > thumb_max_width || *height > thumb_max_height)
- {
- gfloat factor = MAX((gfloat) *width / thumb_max_width, (gfloat) *height / thumb_max_height);
- *width = (gfloat) *width / factor;
- *height = (gfloat) *height / factor;
- }
+ g_free(pixels);
}
-static gint get_xv_thumbnail(gchar *thumb_filename, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask)
+static GdkPixbuf *get_xv_thumbnail(gchar *thumb_filename, gint max_w, gint max_h)
{
gint width, height;
gchar *thumb_name;
- gchar *tmp_string;
- gchar *last_slash;
+ gchar *path;
+ gchar *directory;
+ gchar *name;
guchar *packed_data;
- tmp_string = g_strdup(thumb_filename);
- last_slash = strrchr(tmp_string, '/');
- if(!last_slash) return -1;
- *last_slash++ = '\0';
+ path = path_from_utf8(thumb_filename);
+ directory = g_path_get_dirname(path);
+ name = g_path_get_basename(path);
+
+ thumb_name = g_build_filename(directory, ".xvpics", name, NULL);
+
+ g_free(name);
+ g_free(directory);
+ g_free(path);
- thumb_name = g_strconcat(tmp_string, "/.xvpics/", last_slash, NULL);
packed_data = load_xv_thumbnail(thumb_name, &width, &height);
- g_free(tmp_string);
g_free(thumb_name);
- if(packed_data)
+ if (packed_data)
{
guchar *rgb_data;
- GdkImlibImage *image;
+ GdkPixbuf *pixbuf;
gint i;
rgb_data = g_new(guchar, width * height * 3);
- for(i = 0; i < width * height; i++)
+ for (i = 0; i < width * height; i++)
{
rgb_data[i * 3 + 0] = (packed_data[i] >> 5) * 36;
rgb_data[i * 3 + 1] = ((packed_data[i] & 28) >> 2) * 36;
rgb_data[i * 3 + 2] = (packed_data[i] & 3) * 85;
}
-
g_free(packed_data);
- image = gdk_imlib_create_image_from_data(rgb_data, NULL, width, height);
- g_free(rgb_data);
- normalize_thumb(&width, &height);
- gdk_imlib_render(image, width, height);
-
- if(*thumb_pixmap) gdk_imlib_free_pixmap(*thumb_pixmap);
-
- *thumb_pixmap = gdk_imlib_move_image(image);
- *thumb_mask = gdk_imlib_move_mask(image);
- gdk_imlib_destroy_image(image);
- return thumb_max_width - width;
+
+ pixbuf = gdk_pixbuf_new_from_data(rgb_data, GDK_COLORSPACE_RGB, FALSE, 8,
+ width, height, 3 * width, free_rgb_buffer, NULL);
+
+ if (pixbuf_scale_aspect(width, height, max_w, max_h, &width, &height))
+ {
+ /* scale */
+ GdkPixbuf *tmp;
+
+ tmp = pixbuf;
+ pixbuf = gdk_pixbuf_scale_simple(tmp, width, height, GDK_INTERP_NEAREST);
+ g_object_unref(tmp);
+ }
+
+ return pixbuf;
}
- return -1;
+ return NULL;
}
-
+/* vim: set shiftwidth=8 softtabstop=0 cindent cinoptions={1s: */