summaryrefslogtreecommitdiff
path: root/src/thumbnail.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/thumbnail.c')
-rw-r--r--src/thumbnail.c197
1 files changed, 134 insertions, 63 deletions
diff --git a/src/thumbnail.c b/src/thumbnail.c
index c806ce4..70af5e0 100644
--- a/src/thumbnail.c
+++ b/src/thumbnail.c
@@ -1,7 +1,7 @@
/* thumbnail.c
Copyright (C) 1999-2003 Tom Gilbert.
-Copyright (C) 2010-2011 Daniel Friesel.
+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
@@ -71,7 +71,6 @@ void init_thumbnail_mode(void)
gib_list *l, *last = NULL;
int lineno;
int index_image_width, index_image_height;
- char *s;
unsigned int thumb_counter = 0;
gib_list *line, *lines;
@@ -92,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)
@@ -144,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,
@@ -165,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, 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) {
@@ -187,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");
@@ -380,11 +390,13 @@ 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);
+ 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_imlib_print_load_error(output_buf, td.im_main, err);
+ feh_print_load_error(output_buf, td.im_main, err, LOAD_ERROR_IMLIB);
}
else if (opt.verbose) {
int tw, th;
@@ -403,6 +415,7 @@ void init_thumbnail_mode(void)
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;
@@ -411,7 +424,6 @@ void init_thumbnail_mode(void)
}
- free(s);
return;
}
@@ -563,6 +575,12 @@ int feh_thumbnail_get_thumbnail(Imlib_Image * image, feh_file * file,
if (td.cache_thumbnails) {
uri = feh_thumbnail_get_name_uri(file->filename);
thumb_file = feh_thumbnail_get_name(uri);
+
+ 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);
@@ -579,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;
}
@@ -604,9 +640,9 @@ char *feh_thumbnail_get_name_uri(char *name)
/* FIXME: what happens with http, https, and ftp? MTime etc */
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)
@@ -636,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]);
}
@@ -652,6 +688,8 @@ int feh_thumbnail_generate(Imlib_Image * image, feh_file * file,
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) {
*orig_w = w = gib_imlib_image_get_width(im_temp);
@@ -665,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,
@@ -675,18 +720,32 @@ int feh_thumbnail_generate(Imlib_Image * image, feh_file * file,
sprintf(c_mtime, "%d", (int)sb.st_mtime);
snprintf(c_width, 8, "%d", w);
snprintf(c_height, 8, "%d", h);
- feh_png_write_png(*image, thumb_file, "Thumb::URI", uri,
+ 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);
+ "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,
@@ -727,25 +786,32 @@ int feh_thumbnail_get_generated(Imlib_Image * image, feh_file * file,
void feh_thumbnail_show_fullsize(feh_file *thumbfile)
{
winwidget thumbwin = NULL;
- char *s;
+ gib_list *l;
- if (!opt.thumb_title)
- s = thumbfile->name;
- else
- s = feh_printf(opt.thumb_title, thumbfile, NULL);
-
+ 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(
- gib_list_add_front(NULL, thumbfile),
- s, WIN_TYPE_THUMBNAIL_VIEWER);
+ l,
+ WIN_TYPE_THUMBNAIL_VIEWER);
if (thumbwin)
winwidget_show(thumbwin);
} else if (FEH_FILE(thumbwin->file->data) != thumbfile) {
- free(thumbwin->file);
- thumbwin->file = gib_list_add_front(NULL, thumbfile);
- winwidget_rename(thumbwin, s);
- feh_reload_image(thumbwin, 1, 1);
+ 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
}
}
@@ -827,13 +893,13 @@ void feh_thumbnail_select_prev(winwidget winwid, int jump)
}
}
-void feh_thumbnail_show_selected()
+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()
+feh_file* feh_thumbnail_get_selected_file(void)
{
if (td.selected)
return td.selected->file;
@@ -844,31 +910,36 @@ 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 directory %s", dir_thumbnails);
+ *p = 0;
+ if (stat(dir, &sb) != 0) {
+ if (mkdir(dir, 0700) == -1) {
+ weprintf("unable to create directory %s", dir);
+ }
+ }
+ *p = '/';
}
- free(dir_thumbnails);
-
- if (mkdir(dir, 0700) == -1)
- weprintf("unable to create directory %s", dir);
- else
- status = 1;
+ if (stat(dir, &sb) != 0) {
+ if (mkdir(dir, 0700) == -1) {
+ weprintf("unable to create directory %s", dir);
+ }
+ }
}
free(dir);
}