summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/eom-metadata-reader-png.c45
1 files changed, 40 insertions, 5 deletions
diff --git a/src/eom-metadata-reader-png.c b/src/eom-metadata-reader-png.c
index ebf2ddf..eadf036 100644
--- a/src/eom-metadata-reader-png.c
+++ b/src/eom-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 @@ eom_metadata_reader_png_get_xmp_data (EomMetadataReaderPng *emr )
* A maximum output buffer of 5MB should be enough. */
#define EOM_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
eom_metadata_reader_png_get_icc_profile (EomMetadataReaderPng *emr)
{
@@ -600,11 +626,20 @@ eom_metadata_reader_png_get_icc_profile (EomMetadataReaderPng *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]);
+ eom_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)) {
+ eom_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;