diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/eom-metadata-reader-png.c | 45 |
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; |