From 3d86a6c709366ab839c690185d295b6dea18836f Mon Sep 17 00:00:00 2001 From: Tobias Ellinghaus Date: Fri, 29 Apr 2016 13:10:30 +0200 Subject: [PATCH] plug-ins: Use GIMP's internal profile when loading EXR ... when it's appropriate. --- plug-ins/file-exr/file-exr.c | 19 ++----- plug-ins/file-exr/openexr-wrapper.cc | 74 +++++++++++++++++++++++----- plug-ins/file-exr/openexr-wrapper.h | 4 +- 3 files changed, 69 insertions(+), 28 deletions(-) diff --git a/plug-ins/file-exr/file-exr.c b/plug-ins/file-exr/file-exr.c index e9ab507fb4..135a3c0659 100644 --- a/plug-ins/file-exr/file-exr.c +++ b/plug-ins/file-exr/file-exr.c @@ -302,22 +302,13 @@ load_image (const gchar *filename, */ if (image_type == GIMP_RGB) { - cmsHPROFILE lcms_profile; + GimpColorProfile *profile; - lcms_profile = exr_loader_get_icc_profile (loader); - if (lcms_profile) + profile = exr_loader_get_profile (loader); + if (profile) { - GimpColorProfile *profile; - - profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, - NULL); - cmsCloseProfile (lcms_profile); - - if (profile) - { - gimp_image_set_color_profile (image, profile); - g_object_unref (profile); - } + gimp_image_set_color_profile (image, profile); + g_object_unref (profile); } } diff --git a/plug-ins/file-exr/openexr-wrapper.cc b/plug-ins/file-exr/openexr-wrapper.cc index 6637a19e7c..ef401f8daf 100644 --- a/plug-ins/file-exr/openexr-wrapper.cc +++ b/plug-ins/file-exr/openexr-wrapper.cc @@ -7,6 +7,7 @@ */ #include "libgimp/gimp.h" #include "libgimp/gimpui.h" +#include "libgimpcolor/gimpcolor.h" #include "openexr-wrapper.h" @@ -24,6 +25,15 @@ using namespace Imf; using namespace Imf::RgbaYca; using namespace Imath; +static bool XYZ_equal(cmsCIEXYZ *a, cmsCIEXYZ *b) +{ + static const double epsilon = 0.0001; + // Y is encoding the luminance, we normalize that for comparison + return fabs ((a->X / a->Y * b->Y) - b->X) < epsilon && + fabs ((a->Y / a->Y * b->Y) - b->Y) < epsilon && + fabs ((a->Z / a->Y * b->Y) - b->Z) < epsilon; +} + struct _EXRLoader { _EXRLoader(const char* filename) : @@ -172,12 +182,20 @@ struct _EXRLoader return has_alpha_ ? 1 : 0; } - cmsHPROFILE getICCProfile() const { + GimpColorProfile *getProfile() const { Chromaticities chromaticities; float whiteLuminance = 1.0; - cmsHPROFILE profile = NULL; + GimpColorProfile *linear_srgb_profile; + cmsHPROFILE linear_srgb_lcms; + GimpColorProfile *profile; + cmsHPROFILE lcms_profile; + + cmsCIEXYZ *gimp_r_XYZ, *gimp_g_XYZ, *gimp_b_XYZ, *gimp_w_XYZ; + cmsCIEXYZ exr_r_XYZ, exr_g_XYZ, exr_b_XYZ, exr_w_XYZ; + + // get the color information from the EXR if (hasChromaticities (file_.header ())) chromaticities = Imf::chromaticities (file_.header ()); else @@ -195,6 +213,7 @@ struct _EXRLoader std::cout << "hasWhiteLuminance: " << hasWhiteLuminance (file_.header ()) << std::endl; + std::cout << whiteLuminance << std::endl; std::cout << chromaticities.red << std::endl; std::cout << chromaticities.green << std::endl; std::cout << chromaticities.blue << std::endl; @@ -202,7 +221,6 @@ struct _EXRLoader std::cout << std::endl; #endif - // TODO: maybe factor this out into libgimpcolor/gimpcolorprofile.h ? cmsCIExyY whitePoint = { chromaticities.white.x, chromaticities.white.y, whiteLuminance }; @@ -216,29 +234,61 @@ struct _EXRLoader chromaticities.blue.y, whiteLuminance } }; + // get the primaries + wp from GIMP's internal linear sRGB profile + linear_srgb_profile = gimp_color_profile_new_rgb_srgb_linear (); + linear_srgb_lcms = gimp_color_profile_get_lcms_profile (linear_srgb_profile); + + gimp_r_XYZ = (cmsCIEXYZ *) cmsReadTag (linear_srgb_lcms, cmsSigRedColorantTag); + gimp_g_XYZ = (cmsCIEXYZ *) cmsReadTag (linear_srgb_lcms, cmsSigGreenColorantTag); + gimp_b_XYZ = (cmsCIEXYZ *) cmsReadTag (linear_srgb_lcms, cmsSigBlueColorantTag); + gimp_w_XYZ = (cmsCIEXYZ *) cmsReadTag (linear_srgb_lcms, cmsSigMediaWhitePointTag); + + cmsxyY2XYZ(&exr_r_XYZ, &CameraPrimaries.Red); + cmsxyY2XYZ(&exr_g_XYZ, &CameraPrimaries.Green); + cmsxyY2XYZ(&exr_b_XYZ, &CameraPrimaries.Blue); + cmsxyY2XYZ(&exr_w_XYZ, &whitePoint); + + // ... and check if the data stored in the EXR matches GIMP's internal profile + bool exr_is_linear_srgb = XYZ_equal (&exr_r_XYZ, gimp_r_XYZ) && + XYZ_equal (&exr_g_XYZ, gimp_g_XYZ) && + XYZ_equal (&exr_b_XYZ, gimp_b_XYZ) && + XYZ_equal (&exr_w_XYZ, gimp_w_XYZ); + + // using GIMP's linear sRGB profile allows to skip the conversion popup + if (exr_is_linear_srgb) + return linear_srgb_profile; + + // nope, it's something else. Clean up and build a new profile + g_object_unref (linear_srgb_profile); + + // TODO: maybe factor this out into libgimpcolor/gimpcolorprofile.h ? double Parameters[2] = { 1.0, 0.0 }; cmsToneCurve *Gamma[3]; Gamma[0] = Gamma[1] = Gamma[2] = cmsBuildParametricToneCurve(0, 1, Parameters); - profile = cmsCreateRGBProfile (&whitePoint, &CameraPrimaries, Gamma); + lcms_profile = cmsCreateRGBProfile (&whitePoint, &CameraPrimaries, Gamma); cmsFreeToneCurve (Gamma[0]); - if (profile == NULL) return NULL; + if (lcms_profile == NULL) return NULL; - cmsSetProfileVersion (profile, 2.1); +// cmsSetProfileVersion (lcms_profile, 2.1); cmsMLU *mlu0 = cmsMLUalloc (NULL, 1); cmsMLUsetASCII (mlu0, "en", "US", "(GIMP internal)"); cmsMLU *mlu1 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII (mlu1, "en", "US", "color profile from EXR chromaticities"); cmsMLU *mlu2 = cmsMLUalloc(NULL, 1); cmsMLUsetASCII (mlu2, "en", "US", "color profile from EXR chromaticities"); - cmsWriteTag (profile, cmsSigDeviceMfgDescTag, mlu0); - cmsWriteTag (profile, cmsSigDeviceModelDescTag, mlu1); - cmsWriteTag (profile, cmsSigProfileDescriptionTag, mlu2); + cmsWriteTag (lcms_profile, cmsSigDeviceMfgDescTag, mlu0); + cmsWriteTag (lcms_profile, cmsSigDeviceModelDescTag, mlu1); + cmsWriteTag (lcms_profile, cmsSigProfileDescriptionTag, mlu2); cmsMLUfree (mlu0); cmsMLUfree (mlu1); cmsMLUfree (mlu2); + profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, + NULL); + cmsCloseProfile (lcms_profile); + return profile; } @@ -385,10 +435,10 @@ exr_loader_has_alpha (EXRLoader *loader) return loader->hasAlpha(); } -cmsHPROFILE -exr_loader_get_icc_profile (EXRLoader *loader) +GimpColorProfile * +exr_loader_get_profile (EXRLoader *loader) { - return loader->getICCProfile (); + return loader->getProfile (); } gchar * diff --git a/plug-ins/file-exr/openexr-wrapper.h b/plug-ins/file-exr/openexr-wrapper.h index fcb498435d..f2cf3211bc 100644 --- a/plug-ins/file-exr/openexr-wrapper.h +++ b/plug-ins/file-exr/openexr-wrapper.h @@ -50,8 +50,8 @@ exr_loader_get_image_type (EXRLoader *loader); int exr_loader_has_alpha (EXRLoader *loader); -cmsHPROFILE -exr_loader_get_icc_profile (EXRLoader *loader); +GimpColorProfile * +exr_loader_get_profile (EXRLoader *loader); gchar * exr_loader_get_comment (EXRLoader *loader);