/*
- * Geeqie
- * (C) 2006 John Ellis
- * Copyright (C) 2008 - 2010 The Geeqie Team
+ * Copyright (C) 2006 John Ellis
+ * Copyright (C) 2008 - 2016 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!
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-
#include "main.h"
#include "thumb_standard.h"
+#include "cache.h"
#include "image-load.h"
#include "md5-util.h"
#include "pixbuf_util.h"
#include "filedata.h"
#include "exif.h"
#include "metadata.h"
+#include "color-man.h"
-/*
+/**
+ * @file
+ *
* This thumbnail caching implementation attempts to conform
* to the Thumbnail Managing Standard proposed on freedesktop.org
- * The standard is documented here:
- * http://triq.net/~jens/thumbnail-spec/index.html
+ * The standard is documented here: \n
+ * http://triq.net/~jens/thumbnail-spec/index.html \n
* (why isn't it actually hosted on freedesktop.org?)
*
* This code attempts to conform to version 0.7.0 of the standard.
*
* Notes:
* > Validation of the thumb's embedded uri is a simple strcmp between our
- * version of the escaped uri and the thumb's escaped uri. But not all uri
- * escape functions escape the same set of chars, comparing the unescaped
- * versions may be more accurate.
+ * > version of the escaped uri and the thumb's escaped uri. But not all uri
+ * > escape functions escape the same set of chars, comparing the unescaped
+ * > versions may be more accurate. \n
* > Only Thumb::URI and Thumb::MTime are stored in a thumb at this time.
* Storing the Size, Width, Height should probably be implemented.
*/
}
else
{
- result = g_build_filename(homedir(), THUMB_FOLDER_GLOBAL, cache_subfolder, name, NULL);
+ result = g_build_filename(get_thumbnails_standard_cache_dir(),
+ cache_subfolder, name, NULL);
}
g_free(name);
mark_uri = (tl->cache_local) ? tl->local_uri :tl->thumb_uri;
mark_app = g_strdup_printf("%s %s", GQ_APPNAME, VERSION);
- mark_mtime = g_strdup_printf("%lu", tl->source_mtime);
-
+ mark_mtime = g_strdup_printf("%llu", (unsigned long long)tl->source_mtime);
pathl = path_from_utf8(tmp_path);
success = gdk_pixbuf_save(pixbuf, pathl, "png", NULL,
THUMB_MARKER_URI, mark_uri,
tl->fd->thumb_pixbuf = pixbuf_fallback(tl->fd, tl->requested_width, tl->requested_height);
}
+
+void thumb_loader_std_calibrate_pixbuf(FileData *fd, GdkPixbuf *pixbuf) {
+ ColorMan *cm = NULL;
+ ExifData *exif = NULL;
+ gint color_profile_from_image = COLOR_PROFILE_NONE;
+ ColorManProfileType input_type = COLOR_PROFILE_MEM;
+ ColorManProfileType screen_type;
+ const gchar *input_file = NULL;
+ guchar *profile = NULL;
+ guint profile_len;
+ gint sw, sh;
+
+ if (!options->thumbnails.use_color_management)
+ {
+ return;
+ }
+
+ sw = gdk_pixbuf_get_width(pixbuf);
+ sh = gdk_pixbuf_get_height(pixbuf);
+
+ exif = exif_read_fd(fd);
+
+ if (exif)
+ {
+ profile = exif_get_color_profile(exif, &profile_len);
+ if (profile)
+ {
+ DEBUG_1("Found embedded color profile");
+ color_profile_from_image = COLOR_PROFILE_MEM;
+ }
+ else
+ {
+ gchar *interop_index = exif_get_data_as_text(exif, "Exif.Iop.InteroperabilityIndex");
+
+ if (interop_index)
+ {
+ /* Exif 2.21 specification */
+ if (!strcmp(interop_index, "R98"))
+ {
+ color_profile_from_image = COLOR_PROFILE_SRGB;
+ DEBUG_1("Found EXIF 2.21 ColorSpace of sRGB");
+ }
+ else if (!strcmp(interop_index, "R03"))
+ {
+ color_profile_from_image = COLOR_PROFILE_ADOBERGB;
+ DEBUG_1("Found EXIF 2.21 ColorSpace of AdobeRGB");
+ }
+ g_free(interop_index);
+ }
+ else
+ {
+ gint cs;
+
+ /* ColorSpace == 1 specifies sRGB per EXIF 2.2 */
+ if (!exif_get_integer(exif, "Exif.Photo.ColorSpace", &cs)) cs = 0;
+ if (cs == 1)
+ {
+ color_profile_from_image = COLOR_PROFILE_SRGB;
+ DEBUG_1("Found EXIF 2.2 ColorSpace of sRGB");
+ }
+ else if (cs == 2)
+ {
+ /* non-standard way of specifying AdobeRGB (used by some software) */
+ color_profile_from_image = COLOR_PROFILE_ADOBERGB;
+ DEBUG_1("Found EXIF 2.2 ColorSpace of AdobeRGB");
+ }
+ }
+ }
+
+ if(color_profile_from_image != COLOR_PROFILE_NONE)
+ {
+ // transform image, we always use sRGB as target for thumbnails
+ screen_type = COLOR_PROFILE_SRGB;
+
+ if (profile)
+ {
+ cm = color_man_new_embedded(NULL, pixbuf,
+ profile, profile_len,
+ screen_type, NULL, NULL, 0);
+ g_free(profile);
+ }
+ else
+ {
+ cm = color_man_new(NULL, pixbuf,
+ input_type, input_file,
+ screen_type, NULL, NULL, 0);
+ }
+
+ if(cm) {
+ color_man_correct_region(cm, cm->pixbuf, 0, 0, sw, sh);
+ g_free(cm);
+ }
+
+ }
+ exif_free_fd(fd, exif);
+ }
+}
+
static GdkPixbuf *thumb_loader_std_finish(ThumbLoaderStd *tl, GdkPixbuf *pixbuf, gboolean shrunk)
{
GdkPixbuf *pixbuf_thumb = NULL;
{
tl->fd->exif_orientation = metadata_read_int(tl->fd, ORIENTATION_KEY, EXIF_ORIENTATION_TOP_LEFT);
}
-
+
if (tl->fd->exif_orientation != EXIF_ORIENTATION_TOP_LEFT)
{
rotated = pixbuf_apply_orientation(pixbuf, tl->fd->exif_orientation);
/* do not save the thumbnail if the source file has changed meanwhile -
the thumbnail is most probably broken */
- if (stat_utf8(tl->fd->path, &st) &&
+ if (stat_utf8(tl->fd->path, &st) &&
tl->source_mtime == st.st_mtime &&
tl->source_size == st.st_size)
{
}
}
+ // apply color correction, if required
+ thumb_loader_std_calibrate_pixbuf(tl->fd, result);
+
if (pixbuf_thumb) g_object_unref(pixbuf_thumb);
if (rotated) g_object_unref(rotated);
thumb_loader_std_done_cb(il, data);
return;
}
-
+
DEBUG_1("thumb image error: %s", tl->fd->path);
DEBUG_1(" from: %s", image_loader_get_fd(tl->il)->path);
if (thumb_loader_std_next_source(tl, TRUE)) return;
thumb_loader_std_set_fallback(tl);
-
+
if (tl->func_error) tl->func_error(tl, tl->data);
}
tl->fd = file_data_ref(fd);
- if (!stat_utf8(fd->path, &st))
+ if (!stat_utf8(fd->path, &st) || (tl->fd->format_class != FORMAT_CLASS_IMAGE && tl->fd->format_class != FORMAT_CLASS_RAWIMAGE && tl->fd->format_class != FORMAT_CLASS_VIDEO && tl->fd->format_class != FORMAT_CLASS_COLLECTION && tl->fd->format_class != FORMAT_CLASS_DOCUMENT && !options->file_filter.disable))
{
thumb_loader_std_set_fallback(tl);
return FALSE;
tl->source_size = st.st_size;
tl->source_mode = st.st_mode;
- if (!thumb_cache) thumb_cache = g_build_filename(homedir(), THUMB_FOLDER_GLOBAL, NULL);
+ if (!thumb_cache)
+ {
+ thumb_cache = g_strdup(get_thumbnails_standard_cache_dir());
+ }
+
if (strncmp(tl->fd->path, thumb_cache, strlen(thumb_cache)) != 0)
{
gchar *pathl;
GdkPixbuf *pixbuf;
gboolean valid = FALSE;
- /* get the original thumbnail pixbuf (unrotated, with original options)
+ /* get the original thumbnail pixbuf (unrotated, with original options)
this is called from image_loader done callback, so tv->tl->il must exist*/
- pixbuf = image_loader_get_pixbuf(tv->tl->il);
+ pixbuf = image_loader_get_pixbuf(tv->tl->il);
if (pixbuf)
{
const gchar *uri;
TMaintMove *tm = data;
GdkPixbuf *pixbuf;
- /* get the original thumbnail pixbuf (unrotated, with original options)
+ /* get the original thumbnail pixbuf (unrotated, with original options)
this is called from image_loader done callback, so tm->tl->il must exist*/
- pixbuf = image_loader_get_pixbuf(tm->tl->il);
+ pixbuf = image_loader_get_pixbuf(tm->tl->il);
if (pixbuf)
{
const gchar *uri;
*
* The thumbnails are processed when the app is idle. If the app
* exits early well too bad - they can simply be regenerated from scratch.
- *
- * This does not manage local thumbnails (fixme ?)
+ */
+/** @FIXME This does not manage local thumbnails (fixme ?)
*/
void thumb_std_maint_moved(const gchar *source, const gchar *dest)
{