[gegl] operations: Add gegl:lcms-from-profile
- From: Michael Henning <mhenning src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gegl] operations: Add gegl:lcms-from-profile
- Date: Fri, 5 Jul 2013 20:25:12 +0000 (UTC)
commit 8641c1708b8d2efedfa2346d15fad423e6ee0b93
Author: Michael Henning <drawoc darkrefraction com>
Date: Sun Jun 23 11:29:05 2013 -0400
operations: Add gegl:lcms-from-profile
configure.ac | 35 ++---
operations/external/Makefile.am | 7 +
operations/external/lcms-from-profile.c | 237 +++++++++++++++++++++++++++++++
3 files changed, 258 insertions(+), 21 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 474e151..ad0934e 100644
--- a/configure.ac
+++ b/configure.ac
@@ -44,6 +44,7 @@ m4_define([introspection_required_version], [1.32.0])
m4_define([glib_required_version], [2.32.3])
m4_define([graphviz_required_version], [0.0.0])
m4_define([jasper_required_version], [1.900.1])
+m4_define([lcms_required_version], [2.2])
m4_define([lensfun_required_version], [0.2.5])
m4_define([librsvg_required_version], [2.14.0])
m4_define([lua_required_version], [5.1.0])
@@ -911,31 +912,23 @@ fi
AM_CONDITIONAL(HAVE_V4L, test "$have_v4l" = "yes")
-
-
################
# Check for lcms
################
-
-#AC_ARG_WITH(liblcms, [ --without-lcms build without CMS support])
-#
-#have_lcms="no"
-#if test x$with_liblcms != xno; then
-# AC_CHECK_LIB(lcms, cmsCreateProofingTransform, [
-# AC_CHECK_HEADER(lcms.h,
-# have_lcms=yes
-# LCMS_LIBS="-llcms", [
-# AC_CHECK_HEADER(lcms/lcms.h,
-# have_lcms=yes
-# AC_DEFINE(HAVE_LCMS_LCMS_H, 1,
-# [Define to 1 if the lcms header must be included as lcms/lcms.h])
-# LCMS_LIBS="-llcms")])
-# ])
-#fi
-#
-#AM_CONDITIONAL(HAVE_LCMS, test "x$have_lcms" = "xyes")
-#AC_SUBST(LCMS_LIBS)
+AC_ARG_WITH(lcms, [ --without-lcms build without lcms support])
+
+have_lcms="no (lcms support disabled)"
+if test "x$with_lcms" != xno; then
+ have_lcms=yes
+ PKG_CHECK_MODULES(LCMS, lcms2 >= lcms_required_version,
+ AC_DEFINE(HAVE_LCMS, 1, [Define to 1 if lcms is available])
+ LCMS='lcms$(EXEEXT)',
+ have_lcms="no (lcms not found or unusable)")
+fi
+
+AC_SUBST(LCMS)
+AM_CONDITIONAL(HAVE_LCMS, test "x$have_lcms" = xyes)
####################
# Check for libspiro
diff --git a/operations/external/Makefile.am b/operations/external/Makefile.am
index b29df12..b9e7ba2 100644
--- a/operations/external/Makefile.am
+++ b/operations/external/Makefile.am
@@ -118,6 +118,13 @@ matting_levin_la_LIBADD = $(op_libs) $(UMFPACK_LIBS)
matting_levin_la_CFLAGS = $(AM_CFLAGS)
endif
+if HAVE_LCMS
+ops += lcms-from-profile.la
+lcms_from_profile_la_SOURCES = lcms-from-profile.c
+lcms_from_profile_la_LIBADD = $(op_libs) $(LCMS_LIBS)
+lcms_from_profile_la_CFLAGS = $(AM_CFLAGS)
+endif
+
# No dependencies
ops += ppm-load.la ppm-save.la
ppm_load_la_SOURCES = ppm-load.c
diff --git a/operations/external/lcms-from-profile.c b/operations/external/lcms-from-profile.c
new file mode 100644
index 0000000..f52909d
--- /dev/null
+++ b/operations/external/lcms-from-profile.c
@@ -0,0 +1,237 @@
+/* This file is an image processing operation for GEGL
+ *
+ * GEGL is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * GEGL is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with GEGL; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Copyright 2013 Michael Henning <drawoc darkrefraction com>
+ */
+
+#include "config.h"
+#include <glib/gi18n-lib.h>
+
+#ifdef GEGL_CHANT_PROPERTIES
+
+gegl_chant_pointer (src_profile, _("Source Profile"),
+ _("The cmsHPROFILE corresponding to the icc profile for "
+ "the input data."))
+
+/* These are positioned so their values match up with the LCMS enum */
+gegl_chant_register_enum (gegl_rendering_intent)
+ enum_value (GEGL_RENDERING_INTENT_PERCEPTUAL, "Perceptual")
+ enum_value (GEGL_RENDERING_INTENT_RELATIVE_COLORIMETRIC, "Relative Colorimetric")
+ enum_value (GEGL_RENDERING_INTENT_SATURATION, "Saturation")
+ enum_value (GEGL_RENDERING_INTENT_ABSOLUTE_COLORIMETRIC, "Absolute Colorimetric")
+/* TODO: Add the K_ONLY and K_PLANE intents */
+gegl_chant_register_enum_end (GeglRenderingIntent)
+
+gegl_chant_enum (intent, _("Rendering Intent"),
+ GeglRenderingIntent, gegl_rendering_intent,
+ GEGL_RENDERING_INTENT_PERCEPTUAL,
+ _("The rendering intent to use in the conversion."))
+
+gegl_chant_boolean (black_point_compensation, _("Black Point Compensation"),
+ FALSE, _("Convert using black point compensation."))
+
+#else
+
+#define GEGL_CHANT_TYPE_FILTER
+#define GEGL_CHANT_C_FILE "lcms-from-profile.c"
+
+#include "gegl-chant.h"
+#include <lcms2.h>
+
+static void prepare (GeglOperation *operation)
+{
+ /* TODO: move input format detection code here */
+ gegl_operation_set_format (operation, "output", babl_format ("RGBA float"));
+}
+
+/* This profile corresponds to babl_model ("RGB") */
+static cmsHPROFILE
+create_lcms_linear_rgb_profile (void)
+{
+ cmsHPROFILE ret;
+
+ /* white point is D65 */
+ cmsCIExyY whitepoint = {0.312713, 0.329016, 1.0};
+
+ /* primaries are ITU‐R BT.709‐5 (xYY) */
+ cmsCIExyYTRIPLE primaries = {
+ /*R*/ {0.6400, 0.3300, 1.0},
+ /*G*/ {0.3000, 0.6000, 1.0},
+ /*B*/ {0.1500, 0.0600, 1.0}
+ };
+
+ /* linear light */
+ cmsToneCurve* linear[3];
+ linear[0] = linear[1] = linear[2] = cmsBuildGamma (NULL, 1.0);
+
+ /* create the profile, cleanup, and return */
+ ret = cmsCreateRGBProfile (&whitepoint, &primaries, linear);
+ cmsFreeToneCurve (linear[0]);
+ return ret;
+}
+
+static cmsUInt32Number
+determine_lcms_format (const Babl *babl, cmsHPROFILE profile)
+{
+ cmsUInt32Number format = COLORSPACE_SH (PT_ANY);
+ gint channels, bpc, alpha;
+ const Babl *type;
+
+ channels = cmsChannelsOf (cmsGetColorSpace (profile));
+ alpha = babl_format_get_n_components (babl) - channels;
+ bpc = babl_format_get_bytes_per_pixel (babl)
+ / babl_format_get_n_components (babl);
+
+ type = babl_format_get_type (babl, 0);
+ if (type == babl_type ("half") ||
+ type == babl_type ("float") ||
+ type == babl_type ("double"))
+ format |= FLOAT_SH (1);
+
+ /* bpc == 8 overflows the bitfield otherwise */
+ bpc &= 0x07;
+
+ /*
+ * This is needed so the alpha component lines up with RGBA float
+ * for our memcpy hack later on.
+ */
+ if (alpha > 1 || (alpha && channels != 3))
+ return 0;
+
+ format |= EXTRA_SH (alpha) | CHANNELS_SH (channels) | BYTES_SH (bpc);
+ return format;
+}
+
+static gboolean
+process (GeglOperation *operation,
+ GeglBuffer *input,
+ GeglBuffer *output,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+
+ cmsHTRANSFORM transform;
+ const Babl *in_format, *out_format;
+
+ gboolean alpha;
+ gint bpp;
+
+ in_format = babl_format_n (babl_type ("float"),
+ babl_format_get_n_components (gegl_buffer_get_format (input)));
+
+ bpp = babl_format_get_bytes_per_pixel (in_format);
+
+ /* create the transformation */
+ {
+ cmsHPROFILE in_profile, out_profile;
+ cmsUInt32Number format;
+
+ in_profile = o->src_profile;
+
+ format = determine_lcms_format (in_format, in_profile);
+
+ if (format == 0)
+ return FALSE;
+
+ if (format & EXTRA_SH (1))
+ alpha = TRUE;
+ else
+ alpha = FALSE;
+
+ out_profile = create_lcms_linear_rgb_profile ();
+
+ transform = cmsCreateTransform (in_profile, format,
+ out_profile, alpha ? TYPE_RGBA_FLT : TYPE_RGB_FLT,
+ o->intent, o->black_point_compensation ? cmsFLAGS_BLACKPOINTCOMPENSATION
: 0);
+
+ cmsCloseProfile (out_profile);
+ }
+
+ out_format = alpha ? babl_format ("RGBA float") : babl_format ("RGB float");
+
+ /* iterate over the pixels */
+ {
+ GeglBufferIterator *gi;
+
+ gi = gegl_buffer_iterator_new (input, result, 0, in_format,
+ GEGL_BUFFER_READ, GEGL_ABYSS_NONE);
+
+ gegl_buffer_iterator_add (gi, output, result, 0, out_format,
+ GEGL_BUFFER_WRITE, GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (gi))
+ {
+ if (alpha)
+ memcpy (gi->data[1], gi->data[0], bpp * gi->length);
+
+ cmsDoTransform (transform, gi->data[0], gi->data[1], gi->length);
+ }
+ }
+
+ cmsDeleteTransform (transform);
+
+ return TRUE;
+}
+
+static gboolean
+operation_process (GeglOperation *operation,
+ GeglOperationContext *context,
+ const gchar *output_prop,
+ const GeglRectangle *result,
+ gint level)
+{
+ GeglChantO *o = GEGL_CHANT_PROPERTIES (operation);
+ GeglOperationClass *operation_class;
+
+ operation_class = GEGL_OPERATION_CLASS (gegl_chant_parent_class);
+
+ /* If the profile is NULL, simply become a nop */
+ if (!o->src_profile)
+ {
+ gpointer input = gegl_operation_context_get_object (context, "input");
+ gegl_operation_context_take_object (context, "output",
+ g_object_ref (input));
+ return TRUE;
+ }
+
+ return operation_class->process (operation, context,
+ output_prop, result, level);
+}
+
+static void
+gegl_chant_class_init (GeglChantClass *klass)
+{
+ GeglOperationClass *operation_class;
+ GeglOperationFilterClass *filter_class;
+
+ operation_class = GEGL_OPERATION_CLASS (klass);
+ filter_class = GEGL_OPERATION_FILTER_CLASS (klass);
+
+ operation_class->prepare = prepare;
+ operation_class->process = operation_process;
+
+ filter_class->process = process;
+
+ gegl_operation_class_set_keys (operation_class,
+ "name", "gegl:lcms-from-profile",
+ "categories", "color",
+ "description",
+ _("Converts the input from an ICC color profile to "
+ "a well defined babl format. The input buffer should "
+ "be a babl_format_n type."),
+ NULL);
+}
+#endif
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]