[eog] EogMetadataReaderPng: Use built-in SRGB profile for matching cHRM/gAMA



commit 9589430cda356ba1dd0d170b88ba8b3a77881f3d
Author: Felix Riemann <friemann gnome org>
Date:   Fri May 3 15:53:25 2019 +0200

    EogMetadataReaderPng: Use built-in SRGB profile for matching cHRM/gAMA
    
    The values used for sRGB in cHRM and gAMA chunks do not compute to a
    profile that exactly matches the built-in profile. Catch this case and
    use the built-in profile instead to avoid color differences.
    
    Fixes #51.

 src/eog-metadata-reader-png.c | 45 ++++++++++++++++++++++++++++++++++++++-----
 1 file changed, 40 insertions(+), 5 deletions(-)
---
diff --git a/src/eog-metadata-reader-png.c b/src/eog-metadata-reader-png.c
index deadab5f..6d96f4ca 100644
--- a/src/eog-metadata-reader-png.c
+++ b/src/eog-metadata-reader-png.c
@@ -25,6 +25,7 @@
 #include <config.h>
 #endif
 
+#include <math.h>
 #include <string.h>
 #include <zlib.h>
 
@@ -489,6 +490,31 @@ eog_metadata_reader_png_get_xmp_data (EogMetadataReaderPng *emr )
  * A maximum output buffer of 5MB should be enough. */
 #define EOG_ICC_INFLATE_BUFFER_LIMIT (1024*1024*5)
 
+/* Apparently an sRGB profile saved in cHRM and gAMA chunks does not compute
+ * a profile that exactly matches the built-in sRGB profile and thus could
+ * cause a slight color deviation. Try catching this case to allow fallback
+ * to the built-in profile instead.
+ */
+static gboolean
+_chrm_matches_srgb(const cmsCIExyY       *whitepoint,
+                  const cmsCIExyYTRIPLE *primaries,
+                        gdouble          gammaValue)
+{
+       /* PNGs gAMA value for 2.2 is only accurate to the 4th decimal point */
+#define DOUBLE_EQUAL_MAX_DIFF 1e-4
+#define DOUBLE_EQUAL(a,b) (fabs (a - b) < DOUBLE_EQUAL_MAX_DIFF)
+
+       return (DOUBLE_EQUAL(gammaValue, 2.2)
+               && DOUBLE_EQUAL(whitepoint->x, 0.3127)
+               && DOUBLE_EQUAL(whitepoint->y, 0.329)
+               && DOUBLE_EQUAL(primaries->Red.x, 0.64)
+               && DOUBLE_EQUAL(primaries->Red.y, 0.33)
+               && DOUBLE_EQUAL(primaries->Green.x, 0.3)
+               && DOUBLE_EQUAL(primaries->Green.y, 0.6)
+               && DOUBLE_EQUAL(primaries->Blue.x, 0.15)
+               && DOUBLE_EQUAL(primaries->Blue.y, 0.06));
+}
+
 static gpointer
 eog_metadata_reader_png_get_icc_profile (EogMetadataReaderPng *emr)
 {
@@ -600,11 +626,20 @@ eog_metadata_reader_png_get_icc_profile (EogMetadataReaderPng *emr)
                whitepoint.Y = primaries.Red.Y = primaries.Green.Y = primaries.Blue.Y = 1.0;
 
                gammaValue = (double) 1.0/EXTRACT_DOUBLE_UINT_BLOCK_OFFSET (priv->gAMA_chunk, 0, 100000);
-               gamma[0] = gamma[1] = gamma[2] = cmsBuildGamma (NULL, gammaValue);
-
-               profile = cmsCreateRGBProfile (&whitepoint, &primaries, gamma);
-
-               cmsFreeToneCurve(gamma[0]);
+               eog_debug_message (DEBUG_LCMS, "Gamma %.5lf", gammaValue);
+
+               /* Catch SRGB in cHRM/gAMA chunks and use accurate built-in
+                * profile instead of computing one that "gets close". */
+               if(_chrm_matches_srgb (&whitepoint, &primaries, gammaValue)) {
+                       eog_debug_message (DEBUG_LCMS, "gAMA and cHRM match sRGB");
+                       profile = cmsCreate_sRGBProfile ();
+               } else {
+                       gamma[0] = gamma[1] = gamma[2] =
+                               cmsBuildGamma (NULL, gammaValue);
+                       profile = cmsCreateRGBProfile (&whitepoint, &primaries,
+                                                      gamma);
+                       cmsFreeToneCurve(gamma[0]);
+               }
        }
 
        return profile;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]