Generate sRGB thumbnails for images with embedded color profile data
authorDaniel Vogelbacher <daniel@chaospixel.com>
Mon, 26 Apr 2021 15:59:04 +0000 (17:59 +0200)
committerDaniel Vogelbacher <daniel@chaospixel.com>
Mon, 26 Apr 2021 15:59:04 +0000 (17:59 +0200)
Images with color profiles other than sRGB or AdobeRGB may look
too bright/dark as thumbnails, because Geeqie ignores color profile
information during thumbnail generation.

This patch adds color profile correction for thumbnails if the image
contains EXIF data and provides an embedded color profile or EXIF
color profile identifiers.

src/thumb.c
src/thumb_standard.c
src/thumb_standard.h

index 3e2e9fe..65b0387 100644 (file)
@@ -145,6 +145,11 @@ static void thumb_loader_done_cb(ImageLoader *il, gpointer data)
                return;
                }
 
+       if(!tl->cache_hit)
+               {
+                       // apply color correction, if required
+                       thumb_loader_std_calibrate_pixbuf(tl->fd, pixbuf);
+               }
 
        if (!tl->cache_hit && options->image.exif_rotate_enable)
                {
index 43ab9fe..144ae23 100644 (file)
@@ -30,6 +30,7 @@
 #include "filedata.h"
 #include "exif.h"
 #include "metadata.h"
+#include "color-man.h"
 
 
 /**
@@ -386,6 +387,99 @@ static void thumb_loader_std_set_fallback(ThumbLoaderStd *tl)
        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;
+
+       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;
@@ -499,6 +593,9 @@ static GdkPixbuf *thumb_loader_std_finish(ThumbLoaderStd *tl, GdkPixbuf *pixbuf,
                        }
                }
 
+       // 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);
 
index 418f723..5d7b8ae 100644 (file)
@@ -85,6 +85,7 @@ void thumb_loader_std_free(ThumbLoaderStd *tl);
 
 GdkPixbuf *thumb_loader_std_get_pixbuf(ThumbLoaderStd *tl);
 
+void thumb_loader_std_calibrate_pixbuf(FileData *fd, GdkPixbuf *pixbuf);
 
 /**
  * \headerfile thumb_loader_std_thumb_file_validate