Mercurial > geeqie
diff src/thumb.c @ 1:b3e0e515fabf
Initial revision
author | gqview |
---|---|
date | Mon, 03 Apr 2000 18:24:05 +0000 |
parents | |
children | c0e337a01cb7 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/thumb.c Mon Apr 03 18:24:05 2000 +0000 @@ -0,0 +1,371 @@ +/* + * GQview image viewer + * (C)1999 John Ellis + * + * Author: John Ellis + * + */ + +#include "gqview.h" +#include "icons/img_unknown.xpm" /* fixme! duplicate, included in image.c too */ + +#define THUMBNAIL_CACHE_DIR "/.gqview_thmb" + +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); + +/* + *----------------------------------------------------------------------------- + * thumbnail routines: creation, caching, and maintenance (public) + *----------------------------------------------------------------------------- + */ + +gint create_thumbnail(gchar *path, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask) +{ + gint width, height; + gint space; + GdkImlibImage *thumb = NULL; + GdkImlibImage *image = NULL; + gint cached = FALSE; + + if (debug) printf("Gen thumbnail:%s\n",path); + + /* 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; + } + } + + /* start load from cache */ + + if (enable_thumb_caching) + { + gchar *cache_path; + cache_path = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, path, ".png", NULL); + + if (isfile(cache_path) && filetime(cache_path) >= filetime(path)) + { + 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) + { + 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); + } + else + { + cached = TRUE; + } + } + else + image = gdk_imlib_load_image(path); + + } + else + image = gdk_imlib_load_image(path); + + if (!image) + { + image = gdk_imlib_create_image_from_xpm_data((gchar **)img_unknown_xpm); + cached = TRUE; /* no need to save a thumbnail of the unknown pixmap */ + } + + if (image) + { + if (image->rgb_width > thumb_max_width || image->rgb_height > thumb_max_height) + { + 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; + } + } + else + { + width = image->rgb_width; + height = image->rgb_height; + cached = TRUE; /* don't cache images smaller than thumbnail size */ + } + if (*thumb_pixmap) gdk_imlib_free_pixmap(*thumb_pixmap); + *thumb_pixmap = NULL; + *thumb_mask = NULL; + + /* start save cache */ + + if (enable_thumb_caching && !cached) + { + 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_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); + + thumb_path = g_strconcat(base_dir, path, ".png", NULL); + if (debug) printf("Saving thumb: %s\n",thumb_path); + + gdk_imlib_save_image(thumb, thumb_path, NULL); + + g_free(base_dir); + g_free(thumb_path); + } + else + { + thumb = image; + } + + /* 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; + } + else + { + space = -1; + } + return space; +} + +gint maintain_thumbnail_dir(gchar *dir, gint recursive) +{ + gchar *thumb_dir; + gint base_length; + gint still_have_a_file = FALSE; + + if (debug) printf("maintainance check: %s\n", dir); + + base_length = strlen(homedir()) + strlen(THUMBNAIL_CACHE_DIR); + thumb_dir = g_strconcat(homedir(), THUMBNAIL_CACHE_DIR, dir, NULL); + + if (isdir(thumb_dir)) + { + DIR *dp; + struct dirent *dirent; + struct stat ent_sbuf; + + if((dp = opendir(thumb_dir))==NULL) + { + /* dir not found */ + g_free(thumb_dir); + return FALSE; + } + + while ((dirent = readdir(dp)) != NULL) + { + /* 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 + { + 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; + } + g_free(path_buf); + } + } + closedir(dp); + } + g_free(thumb_dir); + return still_have_a_file; +} + +/* + *----------------------------------------------------------------------------- + * xvpics thumbnail support, read-only (private) + *----------------------------------------------------------------------------- + */ + +/* + * xvpics code originally supplied by: + * "Diederen Damien" <D.Diederen@student.ulg.ac.be> + * + * Note: Code has been modified to fit the style of the other code, and to use + * a few more glib-isms. + */ + +#define XV_BUFFER 2048 +static guchar *load_xv_thumbnail(gchar *filename, gint *widthp, gint *heightp) +{ + FILE *file; + gchar buffer[XV_BUFFER]; + guchar *data; + gint width, height, depth; + + file = fopen(filename, "rt"); + if(!file) return NULL; + + fgets(buffer, XV_BUFFER, file); + if(strncmp(buffer, "P7 332", 6) != 0) + { + fclose(file); + return NULL; + } + + while(fgets(buffer, XV_BUFFER, file) && buffer[0] == '#') /* do_nothing() */; + + if(sscanf(buffer, "%d %d %d", &width, &height, &depth) != 3) + { + fclose(file); + return NULL; + } + + data = g_new(guchar, width * height); + fread(data, 1, width * height, file); + + fclose(file); + *widthp = width; + *heightp = height; + return data; +} +#undef XV_BUFFER + +static void normalize_thumb(gint *width, gint *height) +{ + 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; + } +} + +static gint get_xv_thumbnail(gchar *thumb_filename, GdkPixmap **thumb_pixmap, GdkBitmap **thumb_mask) +{ + gint width, height; + gchar *thumb_name; + gchar *tmp_string; + gchar *last_slash; + guchar *packed_data; + + tmp_string = g_strdup(thumb_filename); + last_slash = strrchr(tmp_string, '/'); + if(!last_slash) return -1; + *last_slash++ = '\0'; + + 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) + { + guchar *rgb_data; + GdkImlibImage *image; + gint i; + + rgb_data = g_new(guchar, width * height * 3); + 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; + } + + return -1; +} +