plug-ins: Use GIMP's internal profile when loading EXR

... when it's appropriate.
This commit is contained in:
Tobias Ellinghaus 2016-04-29 13:10:30 +02:00
parent 1c4fc5620f
commit 3d86a6c709
No known key found for this signature in database
GPG Key ID: 98D42E5ACB5448E8
3 changed files with 69 additions and 28 deletions

View File

@ -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);
}
}

View File

@ -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 *

View File

@ -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);