[gimp/wip/Jehan/issue-3265-png-gama-chunk: 2/2] Issue #3265: PNG gAMA chunk is silently ignored.
- From: Jehan <jehanp src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/wip/Jehan/issue-3265-png-gama-chunk: 2/2] Issue #3265: PNG gAMA chunk is silently ignored.
- Date: Sun, 17 Jan 2021 19:33:41 +0000 (UTC)
commit 01c7b7828a47b1cf498606e05fc4be7a80b85be6
Author: Jehan <jehan girinstud io>
Date: Sun Jan 17 15:28:08 2021 +0100
Issue #3265: PNG gAMA chunk is silently ignored.
PNG has support for profiles, which is the state-of-the-art way to
handle color management nowadays. But it also had some very basic color
management based on a gAMA chunk (for the gamma) and a cHRM chunk
(primary chromaticities).
We don't have a core concept with just these and don't want to walk
backward anyway, but we can easily make basic RGB profiles from these.
This is what this commit is about. It generates profiles at import which
were not actually inside the image, but only represented by these 2 PNG
chunks. What gives it away is that GIMP will propose to convert/keep the
profile at start (unless configured otherwise, as any profile), and the
profile name will specify it is a profile generated from PNG chunks'
values. One can even discard the profile later (if you didn't convert),
so it gives a solution if somehow these metadata were not proper.
plug-ins/common/Makefile.am | 1 +
plug-ins/common/file-png.c | 106 +++++++++++++++++++++++++++++++++++++++++
plug-ins/common/meson.build | 2 +-
plug-ins/common/plugin-defs.pl | 2 +-
4 files changed, 109 insertions(+), 2 deletions(-)
---
diff --git a/plug-ins/common/Makefile.am b/plug-ins/common/Makefile.am
index d9d30be9ca..05964bae82 100644
--- a/plug-ins/common/Makefile.am
+++ b/plug-ins/common/Makefile.am
@@ -955,6 +955,7 @@ file_png_LDADD = \
$(GTK_LIBS) \
$(GEGL_LIBS) \
$(PNG_LIBS) \
+ $(LCMS_LIBS) \
$(RT_LIBS) \
$(INTLLIBS) \
$(file_png_RC)
diff --git a/plug-ins/common/file-png.c b/plug-ins/common/file-png.c
index 2f3a102a51..b08178e483 100644
--- a/plug-ins/common/file-png.c
+++ b/plug-ins/common/file-png.c
@@ -27,6 +27,7 @@
#include <errno.h>
#include <glib/gstdio.h>
+#include "lcms2.h"
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
@@ -560,6 +561,21 @@ load_color_profile (png_structp pp,
return profile;
}
+/* Copied from src/cmsvirt.c in Little-CMS. */
+static cmsToneCurve *
+Build_sRGBGamma (cmsContext ContextID)
+{
+ cmsFloat64Number Parameters[5];
+
+ Parameters[0] = 2.4;
+ Parameters[1] = 1. / 1.055;
+ Parameters[2] = 0.055 / 1.055;
+ Parameters[3] = 1. / 12.92;
+ Parameters[4] = 0.04045;
+
+ return cmsBuildParametricToneCurve (ContextID, 4, Parameters);
+}
+
/*
* 'load_image()' - Load a PNG image into a new image window.
*/
@@ -676,6 +692,96 @@ load_image (GFile *file,
*/
profile = load_color_profile (pp, info, &profile_name);
+ if (! profile && ! png_get_valid (pp, info, PNG_INFO_sRGB) &&
+ (png_get_valid (pp, info, PNG_INFO_gAMA) ||
+ png_get_valid (pp, info, PNG_INFO_cHRM)))
+ {
+ /* This is kind of a special case for PNG. If an image has no
+ * profile, and the sRGB chunk is not set, and either gAMA or cHRM
+ * (or ideally both) are set, then we generate a profile from
+ * these data on import. See #3265.
+ */
+ cmsToneCurve *gamma_curve[3];
+ cmsCIExyY whitepoint;
+ cmsCIExyYTRIPLE primaries;
+ cmsHPROFILE cms_profile = NULL;
+ gdouble gamma = 1.0 / DEFAULT_GAMMA;
+
+ if (png_get_valid (pp, info, PNG_INFO_gAMA) &&
+ png_get_gAMA (pp, info, &gamma) == PNG_INFO_gAMA)
+ {
+ gamma_curve[0] = gamma_curve[1] = gamma_curve[2] = cmsBuildGamma (NULL, 1.0 / gamma);
+ }
+ else
+ {
+ /* Use the sRGB gamma curve. */
+ gamma_curve[0] = gamma_curve[1] = gamma_curve[2] = Build_sRGBGamma (NULL);
+ }
+
+ if (png_get_valid (pp, info, PNG_INFO_cHRM) &&
+ png_get_cHRM (pp, info, &whitepoint.x, &whitepoint.y,
+ &primaries.Red.x, &primaries.Red.y,
+ &primaries.Green.x, &primaries.Green.y,
+ &primaries.Blue.x, &primaries.Blue.y) == PNG_INFO_cHRM)
+ {
+ whitepoint.Y = primaries.Red.Y = primaries.Green.Y = primaries.Blue.Y = 1.0;
+ }
+ else
+ {
+ /* Rec709 primaries and D65 whitepoint as copied from
+ * cmsCreate_sRGBProfileTHR() in Little-CMS.
+ */
+ cmsCIExyY d65_whitepoint = { 0.3127, 0.3290, 1.0 };
+ cmsCIExyYTRIPLE rec709_primaries =
+ {
+ {0.6400, 0.3300, 1.0},
+ {0.3000, 0.6000, 1.0},
+ {0.1500, 0.0600, 1.0}
+ };
+
+ memcpy (&whitepoint, &d65_whitepoint, sizeof whitepoint);
+ memcpy (&primaries, &rec709_primaries, sizeof primaries);
+ }
+ cms_profile = cmsCreateRGBProfile (&whitepoint, &primaries, gamma_curve);
+ cmsFreeToneCurve (gamma_curve[0]);
+ g_warn_if_fail (cms_profile != NULL);
+
+ if (cms_profile != NULL)
+ {
+ /* Customize the profile description to show it is generated
+ * from PNG metadata.
+ */
+ gchar *profile_desc;
+ cmsMLU *description_mlu;
+ cmsContext context_id = cmsGetProfileContextID (cms_profile);
+
+ /* Note that I am not trying to localize these strings on purpose
+ * because cmsMLUsetASCII() expects ASCII. Maybe we should move to
+ * using cmsMLUsetWide() if we want the generated profile
+ * descriptions to be localized. XXX
+ */
+ if ((png_get_valid (pp, info, PNG_INFO_gAMA) && png_get_valid (pp, info, PNG_INFO_cHRM)))
+ profile_desc = g_strdup_printf ("Generated RGB profile from PNG's gAMA (gamma %.4f) and cHRM
chunks",
+ 1.0 / gamma);
+ else if (png_get_valid (pp, info, PNG_INFO_gAMA))
+ profile_desc = g_strdup_printf ("Generated RGB profile from PNG's gAMA chunk (gamma %.4f)",
+ 1.0 / gamma);
+ else
+ profile_desc = g_strdup_printf ("Generated RGB profile from PNG's cHRM chunk");
+
+ description_mlu = cmsMLUalloc (context_id, 1);
+
+ cmsMLUsetASCII (description_mlu, "en", "US", profile_desc);
+ cmsWriteTag (cms_profile, cmsSigProfileDescriptionTag, description_mlu);
+
+ profile = gimp_color_profile_new_from_lcms_profile (cms_profile, NULL);
+
+ g_free (profile_desc);
+ cmsMLUfree (description_mlu);
+ cmsCloseProfile (cms_profile);
+ }
+ }
+
if (profile)
{
*profile_loaded = TRUE;
diff --git a/plug-ins/common/meson.build b/plug-ins/common/meson.build
index f459aa9f92..74693a589c 100644
--- a/plug-ins/common/meson.build
+++ b/plug-ins/common/meson.build
@@ -47,7 +47,7 @@ common_plugins_list = [
},
{ 'name': 'file-pix', },
{ 'name': 'file-png',
- 'deps': [ gtk3, gegl, libpng, ],
+ 'deps': [ gtk3, gegl, libpng, lcms ],
},
{ 'name': 'file-pnm', },
{ 'name': 'file-psp',
diff --git a/plug-ins/common/plugin-defs.pl b/plug-ins/common/plugin-defs.pl
index 49fbc8824c..f1999a32df 100644
--- a/plug-ins/common/plugin-defs.pl
+++ b/plug-ins/common/plugin-defs.pl
@@ -36,7 +36,7 @@
'file-pat' => { ui => 1, gegl => 1 },
'file-pcx' => { ui => 1, gegl => 1 },
'file-pix' => { ui => 1, gegl => 1 },
- 'file-png' => { ui => 1, gegl => 1, libs => 'PNG_LIBS', cflags => 'PNG_CFLAGS' },
+ 'file-png' => { ui => 1, gegl => 0, libdep => 'LCMS', libs => 'PNG_LIBS', cflags => 'PNG_CFLAGS' },
'file-pnm' => { ui => 1, gegl => 1 },
'file-pdf-load' => { ui => 1, gegl => 1, libs => 'POPPLER_LIBS', cflags => 'POPPLER_CFLAGS' },
'file-pdf-save' => { ui => 1, gegl => 1, optional => 1, libs => 'CAIRO_PDF_LIBS', cflags =>
'CAIRO_PDF_CFLAGS' },
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]