diff options
Diffstat (limited to 'src/thumbnail.c')
-rw-r--r-- | src/thumbnail.c | 673 |
1 files changed, 357 insertions, 316 deletions
diff --git a/src/thumbnail.c b/src/thumbnail.c index ed4e0fb..70af5e0 100644 --- a/src/thumbnail.c +++ b/src/thumbnail.c @@ -1,6 +1,7 @@ /* thumbnail.c Copyright (C) 1999-2003 Tom Gilbert. +Copyright (C) 2010-2024 Birte Kristina Friesel. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to @@ -30,10 +31,9 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "thumbnail.h" #include "md5.h" #include "feh_png.h" +#include "index.h" +#include "signals.h" -static char *create_index_dimension_string(int w, int h); -static char *create_index_size_string(char *file); -static char *create_index_title_string(int num, int w, int h); static gib_list *thumbnails = NULL; static thumbmode_data td; @@ -55,23 +55,24 @@ void init_thumbnail_mode(void) int max_column_w = 0; */ + Imlib_Load_Error err; Imlib_Image im_temp; int ww = 0, hh = 0, www, hhh, xxx, yyy; + int orig_w, orig_h; int x = 0, y = 0; winwidget winwid = NULL; Imlib_Image im_thumb = NULL; unsigned char trans_bg = 0; int title_area_h = 0; int tw = 0, th = 0; - int fw_name, fw_size, fw_dim, fh; + int fw, fh; int thumbnailcount = 0; feh_file *file = NULL; gib_list *l, *last = NULL; - int lines; + int lineno; int index_image_width, index_image_height; - int x_offset_name = 0, x_offset_dim = 0, x_offset_size = 0; - char *s; unsigned int thumb_counter = 0; + gib_list *line, *lines; /* initialize thumbnail mode data */ td.im_main = NULL; @@ -90,6 +91,8 @@ void init_thumbnail_mode(void) td.vertical = 0; td.max_column_w = 0; + if (!opt.thumb_title) + opt.thumb_title = "%n"; mode = "thumbnail"; if (opt.font) @@ -102,6 +105,9 @@ void init_thumbnail_mode(void) int fh, fw; td.font_title = gib_imlib_load_font(opt.title_font); + if (!td.font_title) + td.font_title = gib_imlib_load_font(DEFAULT_FONT_TITLE); + gib_imlib_get_text_size(td.font_title, "W", NULL, &fw, &fh, IMLIB_TEXT_TO_RIGHT); title_area_h = fh + 4; @@ -114,9 +120,8 @@ void init_thumbnail_mode(void) /* Work out how tall the font is */ gib_imlib_get_text_size(td.font_main, "W", NULL, &tw, &th, IMLIB_TEXT_TO_RIGHT); - /* For now, allow room for the right number of lines with small gaps */ - td.text_area_h = ((th + 2) * (opt.index_show_name + opt.index_show_size + - opt.index_show_dim)) + 5; + get_index_string_dim(NULL, td.font_main, &fw, &fh); + td.text_area_h = fh + 5; /* This includes the text area for index data */ td.thumb_tot_h = opt.thumb_h + td.text_area_h; @@ -140,11 +145,21 @@ void init_thumbnail_mode(void) index_image_width = td.w; index_image_height = td.h + title_area_h; + D(("imlib_create_image(%d, %d)\n", index_image_width, index_image_height)); td.im_main = imlib_create_image(index_image_width, index_image_height); - gib_imlib_image_set_has_alpha(td.im_main, 1); - if (!td.im_main) - eprintf("Imlib error creating index image, are you low on RAM?"); + if (!td.im_main) { + if (index_image_height >= 32768 || index_image_width >= 32768) { + eprintf("Failed to create %dx%d pixels (%d MB) index image.\n" + "This is probably due to Imlib2 issues when dealing with images larger than 32k x 32k pixels.", + index_image_width, index_image_height, index_image_width * index_image_height * 4 / (1024*1024)); + } else { + eprintf("Failed to create %dx%d pixels (%d MB) index image. Do you have enough RAM?", + index_image_width, index_image_height, index_image_width * index_image_height * 4 / (1024*1024)); + } + } + + gib_imlib_image_set_has_alpha(td.im_main, 1); if (td.im_bg) gib_imlib_blend_image_onto_image(td.im_main, td.im_bg, @@ -161,20 +176,13 @@ void init_thumbnail_mode(void) td.h + title_area_h, 0, 0, 0, 255); } - /* Create title now */ - - if (!opt.title) - s = estrdup(PACKAGE " [thumbnail mode]"); - else - s = estrdup(feh_printf(opt.title, NULL)); if (opt.display) { - winwid = winwidget_create_from_image(td.im_main, s, WIN_TYPE_THUMBNAIL); + winwid = winwidget_create_from_image(td.im_main, WIN_TYPE_THUMBNAIL); + winwidget_rename(winwid, PACKAGE " [thumbnail mode]"); winwidget_show(winwid); } - /* make sure we have an ~/.thumbnails/normal directory for storing - permanent thumbnails */ td.cache_thumbnails = opt.cache_thumbnails; if (td.cache_thumbnails) { @@ -183,9 +191,15 @@ void init_thumbnail_mode(void) else td.cache_dim = opt.thumb_h; - if (td.cache_dim > 256) { - /* No caching as specified by standard. Sort of. */ + if (td.cache_dim > 1024) { + /* Not specified by XDG thumbnail standard */ td.cache_thumbnails = 0; + } else if (td.cache_dim > 512) { + td.cache_dim = 1024; + td.cache_dir = estrdup("xx-large"); + } else if (td.cache_dim > 256) { + td.cache_dim = 512; + td.cache_dir = estrdup("x-large"); } else if (td.cache_dim > 128) { td.cache_dim = 256; td.cache_dir = estrdup("large"); @@ -204,7 +218,8 @@ void init_thumbnail_mode(void) } D(("About to load image %s\n", file->filename)); /* if (feh_load_image(&im_temp, file) != 0) */ - if (feh_thumbnail_get_thumbnail(&im_temp, file) != 0) { + if (feh_thumbnail_get_thumbnail(&im_temp, file, &orig_w, &orig_h) + != 0) { if (opt.verbose) feh_display_status('.'); D(("Successfully loaded %s\n", file->filename)); @@ -212,6 +227,12 @@ void init_thumbnail_mode(void) hhh = opt.thumb_h; ww = gib_imlib_image_get_width(im_temp); hh = gib_imlib_image_get_height(im_temp); + + if (!orig_w) { + orig_w = ww; + orig_h = hh; + } + thumbnailcount++; if (gib_imlib_image_has_alpha(im_temp)) imlib_context_set_blend(1); @@ -252,34 +273,18 @@ void init_thumbnail_mode(void) td.text_area_w = opt.thumb_w; /* Now draw on the info text */ - if (opt.index_show_name) { - gib_imlib_get_text_size(td.font_main, file->name, NULL, - &fw_name, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw_name > td.text_area_w) - td.text_area_w = fw_name; - } - if (opt.index_show_dim) { - gib_imlib_get_text_size(td.font_main, - create_index_dimension_string(ww, hh), - NULL, &fw_dim, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw_dim > td.text_area_w) - td.text_area_w = fw_dim; - } - if (opt.index_show_size) { - gib_imlib_get_text_size(td.font_main, - create_index_size_string(file->filename), - NULL, &fw_size, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw_size > td.text_area_w) - td.text_area_w = fw_size; + if (opt.index_info) { + get_index_string_dim(file, td.font_main, &fw, &fh); + if (fw > td.text_area_w) + td.text_area_w = fw; + if (fh > td.text_area_h) { + td.text_area_h = fh + 5; + td.thumb_tot_h = opt.thumb_h + td.text_area_h; + } } if (td.text_area_w > opt.thumb_w) td.text_area_w += 5; - /* offsets for centering text */ - x_offset_name = (td.text_area_w - fw_name) / 2; - x_offset_dim = (td.text_area_w - fw_dim) / 2; - x_offset_size = (td.text_area_w - fw_size) / 2; - if (td.vertical) { if (td.text_area_w > td.max_column_w) td.max_column_w = td.text_area_w; @@ -320,28 +325,23 @@ void init_thumbnail_mode(void) gib_imlib_free_image_and_decache(im_thumb); - lines = 0; - if (opt.index_show_name) - gib_imlib_text_draw(td.im_main, - td.font_main, NULL, - x + x_offset_name, - y + opt.thumb_h + (lines++ * (th + 2)) + 2, - file->name, IMLIB_TEXT_TO_RIGHT, - 255, 255, 255, 255); - if (opt.index_show_dim) - gib_imlib_text_draw(td.im_main, - td.font_main, NULL, - x + x_offset_dim, - y + opt.thumb_h + (lines++ * (th + 2)) + 2, - create_index_dimension_string(ww, hh), - IMLIB_TEXT_TO_RIGHT, 255, 255, 255, 255); - if (opt.index_show_size) - gib_imlib_text_draw(td.im_main, - td.font_main, NULL, - x + x_offset_size, - y + opt.thumb_h + (lines++ * (th + 2)) + 2, - create_index_size_string(file->filename), - IMLIB_TEXT_TO_RIGHT, 255, 255, 255, 255); + lineno = 0; + if (opt.index_info) { + line = lines = feh_wrap_string(create_index_string(file), + opt.thumb_w * 3, td.font_main, NULL); + + while (line) { + gib_imlib_get_text_size(td.font_main, (char *) line -> data, + NULL, &fw, &fh, IMLIB_TEXT_TO_RIGHT); + gib_imlib_text_draw(td.im_main, td.font_main, NULL, + x + ((td.text_area_w - fw) >> 1), + y + opt.thumb_h + (lineno++ * (th + 2)) + 2, + (char *) line->data, + IMLIB_TEXT_TO_RIGHT, 255, 255, 255, 255); + line = line->next; + } + gib_list_free_and_data(lines); + } if (td.vertical) y += td.thumb_tot_h; @@ -355,7 +355,7 @@ void init_thumbnail_mode(void) if (opt.display) { /* thumb_counter is unsigned, so no need to catch overflows */ if (++thumb_counter == opt.thumb_redraw) { - winwidget_render_image(winwid, 0, 0); + winwidget_render_image(winwid, 0, 1); thumb_counter = 0; } if (!feh_main_iteration(0)) @@ -364,10 +364,10 @@ void init_thumbnail_mode(void) } if (thumb_counter != 0) - winwidget_render_image(winwid, 0, 0); + winwidget_render_image(winwid, 0, 1); if (opt.verbose) - fprintf(stdout, "\n"); + putc('\n', stderr); if (opt.title_font) { int fw, fh, fx, fy; @@ -380,6 +380,9 @@ void init_thumbnail_mode(void) fy = index_image_height - fh - 2; gib_imlib_text_draw(td.im_main, td.font_title, NULL, fx, fy, s, IMLIB_TEXT_TO_RIGHT, 255, 255, 255, 255); + + if (opt.display) + winwidget_render_image(winwid, 0, 1); } if (opt.output && opt.output_file) { @@ -387,16 +390,21 @@ void init_thumbnail_mode(void) if (opt.output_dir) snprintf(output_buf, 1024, "%s/%s", opt.output_dir, opt.output_file); - else - strncpy(output_buf, opt.output_file, 1024); - gib_imlib_save_image(td.im_main, output_buf); - if (opt.verbose) { + else { + strncpy(output_buf, opt.output_file, 1023); + output_buf[1023] = '\0'; + } + gib_imlib_save_image_with_error_return(td.im_main, output_buf, &err); + if (err) { + feh_print_load_error(output_buf, td.im_main, err, LOAD_ERROR_IMLIB); + } + else if (opt.verbose) { int tw, th; tw = gib_imlib_image_get_width(td.im_main); th = gib_imlib_image_get_height(td.im_main); - fprintf(stdout, PACKAGE " - File saved as %s\n", output_buf); - fprintf(stdout, + fprintf(stderr, PACKAGE " - File saved as %s\n", output_buf); + fprintf(stderr, " - Image is %dx%d pixels and contains %d thumbnails\n", tw, th, thumbnailcount); } @@ -404,43 +412,19 @@ void init_thumbnail_mode(void) if (!opt.display) gib_imlib_free_image_and_decache(td.im_main); - - free(s); - return; -} - -static char *create_index_size_string(char *file) -{ - static char str[50]; - int size = 0; - double kbs = 0.0; - struct stat st; - - if (stat(file, &st)) - kbs = 0.0; - else { - size = st.st_size; - kbs = (double) size / 1000; + else if (opt.start_list_at) { + for (l = thumbnails; l; l = l->next) { + if (!strcmp(opt.start_list_at, FEH_THUMB(l->data)->file->filename)) { + free(opt.start_list_at); + opt.start_list_at = NULL; + feh_thumbnail_select(winwid, FEH_THUMB(l->data)); + break; + } + } } - snprintf(str, sizeof(str), "%.2fKb", kbs); - return(str); -} - -static char *create_index_dimension_string(int w, int h) -{ - static char str[50]; - - snprintf(str, sizeof(str), "%dx%d", w, h); - return(str); -} - -static char *create_index_title_string(int num, int w, int h) -{ - static char str[50]; - snprintf(str, sizeof(str), PACKAGE " index - %d thumbnails, %d by %d pixels", num, w, h); - return(str); + return; } feh_thumbnail *feh_thumbnail_new(feh_file * file, int x, int y, int w, int h) @@ -518,24 +502,20 @@ void feh_thumbnail_mark_removed(feh_file * file, int deleted) if (thumb) { w = winwidget_get_first_window_of_type(WIN_TYPE_THUMBNAIL); if (w) { - td.font_main = imlib_load_font(DEFAULT_FONT_TITLE); + int tw, th; if (deleted) gib_imlib_image_fill_rectangle(w->im, thumb->x, thumb->y, thumb->w, thumb->h, 255, 0, 0, 150); else gib_imlib_image_fill_rectangle(w->im, thumb->x, thumb->y, thumb->w, thumb->h, 0, 0, 255, 150); - if (td.font_main) { - int tw, th; - - gib_imlib_get_text_size(td.font_main, "X", NULL, &tw, &th, - IMLIB_TEXT_TO_RIGHT); - gib_imlib_text_draw(w->im, td.font_main, NULL, - thumb->x + ((thumb->w - tw) / 2), - thumb->y + ((thumb->h - th) / 2), "X", - IMLIB_TEXT_TO_RIGHT, 205, 205, 50, 255); - } else - weprintf(DEFAULT_FONT_TITLE); + + gib_imlib_get_text_size(td.font_main, "X", NULL, &tw, &th, + IMLIB_TEXT_TO_RIGHT); + gib_imlib_text_draw(w->im, td.font_main, NULL, + thumb->x + ((thumb->w - tw) / 2), + thumb->y + ((thumb->h - th) / 2), "X", + IMLIB_TEXT_TO_RIGHT, 205, 205, 50, 255); winwidget_render_image(w, 0, 1); } thumb->exists = 0; @@ -545,193 +525,68 @@ void feh_thumbnail_mark_removed(feh_file * file, int deleted) void feh_thumbnail_calculate_geometry(void) { - gib_list *l; - feh_file *file; - - int x = 0, y = 0; - int fw, fh; - if (!opt.limit_w && !opt.limit_h) { if (td.im_bg) { - if (opt.verbose) - fprintf(stdout, - PACKAGE - " - No size restriction specified for index.\n" - " You did specify a background however, so the\n" - " index size has defaulted to the size of the image\n"); opt.limit_w = td.bg_w; opt.limit_h = td.bg_h; - } else { - if (opt.verbose) - fprintf(stdout, - PACKAGE - " - No size restriction specified for index.\n" - " Using defaults (width limited to 640)\n"); - opt.limit_w = 640; - } + } else + opt.limit_w = 800; } /* Here we need to whiz through the files, and look at the filenames and info in the selected font, work out how much space we need, and calculate the size of the image we will require */ - if (opt.limit_w && opt.limit_h) { - int rec_h = 0; - + if (opt.limit_w) { td.w = opt.limit_w; - td.h = opt.limit_h; - - /* Work out if this is big enough, and give a warning if not */ - - /* Pretend we are limiting width by that specified, loop through, and - see it we fit in the height specified. If not, continue the loop, - and recommend the final value instead. Carry on and make the index - anyway. */ - - for (l = filelist; l; l = l->next) { - file = FEH_FILE(l->data); - td.text_area_w = opt.thumb_w; - if (opt.index_show_name) { - gib_imlib_get_text_size(td.font_main, file->name, NULL, - &fw, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw > td.text_area_w) - td.text_area_w = fw; - } - if (opt.index_show_dim) { - gib_imlib_get_text_size(td.font_main, - create_index_dimension_string(1000, 1000), - NULL, &fw, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw > td.text_area_w) - td.text_area_w = fw; - } - if (opt.index_show_size) { - gib_imlib_get_text_size(td.font_main, - create_index_size_string(file->filename), - NULL, &fw, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw > td.text_area_w) - td.text_area_w = fw; - } - if (td.text_area_w > opt.thumb_w) - td.text_area_w += 5; - if ((x > td.w - td.text_area_w)) { - x = 0; - y += td.thumb_tot_h; - } - - x += td.text_area_w; - } - rec_h = y + td.thumb_tot_h; - - if (td.h < rec_h) { - weprintf - ("The image size you specified (%d by %d) is not large\n" - "enough to hold all the thumnails you specified (%d). To fit all\n" - "the thumnails, either decrease their size, choose a smaller font,\n" - "or use a larger image (may I recommend %d by %d?)", - opt.limit_w, opt.limit_h, filelist_len, opt.limit_w, rec_h); + index_calculate_height(td.font_main, td.w, &td.h, &td.thumb_tot_h); + + if (opt.limit_h) { + if (td.h> opt.limit_h) + weprintf( + "The image size you specified (%dx%d) is not large\n" + "enough to hold all %d thumbnails. To fit all\n" + "the thumnails, either decrease their size, choose a smaller font,\n" + "or use a larger image (like %dx%d)", + opt.limit_w, opt.limit_h, filelist_len, opt.limit_w, td.h); + td.h = opt.limit_h; } } else if (opt.limit_h) { td.vertical = 1; td.h = opt.limit_h; - /* calc w */ - for (l = filelist; l; l = l->next) { - file = FEH_FILE(l->data); - td.text_area_w = opt.thumb_w; - /* Calc width of text */ - if (opt.index_show_name) { - gib_imlib_get_text_size(td.font_main, file->name, NULL, - &fw, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw > td.text_area_w) - td.text_area_w = fw; - } - if (opt.index_show_dim) { - gib_imlib_get_text_size(td.font_main, - create_index_dimension_string(1000, 1000), - NULL, &fw, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw > td.text_area_w) - td.text_area_w = fw; - } - if (opt.index_show_size) { - gib_imlib_get_text_size(td.font_main, - create_index_size_string(file->filename), - NULL, &fw, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw > td.text_area_w) - td.text_area_w = fw; - } - if (td.text_area_w > opt.thumb_w) - td.text_area_w += 5; - - if (td.text_area_w > td.max_column_w) - td.max_column_w = td.text_area_w; - - if ((y > td.h - td.thumb_tot_h)) { - y = 0; - x += td.max_column_w; - td.max_column_w = 0; - } - - y += td.thumb_tot_h; - } - td.w = x + td.text_area_w; - td.max_column_w = 0; - } else if (opt.limit_w) { - td.w = opt.limit_w; - /* calc h */ - for (l = filelist; l; l = l->next) { - file = FEH_FILE(l->data); - td.text_area_w = opt.thumb_w; - if (opt.index_show_name) { - gib_imlib_get_text_size(td.font_main, file->name, NULL, - &fw, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw > td.text_area_w) - td.text_area_w = fw; - } - if (opt.index_show_dim) { - gib_imlib_get_text_size(td.font_main, - create_index_dimension_string(1000, 1000), - NULL, &fw, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw > td.text_area_w) - td.text_area_w = fw; - } - if (opt.index_show_size) { - gib_imlib_get_text_size(td.font_main, - create_index_size_string(file->filename), - NULL, &fw, &fh, IMLIB_TEXT_TO_RIGHT); - if (fw > td.text_area_w) - td.text_area_w = fw; - } - - if (td.text_area_w > opt.thumb_w) - td.text_area_w += 5; - - if ((x > td.w - td.text_area_w)) { - x = 0; - y += td.thumb_tot_h; - } - - x += td.text_area_w; - } - td.h = y + td.thumb_tot_h; + index_calculate_width(td.font_main, &td.w, td.h, &td.thumb_tot_h); } } -int feh_thumbnail_get_thumbnail(Imlib_Image * image, feh_file * file) +int feh_thumbnail_get_thumbnail(Imlib_Image * image, feh_file * file, + int * orig_w, int * orig_h) { int status = 0; char *thumb_file = NULL, *uri = NULL; + *orig_w = 0; + *orig_h = 0; + if (!file || !file->filename) return (0); if (td.cache_thumbnails) { uri = feh_thumbnail_get_name_uri(file->filename); thumb_file = feh_thumbnail_get_name(uri); - status = feh_thumbnail_get_generated(image, file, thumb_file); + + if (thumb_file == NULL) { + free(uri); + return feh_load_image(image, file); + } + + status = feh_thumbnail_get_generated(image, file, thumb_file, + orig_w, orig_h); if (!status) - status = feh_thumbnail_generate(image, file, thumb_file, uri); + status = feh_thumbnail_generate(image, file, thumb_file, uri, + orig_w, orig_h); D(("uri is %s, thumb_file is %s\n", uri, thumb_file)); free(uri); @@ -742,21 +597,39 @@ int feh_thumbnail_get_thumbnail(Imlib_Image * image, feh_file * file) return status; } +static char *feh_thumbnail_get_prefix(void) +{ + char *dir = NULL, *home, *xdg_cache_home; + + // TODO: perhaps make sure that either of those paths aren't /-terminated + + xdg_cache_home = getenv("XDG_CACHE_HOME"); + if (xdg_cache_home && xdg_cache_home[0] == '/') { + dir = estrjoin("/", xdg_cache_home, "thumbnails", td.cache_dir, NULL); + } else { + home = getenv("HOME"); + if (home && home[0] == '/') { + dir = estrjoin("/", home, ".cache/thumbnails", td.cache_dir, NULL); + } + } + + return dir; +} + char *feh_thumbnail_get_name(char *uri) { - char *home = NULL, *thumb_file = NULL, *md5_name = NULL; + char *prefix, *thumb_file = NULL, *md5_name; /* FIXME: make sure original file isn't under ~/.thumbnails */ - md5_name = feh_thumbnail_get_name_md5(uri); - - home = getenv("HOME"); - if (home) { - thumb_file = estrjoin("/", home, ".thumbnails", td.cache_dir, md5_name, NULL); + prefix = feh_thumbnail_get_prefix(); + if (prefix) { + md5_name = feh_thumbnail_get_name_md5(uri); + thumb_file = estrjoin("/", prefix, md5_name, NULL); + free(md5_name); + free(prefix); } - free(md5_name); - return thumb_file; } @@ -765,14 +638,15 @@ char *feh_thumbnail_get_name_uri(char *name) char *cwd, *uri = NULL; /* FIXME: what happens with http, https, and ftp? MTime etc */ - if ((strncmp(name, "http://", 7) != 0) && - (strncmp(name, "https://", 8) != 0) && (strncmp(name, "ftp://", 6) != 0) - && (strncmp(name, "file://", 7) != 0)) { + if (!path_is_url(name)) { - /* make sure it's an absoulte path */ + /* make sure it's an absolute path */ /* FIXME: add support for ~, need to investigate if it's expanded - somewhere else before adding (unecessary) code */ + somewhere else before adding (unnecessary) code */ if (name[0] != '/') { + /* work around /some/path/./image.ext */ + if ((strncmp(name, "./", 2)) == 0) + name += 2; cwd = getcwd(NULL, 0); uri = estrjoin("/", "file:/", cwd, name, NULL); free(cwd); @@ -798,7 +672,7 @@ char *feh_thumbnail_get_name_md5(char *uri) md5_finish(&pms, digest); /* print the md5 as hex to a string */ - md5_name = emalloc(32 + 4 + 1 * sizeof(char)); /* md5 + .png + '\0' */ + md5_name = emalloc(32 + 4 + 1); /* md5 + .png + '\0' */ for (i = 0, pos = md5_name; i < 16; i++, pos += 2) { sprintf(pos, "%02x", digest[i]); } @@ -808,15 +682,18 @@ char *feh_thumbnail_get_name_md5(char *uri) } int feh_thumbnail_generate(Imlib_Image * image, feh_file * file, - char *thumb_file, char *uri) + char *thumb_file, char *uri, int * orig_w, int * orig_h) { int w, h, thumb_w, thumb_h; Imlib_Image im_temp; struct stat sb; + char c_width[8], c_height[8]; + char *tmp_thumb_file, *prefix; + int tmp_fd; if (feh_load_image(&im_temp, file) != 0) { - w = gib_imlib_image_get_width(im_temp); - h = gib_imlib_image_get_height(im_temp); + *orig_w = w = gib_imlib_image_get_width(im_temp); + *orig_h = h = gib_imlib_image_get_height(im_temp); thumb_w = td.cache_dim; thumb_h = td.cache_dim; @@ -826,6 +703,13 @@ int feh_thumbnail_generate(Imlib_Image * image, feh_file * file, thumb_h = td.cache_dim / ratio; else if (ratio != 1.0) thumb_w = td.cache_dim * ratio; + } else { + /* + * The image is smaller than the specified thumbnail size. + * Do not cache or transform it. + */ + *image = im_temp; + return 1; } *image = gib_imlib_create_cropped_scaled_image(im_temp, 0, 0, w, h, @@ -834,31 +718,57 @@ int feh_thumbnail_generate(Imlib_Image * image, feh_file * file, if (!stat(file->filename, &sb)) { char c_mtime[128]; sprintf(c_mtime, "%d", (int)sb.st_mtime); - feh_png_write_png(*image, thumb_file, "Thumb::URI", uri, - "Thumb::MTime", c_mtime); + snprintf(c_width, 8, "%d", w); + snprintf(c_height, 8, "%d", h); + prefix = feh_thumbnail_get_prefix(); + if (prefix == NULL) { + gib_imlib_free_image_and_decache(im_temp); + return 0; + } + tmp_thumb_file = estrjoin("/", prefix, ".feh_thumbnail_XXXXXX", NULL); + free(prefix); + tmp_fd = mkstemp(tmp_thumb_file); + if (!feh_png_write_png_fd(*image, tmp_fd, "Thumb::URI", uri, + "Thumb::MTime", c_mtime, + "Thumb::Image::Width", c_width, + "Thumb::Image::Height", c_height)) { + rename(tmp_thumb_file, thumb_file); + } else { + unlink(tmp_thumb_file); + } + close(tmp_fd); + free(tmp_thumb_file); } gib_imlib_free_image_and_decache(im_temp); - return (1); + return 1; } - return (0); + return 0; } -int feh_thumbnail_get_generated(Imlib_Image * image, feh_file * file, char *thumb_file) +int feh_thumbnail_get_generated(Imlib_Image * image, feh_file * file, + char *thumb_file, int * orig_w, int * orig_h) { struct stat sb; char *c_mtime; + char *c_width, *c_height; time_t mtime = 0; gib_hash *hash; if (!stat(file->filename, &sb)) { hash = feh_png_read_comments(thumb_file); if (hash != NULL) { - c_mtime = (char *) gib_hash_get(hash, "Thumb::MTime"); + c_mtime = (char *) gib_hash_get(hash, "Thumb::MTime"); + c_width = (char *) gib_hash_get(hash, "Thumb::Image::Width"); + c_height = (char *) gib_hash_get(hash, "Thumb::Image::Height"); if (c_mtime != NULL) mtime = (time_t) strtol(c_mtime, NULL, 10); + if (c_width != NULL) + *orig_w = atoi(c_width); + if (c_height != NULL) + *orig_h = atoi(c_height); gib_hash_free_and_data(hash); } @@ -873,34 +783,165 @@ int feh_thumbnail_get_generated(Imlib_Image * image, feh_file * file, char *thum return (0); } +void feh_thumbnail_show_fullsize(feh_file *thumbfile) +{ + winwidget thumbwin = NULL; + gib_list *l; + + for (l = filelist; l; l = l->next) { + if (FEH_FILE(l->data) == thumbfile) { + break; + } + } + if (!l) { + eprintf("Cannot find %s in filelist, wtf", thumbfile->filename); + } + thumbwin = winwidget_get_first_window_of_type(WIN_TYPE_THUMBNAIL_VIEWER); + if (!thumbwin) { + thumbwin = winwidget_create_from_file( + l, + WIN_TYPE_THUMBNAIL_VIEWER); + if (thumbwin) + winwidget_show(thumbwin); + } else if (FEH_FILE(thumbwin->file->data) != thumbfile) { + thumbwin->file = l; +#ifdef HAVE_INOTIFY + winwidget_inotify_remove(thumbwin); +#endif + feh_reload_image(thumbwin, 1, 0); +#ifdef HAVE_INOTIFY + winwidget_inotify_add(thumbwin, thumbfile); +#endif + } +} + +void feh_thumbnail_select(winwidget winwid, feh_thumbnail *thumbnail) +{ + Imlib_Image origwin; + + if (thumbnail == td.selected) + return; + + if (thumbnail) { + origwin = winwid->im; + winwid->im = gib_imlib_clone_image(origwin); + gib_imlib_image_fill_rectangle(winwid->im, + thumbnail->x, thumbnail->y, thumbnail->w, + thumbnail->h, 50, 50, 255, 100); + gib_imlib_image_draw_rectangle(winwid->im, + thumbnail->x, thumbnail->y, thumbnail->w, + thumbnail->h, 255, 255, 255, 255); + gib_imlib_image_draw_rectangle(winwid->im, + thumbnail->x + 1, thumbnail->y + 1, + thumbnail->w - 2, thumbnail->h - 2, + 0, 0, 0, 255); + gib_imlib_image_draw_rectangle(winwid->im, + thumbnail->x + 2, thumbnail->y + 2, + thumbnail->w - 4, thumbnail->h - 4, + 255, 255, 255, 255); + winwidget_render_image(winwid, 0, 0); + gib_imlib_free_image_and_decache(winwid->im); + winwid->im = origwin; + } else + winwidget_render_image(winwid, 0, 0); + + td.selected = thumbnail; +} + +void feh_thumbnail_select_next(winwidget winwid, int jump) +{ + gib_list *l; + feh_thumbnail *thumb; + int len = 0, cur = 0, target = 0; + + for (l = thumbnails; l; l = l->next) { + thumb = FEH_THUMB(l->data); + if (thumb == td.selected) + cur = len; + len++; + } + + target = (cur + len - jump) % len; + + for (l = thumbnails; l; l = l->next) { + if (target-- == 0) { + feh_thumbnail_select(winwid, FEH_THUMB(l->data)); + } + } +} + +void feh_thumbnail_select_prev(winwidget winwid, int jump) +{ + gib_list *l; + feh_thumbnail *thumb; + int len = 0, cur = 0, target = 0; + + for (l = thumbnails; l; l = l->next) { + thumb = FEH_THUMB(l->data); + if (thumb == td.selected) + cur = len; + len++; + } + + target = (cur + jump) % len; + + for (l = thumbnails; l; l = l->next) { + if (target-- == 0) { + feh_thumbnail_select(winwid, FEH_THUMB(l->data)); + break; + } + } +} + +void feh_thumbnail_show_selected(void) +{ + if (td.selected && td.selected->file) + feh_thumbnail_show_fullsize(td.selected->file); +} + +feh_file* feh_thumbnail_get_selected_file(void) +{ + if (td.selected) + return td.selected->file; + return NULL; +} + int feh_thumbnail_setup_thumbnail_dir(void) { int status = 0; struct stat sb; - char *dir, *dir_thumbnails, *home; + char *dir, *p; - home = getenv("HOME"); - if (home != NULL) { - dir = estrjoin("/", home, ".thumbnails", td.cache_dir, NULL); + dir = feh_thumbnail_get_prefix(); + if (dir) { if (!stat(dir, &sb)) { if (S_ISDIR(sb.st_mode)) status = 1; else weprintf("%s should be a directory", dir); } else { - dir_thumbnails = estrjoin("/", home, ".thumbnails", NULL); + for (p = dir + 1; *p; p++) { + if (*p != '/') { + continue; + } - if (stat(dir_thumbnails, &sb) != 0) { - if (mkdir(dir_thumbnails, 0700) == -1) - weprintf("unable to create %s directory", dir_thumbnails); + *p = 0; + if (stat(dir, &sb) != 0) { + if (mkdir(dir, 0700) == -1) { + weprintf("unable to create directory %s", dir); + } + } + *p = '/'; } - if (mkdir(dir, 0700) == -1) - weprintf("unable to create %s directory", dir); - else - status = 1; + if (stat(dir, &sb) != 0) { + if (mkdir(dir, 0700) == -1) { + weprintf("unable to create directory %s", dir); + } + } } + free(dir); } return status; |