all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: Mark Oteiza <mvoteiza@udel.edu>
To: Eli Zaretskii <eliz@gnu.org>
Cc: 28400@debbugs.gnu.org
Subject: bug#28400: 26.0.50; lcms2 bindings
Date: Mon, 11 Sep 2017 19:10:06 -0400	[thread overview]
Message-ID: <20170911231006.GA5455@holos.localdomain> (raw)
In-Reply-To: <831sndth2e.fsf@gnu.org>

On 11/09/17 at 06:01pm, Eli Zaretskii wrote:
> > Date: Sun, 10 Sep 2017 18:04:22 -0400
> > From: Mark Oteiza <mvoteiza@udel.edu>
> > Cc: 28400@debbugs.gnu.org
> > 
> > >Is it really so much better than what we have now to justify requiring
> > >yet another library to build Emacs?  If it is, could you tell what are
> > >the main advantages, or point to where those advantages are described?
> > 
> > It was just much easier for me to hack existing code than figure out adding
> > a new file and the configure.ac business.  It would be much more
> > sensible to offer it as an optional feature and expose color metrics as
> > optional arguments, e.g.
> > 
> >   (color-distance COLOR1 COLOR2 &optional FRAME METRIC)
> > 
> > where METRIC accepts two colors and returns a number.
> 
> Oh, I see.  But in that case, I think adding a new file and the
> configure.ac business is actually quite easy.

Humble beginnings attached.

 configure.ac    |  19 +++++++
 src/Makefile.in |   6 ++-
 src/emacs.c     |   4 ++
 src/lcms.c      | 157 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/lisp.h      |   5 ++
 5 files changed, 189 insertions(+), 2 deletions(-)

diff --git a/configure.ac b/configure.ac
index d294412dc4..df3931f938 100644
--- a/configure.ac
+++ b/configure.ac
@@ -3451,6 +3451,25 @@ AC_DEFUN
 fi
 AC_SUBST(LIBJPEG)
 
+HAVE_LCMS2=no
+LIBLCMS2=
+if test "${with_lcms2}" != "no"; then
+  OLIBS=$LIBS
+  AC_SEARCH_LIBS([cmsCreateTransform], [lcms2], [HAVE_LCMS2=yes])
+  LIBS=$OLIBS
+  case $ac_cv_search_cmsCreateTransform in
+    -*) LIBLCMS2=$ac_cv_search_cmsCreateTransform ;;
+  esac
+fi
+if test "${HAVE_LCMS2}" = "yes"; then
+  AC_DEFINE([HAVE_LCMS2], 1, [Define to 1 if you have the lcms2 library (-llcms2).])
+  ### ???
+  if test "${opsys}" = "mingw32"; then
+     LIBLCMS2=
+  fi
+fi
+AC_SUBST(LIBLCMS2)
+
 HAVE_ZLIB=no
 LIBZ=
 if test "${with_zlib}" != "no"; then
diff --git a/src/Makefile.in b/src/Makefile.in
index dde3f1d3fb..a98ad9c5eb 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -234,6 +234,8 @@ LIBXML2_CFLAGS =
 
 GETADDRINFO_A_LIBS = @GETADDRINFO_A_LIBS@
 
+LIBLCMS2 = @LIBLCMS2@
+
 LIBZ = @LIBZ@
 
 ## system-specific libs for dynamic modules, else empty
@@ -389,7 +391,7 @@ base_obj =
 	syntax.o $(UNEXEC_OBJ) bytecode.o \
 	process.o gnutls.o callproc.o \
 	region-cache.o sound.o atimer.o \
-	doprnt.o intervals.o textprop.o composite.o xml.o $(NOTIFY_OBJ) \
+	doprnt.o intervals.o textprop.o composite.o xml.o lcms.o $(NOTIFY_OBJ) \
 	$(XWIDGETS_OBJ) \
 	profiler.o decompress.o \
 	thread.o systhread.o \
@@ -490,7 +492,7 @@ LIBES =
    $(LIBXML2_LIBS) $(LIBGPM) $(LIBS_SYSTEM) $(CAIRO_LIBS) \
    $(LIBS_TERMCAP) $(GETLOADAVG_LIBS) $(SETTINGS_LIBS) $(LIBSELINUX_LIBS) \
    $(FREETYPE_LIBS) $(FONTCONFIG_LIBS) $(LIBOTF_LIBS) $(M17N_FLT_LIBS) \
-   $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) \
+   $(LIBGNUTLS_LIBS) $(LIB_PTHREAD) $(GETADDRINFO_A_LIBS) $(LIBLCMS2) \
    $(NOTIFY_LIBS) $(LIB_MATH) $(LIBZ) $(LIBMODULES) $(LIBSYSTEMD_LIBS)
 
 ## FORCE it so that admin/unidata can decide whether these files
diff --git a/src/emacs.c b/src/emacs.c
index 44f6285795..668711a5ab 100644
--- a/src/emacs.c
+++ b/src/emacs.c
@@ -1546,6 +1546,10 @@ Using an Emacs configured with --with-x-toolkit=lucid does not have this problem
       syms_of_xml ();
 #endif
 
+#ifdef HAVE_LCMS2
+      syms_of_lcms2 ();
+#endif
+
 #ifdef HAVE_ZLIB
       syms_of_decompress ();
 #endif
diff --git a/src/lcms.c b/src/lcms.c
new file mode 100644
index 0000000000..560b262818
--- /dev/null
+++ b/src/lcms.c
@@ -0,0 +1,157 @@
+/* Interface to Little CMS
+   Copyright (C) 2017 Mark Oteiza <mvoteiza@udel.edu>
+
+This file is NOT part of GNU Emacs.
+
+GNU Emacs is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or (at
+your option) any later version.
+
+GNU Emacs 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 General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with GNU Emacs.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include <config.h>
+
+#ifdef HAVE_LCMS2
+
+#include <lcms2.h>
+#include <math.h>
+
+#include "lisp.h"
+
+static bool
+parse_lab_list (Lisp_Object lab_list, cmsCIELab *color)
+{
+#define PARSE_LAB_LIST_FIELD(field)					\
+  if (CONSP (lab_list) && NUMBERP (XCAR (lab_list)))			\
+    {									\
+      color->field = XFLOATINT (XCAR (lab_list));			\
+      lab_list = XCDR (lab_list);					\
+    }									\
+  else									\
+    return false;
+
+  PARSE_LAB_LIST_FIELD (L);
+  PARSE_LAB_LIST_FIELD (a);
+  PARSE_LAB_LIST_FIELD (b);
+
+  return true;
+}
+
+/* http://www.ece.rochester.edu/~gsharma/ciede2000/ciede2000noteCRNA.pdf> */
+
+DEFUN ("lcms-cie-de2000", Flcms_cie_de2000, Slcms_cie_de2000, 2, 2, 0,
+       doc: /* Compute CIEDE2000 metric distance between COLOR1 and COLOR2.
+Each color is a list of L*a*b* coordinates, where the L* channel ranges from
+0 to 100, and the a* and b* channels range from -128 to 128.
+Optional arguments KL, KC, KH are weighting parameters for lightness,
+chroma, and hue, respectively. */)
+  (Lisp_Object color1, Lisp_Object color2)
+{
+  cmsCIELab Lab1, Lab2;
+
+  if (!(CONSP (color1) && parse_lab_list (color1, &Lab1)))
+    signal_error ("Invalid color", color1);
+  if (!(CONSP (color2) && parse_lab_list (color2, &Lab2)))
+    signal_error ("Invalid color", color1);
+  return make_float (cmsCIE2000DeltaE (&Lab1, &Lab2, 1.0f, 1.0f, 1.0f));
+}
+
+/* FIXME: code duplication */
+
+static bool
+parse_xyz_list (Lisp_Object xyz_list, cmsCIEXYZ *color)
+{
+#define PARSE_XYZ_LIST_FIELD(field)					\
+  if (CONSP (xyz_list) && NUMBERP (XCAR (xyz_list)))			\
+    {									\
+      color->field = XFLOATINT (XCAR (xyz_list));			\
+      xyz_list = XCDR (xyz_list);					\
+    }									\
+  else									\
+    return false;
+
+  PARSE_XYZ_LIST_FIELD (X);
+  PARSE_XYZ_LIST_FIELD (Y);
+  PARSE_XYZ_LIST_FIELD (Z);
+
+  return true;
+}
+
+DEFUN ("lcms-cam02-ucs", Flcms-cam02-ucs, Slcms_cam02_ucs, 2, 2, 0,
+       doc: /* Compute CAM02-UCS metric distance between COLOR1 and COLOR2.
+Each color is a list of XYZ coordinates.
+Optional argument is the XYZ white point, which defaults to D65. */)
+  (Lisp_Object color1, Lisp_Object color2)
+{
+  cmsViewingConditions vc;
+  cmsJCh jch1, jch2;
+  cmsHANDLE h1, h2;
+  cmsCIEXYZ xyz1, xyz2;
+  double Jp1, ap1, bp1, Jp2, ap2, bp2;
+  double Mp1, Mp2, FL, k;
+
+  if (!(CONSP (color1) && parse_xyz_list (color1, &xyz1)))
+    signal_error ("Invalid color", color1);
+  if (!(CONSP (color2) && parse_xyz_list (color2, &xyz2)))
+    signal_error ("Invalid color", color1);
+
+  vc.whitePoint.X = 95.047;
+  vc.whitePoint.Y = 100.00;
+  vc.whitePoint.Z = 108.883;
+  vc.Yb = 20;
+  vc.La = 100;
+  vc.surround = AVG_SURROUND;
+  vc.D_value = 1.0;
+
+  h1 = cmsCIECAM02Init(0, &vc);
+  h2 = cmsCIECAM02Init(0, &vc);
+  cmsCIECAM02Forward(h1, &xyz1, &jch1);
+  cmsCIECAM02Forward(h2, &xyz2, &jch2);
+  cmsCIECAM02Done(h1);
+  cmsCIECAM02Done(h2);
+  /* Now have JCh, need to calculate Jab
+
+     M = C * F_L^0.25
+     J' = 1.7 J / (1 + 0.007 J)
+     M' = 43.86 ln(1 + 0.0228 M)
+     a' = M' cos(h)
+     b' = M' sin(h)
+
+     where
+
+     F_L = 0.2 k^4 (5 L_A) + 0.1 (1 - k^4)^2 (5 L_A)^(1/3),
+     k = 1/(5 L_A + 1)
+  */
+  k = 1.0f / (1.0f + (5.0f * vc.La));
+  FL = pow(k, 4) * vc.La +
+    0.1f * pow(1 - pow(k, 4), 2) * pow(5.0f * vc.La, 1.0f / 3.0f);
+  Mp1 = 43.86f * log(1.0f + 0.0228f * (jch1.C * pow(FL, 0.25)));
+  Mp2 = 43.86f * log(1.0f + 0.0228f * (jch2.C * pow(FL, 0.25)));
+  Jp1 = 1.7f * jch1.J / (1.0f + (0.007f * jch1.J));
+  Jp2 = 1.7f * jch2.J / (1.0f + (0.007f * jch2.J));
+  ap1 = Mp1 * cos(jch1.h);
+  ap2 = Mp2 * cos(jch2.h);
+  bp1 = Mp1 * sin(jch1.h);
+  bp2 = Mp2 * sin(jch2.h);
+  return make_float(sqrt(pow(Jp2 - Jp1, 2) +
+                         pow(ap2 - ap1, 2) +
+                         pow(bp2 - bp1, 2)));
+}
+
+\f
+/* Initialization */
+void
+syms_of_lcms2 (void)
+{
+  defsubr (&Slcms_cie_de2000);
+  defsubr (&Slcms_cam02_ucs);
+}
+
+#endif /* HAVE_LCMS2 */
diff --git a/src/lisp.h b/src/lisp.h
index 81f8d6a24b..19594e7830 100644
--- a/src/lisp.h
+++ b/src/lisp.h
@@ -4396,6 +4396,11 @@ extern void syms_of_xml (void);
 extern void xml_cleanup_parser (void);
 #endif
 
+#ifdef HAVE_LCMS2
+/* Defined in lcms.c.  */
+extern void syms_of_lcms2 (void);
+#endif
+
 #ifdef HAVE_ZLIB
 /* Defined in decompress.c.  */
 extern void syms_of_decompress (void);





  parent reply	other threads:[~2017-09-11 23:10 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-09-09 15:50 bug#28400: 26.0.50; lcms2 bindings Mark Oteiza
2017-09-09 17:37 ` Eli Zaretskii
2017-09-10 22:04   ` Mark Oteiza
2017-09-11 15:01     ` Eli Zaretskii
2017-09-11 15:25       ` Mark Oteiza
2017-09-11 15:35         ` Eli Zaretskii
2017-09-11 23:10       ` Mark Oteiza [this message]
2017-09-12 15:53         ` Eli Zaretskii
2017-09-12 21:06           ` Mark Oteiza

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20170911231006.GA5455@holos.localdomain \
    --to=mvoteiza@udel.edu \
    --cc=28400@debbugs.gnu.org \
    --cc=eliz@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this external index

	https://git.savannah.gnu.org/cgit/emacs.git
	https://git.savannah.gnu.org/cgit/emacs/org-mode.git

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.