summaryrefslogtreecommitdiffstats
path: root/libgimpcolor
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:30:19 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 18:30:19 +0000
commit5c1676dfe6d2f3c837a5e074117b45613fd29a72 (patch)
treecbffb45144febf451e54061db2b21395faf94bfe /libgimpcolor
parentInitial commit. (diff)
downloadgimp-5c1676dfe6d2f3c837a5e074117b45613fd29a72.tar.xz
gimp-5c1676dfe6d2f3c837a5e074117b45613fd29a72.zip
Adding upstream version 2.10.34.upstream/2.10.34upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'libgimpcolor')
-rw-r--r--libgimpcolor/Makefile.am148
-rw-r--r--libgimpcolor/Makefile.in1523
-rw-r--r--libgimpcolor/gimpadaptivesupersample.c394
-rw-r--r--libgimpcolor/gimpadaptivesupersample.h50
-rw-r--r--libgimpcolor/gimpbilinear.c313
-rw-r--r--libgimpcolor/gimpbilinear.h63
-rw-r--r--libgimpcolor/gimpcairo.c210
-rw-r--r--libgimpcolor/gimpcairo.h159
-rw-r--r--libgimpcolor/gimpcmyk.c233
-rw-r--r--libgimpcolor/gimpcmyk.h78
-rw-r--r--libgimpcolor/gimpcolor.def128
-rw-r--r--libgimpcolor/gimpcolor.h41
-rw-r--r--libgimpcolor/gimpcolormanaged.c151
-rw-r--r--libgimpcolor/gimpcolormanaged.h82
-rw-r--r--libgimpcolor/gimpcolorprofile.c1789
-rw-r--r--libgimpcolor/gimpcolorprofile.h128
-rw-r--r--libgimpcolor/gimpcolorspace.c1103
-rw-r--r--libgimpcolor/gimpcolorspace.h121
-rw-r--r--libgimpcolor/gimpcolortransform.c596
-rw-r--r--libgimpcolor/gimpcolortransform.h127
-rw-r--r--libgimpcolor/gimpcolortypes.h126
-rw-r--r--libgimpcolor/gimphsl.c93
-rw-r--r--libgimpcolor/gimphsl.h49
-rw-r--r--libgimpcolor/gimphsv.c107
-rw-r--r--libgimpcolor/gimphsv.h54
-rw-r--r--libgimpcolor/gimppixbuf.c152
-rw-r--r--libgimpcolor/gimppixbuf.h43
-rw-r--r--libgimpcolor/gimprgb-parse.c651
-rw-r--r--libgimpcolor/gimprgb.c846
-rw-r--r--libgimpcolor/gimprgb.h233
-rw-r--r--libgimpcolor/test-color-parser.c119
31 files changed, 9910 insertions, 0 deletions
diff --git a/libgimpcolor/Makefile.am b/libgimpcolor/Makefile.am
new file mode 100644
index 0000000..767f3b9
--- /dev/null
+++ b/libgimpcolor/Makefile.am
@@ -0,0 +1,148 @@
+## Process this file with automake to produce Makefile.in
+
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+
+if PLATFORM_WIN32
+no_undefined = -no-undefined
+endif
+
+if PLATFORM_WIN32
+else
+libm = -lm
+endif
+
+if OS_WIN32
+gimpcolor_def = gimpcolor.def
+libgimpcolor_export_symbols = -export-symbols $(srcdir)/gimpcolor.def
+
+install-libtool-import-lib:
+ $(INSTALL) .libs/libgimpcolor-$(GIMP_API_VERSION).dll.a $(DESTDIR)$(libdir)
+ $(INSTALL) $(srcdir)/gimpcolor.def $(DESTDIR)$(libdir)
+
+uninstall-libtool-import-lib:
+ -rm $(DESTDIR)$(libdir)/libgimpcolor-$(GIMP_API_VERSION).dll.a
+ -rm $(DESTDIR)$(libdir)/gimpcolor.def
+else
+install-libtool-import-lib:
+uninstall-libtool-import-lib:
+endif
+
+if MS_LIB_AVAILABLE
+noinst_DATA = gimpcolor-$(GIMP_API_VERSION).lib
+
+install-ms-lib:
+ $(INSTALL) gimpcolor-$(GIMP_API_VERSION).lib $(DESTDIR)$(libdir)
+
+uninstall-ms-lib:
+ -rm $(DESTDIR)$(libdir)/gimpcolor-$(GIMP_API_VERSION).lib
+
+gimpcolor-@GIMP_API_VERSION@.lib: gimpcolor.def
+ lib -name:libgimpcolor-$(GIMP_API_VERSION)-@LT_CURRENT_MINUS_AGE@.dll -def:gimpcolor.def -out:$@
+
+else
+install-ms-lib:
+uninstall-ms-lib:
+endif
+
+libgimpcolorincludedir = $(includedir)/gimp-$(GIMP_API_VERSION)/libgimpcolor
+
+AM_CPPFLAGS = \
+ -DG_LOG_DOMAIN=\"LibGimpColor\" \
+ -DGIMP_COLOR_COMPILATION \
+ -I$(top_srcdir) \
+ $(GEGL_CFLAGS) \
+ $(CAIRO_CFLAGS) \
+ $(GDK_PIXBUF_CFLAGS) \
+ $(LCMS_CFLAGS) \
+ -I$(includedir)
+
+EXTRA_DIST = \
+ gimpcolor.def
+
+lib_LTLIBRARIES = libgimpcolor-@GIMP_API_VERSION@.la
+
+libgimpcolor_@GIMP_API_VERSION@_la_SOURCES = \
+ gimpcolor.h \
+ gimpcolortypes.h \
+ gimpadaptivesupersample.c \
+ gimpadaptivesupersample.h \
+ gimpbilinear.c \
+ gimpbilinear.h \
+ gimpcairo.c \
+ gimpcairo.h \
+ gimpcmyk.c \
+ gimpcmyk.h \
+ gimpcolormanaged.c \
+ gimpcolormanaged.h \
+ gimpcolorprofile.c \
+ gimpcolorprofile.h \
+ gimpcolorspace.c \
+ gimpcolorspace.h \
+ gimpcolortransform.c \
+ gimpcolortransform.h \
+ gimphsl.c \
+ gimphsl.h \
+ gimphsv.c \
+ gimphsv.h \
+ gimppixbuf.c \
+ gimppixbuf.h \
+ gimprgb.c \
+ gimprgb.h \
+ gimprgb-parse.c
+
+libgimpcolorinclude_HEADERS = \
+ gimpcolor.h \
+ gimpcolortypes.h \
+ gimpadaptivesupersample.h \
+ gimpbilinear.h \
+ gimpcairo.h \
+ gimpcmyk.h \
+ gimpcolormanaged.h \
+ gimpcolorprofile.h \
+ gimpcolorspace.h \
+ gimpcolortransform.h \
+ gimphsl.h \
+ gimphsv.h \
+ gimppixbuf.h \
+ gimprgb.h
+
+libgimpcolor_@GIMP_API_VERSION@_la_LDFLAGS = \
+ -version-info $(LT_VERSION_INFO) \
+ $(no_undefined) \
+ $(libgimpcolor_export_symbols)
+
+EXTRA_libgimpcolor_@GIMP_API_VERSION@_la_DEPENDENCIES = $(gimpcolor_def)
+
+libgimpcolor_@GIMP_API_VERSION@_la_LIBADD = \
+ $(libgimpbase) \
+ $(GEGL_LIBS) \
+ $(CAIRO_LIBS) \
+ $(GDK_PIXBUF_LIBS) \
+ $(LCMS_LIBS) \
+ $(libm)
+
+
+#
+# test programs, not to be built by default and never installed
+#
+
+TESTS = test-color-parser$(EXEEXT)
+
+EXTRA_PROGRAMS = test-color-parser
+
+test_color_parser_DEPENDENCIES = \
+ $(libgimpbase) \
+ $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+
+test_color_parser_LDADD = \
+ $(CAIRO_LIBS) \
+ $(GLIB_LIBS) \
+ $(test_color_parser_DEPENDENCIES)
+
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+
+
+install-data-local: install-ms-lib install-libtool-import-lib
+
+uninstall-local: uninstall-ms-lib uninstall-libtool-import-lib
diff --git a/libgimpcolor/Makefile.in b/libgimpcolor/Makefile.in
new file mode 100644
index 0000000..b3d7659
--- /dev/null
+++ b/libgimpcolor/Makefile.in
@@ -0,0 +1,1523 @@
+# Makefile.in generated by automake 1.16.3 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2020 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = { \
+ if test -z '$(MAKELEVEL)'; then \
+ false; \
+ elif test -n '$(MAKE_HOST)'; then \
+ true; \
+ elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \
+ true; \
+ else \
+ false; \
+ fi; \
+}
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = test-color-parser$(EXEEXT)
+subdir = libgimpcolor
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
+ $(top_srcdir)/m4macros/alsa.m4 \
+ $(top_srcdir)/m4macros/ax_compare_version.m4 \
+ $(top_srcdir)/m4macros/ax_cxx_compile_stdcxx.m4 \
+ $(top_srcdir)/m4macros/ax_gcc_func_attribute.m4 \
+ $(top_srcdir)/m4macros/ax_prog_cc_for_build.m4 \
+ $(top_srcdir)/m4macros/ax_prog_perl_version.m4 \
+ $(top_srcdir)/m4macros/detectcflags.m4 \
+ $(top_srcdir)/m4macros/pythondev.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+DIST_COMMON = $(srcdir)/Makefile.am $(libgimpcolorinclude_HEADERS) \
+ $(am__DIST_COMMON)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(libdir)" \
+ "$(DESTDIR)$(libgimpcolorincludedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgimpcolor_@GIMP_API_VERSION@_la_DEPENDENCIES = $(libgimpbase) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgimpcolor_@GIMP_API_VERSION@_la_OBJECTS = \
+ gimpadaptivesupersample.lo gimpbilinear.lo gimpcairo.lo \
+ gimpcmyk.lo gimpcolormanaged.lo gimpcolorprofile.lo \
+ gimpcolorspace.lo gimpcolortransform.lo gimphsl.lo gimphsv.lo \
+ gimppixbuf.lo gimprgb.lo gimprgb-parse.lo
+libgimpcolor_@GIMP_API_VERSION@_la_OBJECTS = \
+ $(am_libgimpcolor_@GIMP_API_VERSION@_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgimpcolor_@GIMP_API_VERSION@_la_LINK = $(LIBTOOL) $(AM_V_lt) \
+ --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
+ $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(libgimpcolor_@GIMP_API_VERSION@_la_LDFLAGS) $(LDFLAGS) -o $@
+test_color_parser_SOURCES = test-color-parser.c
+test_color_parser_OBJECTS = test-color-parser.$(OBJEXT)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__maybe_remake_depfiles = depfiles
+am__depfiles_remade = ./$(DEPDIR)/gimpadaptivesupersample.Plo \
+ ./$(DEPDIR)/gimpbilinear.Plo ./$(DEPDIR)/gimpcairo.Plo \
+ ./$(DEPDIR)/gimpcmyk.Plo ./$(DEPDIR)/gimpcolormanaged.Plo \
+ ./$(DEPDIR)/gimpcolorprofile.Plo \
+ ./$(DEPDIR)/gimpcolorspace.Plo \
+ ./$(DEPDIR)/gimpcolortransform.Plo ./$(DEPDIR)/gimphsl.Plo \
+ ./$(DEPDIR)/gimphsv.Plo ./$(DEPDIR)/gimppixbuf.Plo \
+ ./$(DEPDIR)/gimprgb-parse.Plo ./$(DEPDIR)/gimprgb.Plo \
+ ./$(DEPDIR)/test-color-parser.Po
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgimpcolor_@GIMP_API_VERSION@_la_SOURCES) \
+ test-color-parser.c
+DIST_SOURCES = $(libgimpcolor_@GIMP_API_VERSION@_la_SOURCES) \
+ test-color-parser.c
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(noinst_DATA)
+HEADERS = $(libgimpcolorinclude_HEADERS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red=''; \
+ grn=''; \
+ lgn=''; \
+ blu=''; \
+ mgn=''; \
+ brg=''; \
+ std=''; \
+ fi; \
+}
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_TESTSUITE_SUMMARY_HEADER = ' for $(PACKAGE_STRING)'
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp \
+ $(top_srcdir)/test-driver
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+AA_LIBS = @AA_LIBS@
+ACLOCAL = @ACLOCAL@
+ALLOCA = @ALLOCA@
+ALL_LINGUAS = @ALL_LINGUAS@
+ALSA_CFLAGS = @ALSA_CFLAGS@
+ALSA_LIBS = @ALSA_LIBS@
+ALTIVEC_EXTRA_CFLAGS = @ALTIVEC_EXTRA_CFLAGS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+APPSTREAM_UTIL = @APPSTREAM_UTIL@
+AR = @AR@
+AS = @AS@
+ATK_CFLAGS = @ATK_CFLAGS@
+ATK_LIBS = @ATK_LIBS@
+ATK_REQUIRED_VERSION = @ATK_REQUIRED_VERSION@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BABL_CFLAGS = @BABL_CFLAGS@
+BABL_LIBS = @BABL_LIBS@
+BABL_REQUIRED_VERSION = @BABL_REQUIRED_VERSION@
+BUG_REPORT_URL = @BUG_REPORT_URL@
+BUILD_EXEEXT = @BUILD_EXEEXT@
+BUILD_OBJEXT = @BUILD_OBJEXT@
+BZIP2_LIBS = @BZIP2_LIBS@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
+CAIRO_PDF_CFLAGS = @CAIRO_PDF_CFLAGS@
+CAIRO_PDF_LIBS = @CAIRO_PDF_LIBS@
+CAIRO_PDF_REQUIRED_VERSION = @CAIRO_PDF_REQUIRED_VERSION@
+CAIRO_REQUIRED_VERSION = @CAIRO_REQUIRED_VERSION@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCAS = @CCAS@
+CCASDEPMODE = @CCASDEPMODE@
+CCASFLAGS = @CCASFLAGS@
+CCDEPMODE = @CCDEPMODE@
+CC_FOR_BUILD = @CC_FOR_BUILD@
+CC_VERSION = @CC_VERSION@
+CFLAGS = @CFLAGS@
+CFLAGS_FOR_BUILD = @CFLAGS_FOR_BUILD@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CPPFLAGS_FOR_BUILD = @CPPFLAGS_FOR_BUILD@
+CPP_FOR_BUILD = @CPP_FOR_BUILD@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DESKTOP_DATADIR = @DESKTOP_DATADIR@
+DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@
+DLLTOOL = @DLLTOOL@
+DOC_SHOOTER = @DOC_SHOOTER@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+FILE_AA = @FILE_AA@
+FILE_EXR = @FILE_EXR@
+FILE_HEIF = @FILE_HEIF@
+FILE_JP2_LOAD = @FILE_JP2_LOAD@
+FILE_JPEGXL = @FILE_JPEGXL@
+FILE_MNG = @FILE_MNG@
+FILE_PDF_SAVE = @FILE_PDF_SAVE@
+FILE_PS = @FILE_PS@
+FILE_WMF = @FILE_WMF@
+FILE_XMC = @FILE_XMC@
+FILE_XPM = @FILE_XPM@
+FONTCONFIG_CFLAGS = @FONTCONFIG_CFLAGS@
+FONTCONFIG_LIBS = @FONTCONFIG_LIBS@
+FONTCONFIG_REQUIRED_VERSION = @FONTCONFIG_REQUIRED_VERSION@
+FREETYPE2_REQUIRED_VERSION = @FREETYPE2_REQUIRED_VERSION@
+FREETYPE_CFLAGS = @FREETYPE_CFLAGS@
+FREETYPE_LIBS = @FREETYPE_LIBS@
+GDBUS_CODEGEN = @GDBUS_CODEGEN@
+GDK_PIXBUF_CFLAGS = @GDK_PIXBUF_CFLAGS@
+GDK_PIXBUF_CSOURCE = @GDK_PIXBUF_CSOURCE@
+GDK_PIXBUF_LIBS = @GDK_PIXBUF_LIBS@
+GDK_PIXBUF_REQUIRED_VERSION = @GDK_PIXBUF_REQUIRED_VERSION@
+GEGL = @GEGL@
+GEGL_CFLAGS = @GEGL_CFLAGS@
+GEGL_LIBS = @GEGL_LIBS@
+GEGL_MAJOR_MINOR_VERSION = @GEGL_MAJOR_MINOR_VERSION@
+GEGL_REQUIRED_VERSION = @GEGL_REQUIRED_VERSION@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GEXIV2_CFLAGS = @GEXIV2_CFLAGS@
+GEXIV2_LIBS = @GEXIV2_LIBS@
+GEXIV2_REQUIRED_VERSION = @GEXIV2_REQUIRED_VERSION@
+GIMP_API_VERSION = @GIMP_API_VERSION@
+GIMP_APP_VERSION = @GIMP_APP_VERSION@
+GIMP_BINARY_AGE = @GIMP_BINARY_AGE@
+GIMP_COMMAND = @GIMP_COMMAND@
+GIMP_DATA_VERSION = @GIMP_DATA_VERSION@
+GIMP_FULL_NAME = @GIMP_FULL_NAME@
+GIMP_INTERFACE_AGE = @GIMP_INTERFACE_AGE@
+GIMP_MAJOR_VERSION = @GIMP_MAJOR_VERSION@
+GIMP_MICRO_VERSION = @GIMP_MICRO_VERSION@
+GIMP_MINOR_VERSION = @GIMP_MINOR_VERSION@
+GIMP_MKENUMS = @GIMP_MKENUMS@
+GIMP_MODULES = @GIMP_MODULES@
+GIMP_PACKAGE_REVISION = @GIMP_PACKAGE_REVISION@
+GIMP_PKGCONFIG_VERSION = @GIMP_PKGCONFIG_VERSION@
+GIMP_PLUGINS = @GIMP_PLUGINS@
+GIMP_PLUGIN_VERSION = @GIMP_PLUGIN_VERSION@
+GIMP_REAL_VERSION = @GIMP_REAL_VERSION@
+GIMP_RELEASE = @GIMP_RELEASE@
+GIMP_SYSCONF_VERSION = @GIMP_SYSCONF_VERSION@
+GIMP_TOOL_VERSION = @GIMP_TOOL_VERSION@
+GIMP_UNSTABLE = @GIMP_UNSTABLE@
+GIMP_USER_VERSION = @GIMP_USER_VERSION@
+GIMP_VERSION = @GIMP_VERSION@
+GIO_CFLAGS = @GIO_CFLAGS@
+GIO_LIBS = @GIO_LIBS@
+GIO_UNIX_CFLAGS = @GIO_UNIX_CFLAGS@
+GIO_UNIX_LIBS = @GIO_UNIX_LIBS@
+GIO_WINDOWS_CFLAGS = @GIO_WINDOWS_CFLAGS@
+GIO_WINDOWS_LIBS = @GIO_WINDOWS_LIBS@
+GLIB_CFLAGS = @GLIB_CFLAGS@
+GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_LIBS = @GLIB_LIBS@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GLIB_REQUIRED_VERSION = @GLIB_REQUIRED_VERSION@
+GMODULE_NO_EXPORT_CFLAGS = @GMODULE_NO_EXPORT_CFLAGS@
+GMODULE_NO_EXPORT_LIBS = @GMODULE_NO_EXPORT_LIBS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GOBJECT_QUERY = @GOBJECT_QUERY@
+GREP = @GREP@
+GS_LIBS = @GS_LIBS@
+GTKDOC_CHECK = @GTKDOC_CHECK@
+GTKDOC_CHECK_PATH = @GTKDOC_CHECK_PATH@
+GTKDOC_DEPS_CFLAGS = @GTKDOC_DEPS_CFLAGS@
+GTKDOC_DEPS_LIBS = @GTKDOC_DEPS_LIBS@
+GTKDOC_MKPDF = @GTKDOC_MKPDF@
+GTKDOC_REBASE = @GTKDOC_REBASE@
+GTK_CFLAGS = @GTK_CFLAGS@
+GTK_LIBS = @GTK_LIBS@
+GTK_MAC_INTEGRATION_CFLAGS = @GTK_MAC_INTEGRATION_CFLAGS@
+GTK_MAC_INTEGRATION_LIBS = @GTK_MAC_INTEGRATION_LIBS@
+GTK_REQUIRED_VERSION = @GTK_REQUIRED_VERSION@
+GTK_UPDATE_ICON_CACHE = @GTK_UPDATE_ICON_CACHE@
+GUDEV_CFLAGS = @GUDEV_CFLAGS@
+GUDEV_LIBS = @GUDEV_LIBS@
+HARFBUZZ_CFLAGS = @HARFBUZZ_CFLAGS@
+HARFBUZZ_LIBS = @HARFBUZZ_LIBS@
+HARFBUZZ_REQUIRED_VERSION = @HARFBUZZ_REQUIRED_VERSION@
+HAVE_CXX14 = @HAVE_CXX14@
+HAVE_FINITE = @HAVE_FINITE@
+HAVE_ISFINITE = @HAVE_ISFINITE@
+HAVE_VFORK = @HAVE_VFORK@
+HOST_GLIB_COMPILE_RESOURCES = @HOST_GLIB_COMPILE_RESOURCES@
+HTML_DIR = @HTML_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_REQUIRED_VERSION = @INTLTOOL_REQUIRED_VERSION@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+INTLTOOL_V_MERGE = @INTLTOOL_V_MERGE@
+INTLTOOL_V_MERGE_OPTIONS = @INTLTOOL_V_MERGE_OPTIONS@
+INTLTOOL__v_MERGE_ = @INTLTOOL__v_MERGE_@
+INTLTOOL__v_MERGE_0 = @INTLTOOL__v_MERGE_0@
+INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@
+ISO_CODES_LOCALEDIR = @ISO_CODES_LOCALEDIR@
+ISO_CODES_LOCATION = @ISO_CODES_LOCATION@
+JPEG_LIBS = @JPEG_LIBS@
+JSON_GLIB_CFLAGS = @JSON_GLIB_CFLAGS@
+JSON_GLIB_LIBS = @JSON_GLIB_LIBS@
+JXL_CFLAGS = @JXL_CFLAGS@
+JXL_LIBS = @JXL_LIBS@
+JXL_THREADS_CFLAGS = @JXL_THREADS_CFLAGS@
+JXL_THREADS_LIBS = @JXL_THREADS_LIBS@
+LCMS_CFLAGS = @LCMS_CFLAGS@
+LCMS_LIBS = @LCMS_LIBS@
+LCMS_REQUIRED_VERSION = @LCMS_REQUIRED_VERSION@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LDFLAGS_FOR_BUILD = @LDFLAGS_FOR_BUILD@
+LIBBACKTRACE_LIBS = @LIBBACKTRACE_LIBS@
+LIBHEIF_CFLAGS = @LIBHEIF_CFLAGS@
+LIBHEIF_LIBS = @LIBHEIF_LIBS@
+LIBHEIF_REQUIRED_VERSION = @LIBHEIF_REQUIRED_VERSION@
+LIBJXL_REQUIRED_VERSION = @LIBJXL_REQUIRED_VERSION@
+LIBLZMA_REQUIRED_VERSION = @LIBLZMA_REQUIRED_VERSION@
+LIBMYPAINT_CFLAGS = @LIBMYPAINT_CFLAGS@
+LIBMYPAINT_LIBS = @LIBMYPAINT_LIBS@
+LIBMYPAINT_REQUIRED_VERSION = @LIBMYPAINT_REQUIRED_VERSION@
+LIBOBJS = @LIBOBJS@
+LIBPNG_REQUIRED_VERSION = @LIBPNG_REQUIRED_VERSION@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIBUNWIND_CFLAGS = @LIBUNWIND_CFLAGS@
+LIBUNWIND_LIBS = @LIBUNWIND_LIBS@
+LIBUNWIND_REQUIRED_VERSION = @LIBUNWIND_REQUIRED_VERSION@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LT_CURRENT_MINUS_AGE = @LT_CURRENT_MINUS_AGE@
+LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@
+LT_VERSION_INFO = @LT_VERSION_INFO@
+LZMA_CFLAGS = @LZMA_CFLAGS@
+LZMA_LIBS = @LZMA_LIBS@
+MAIL = @MAIL@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MIME_INFO_CFLAGS = @MIME_INFO_CFLAGS@
+MIME_INFO_LIBS = @MIME_INFO_LIBS@
+MIME_TYPES = @MIME_TYPES@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MMX_EXTRA_CFLAGS = @MMX_EXTRA_CFLAGS@
+MNG_CFLAGS = @MNG_CFLAGS@
+MNG_LIBS = @MNG_LIBS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+MYPAINT_BRUSHES_CFLAGS = @MYPAINT_BRUSHES_CFLAGS@
+MYPAINT_BRUSHES_LIBS = @MYPAINT_BRUSHES_LIBS@
+NATIVE_GLIB_CFLAGS = @NATIVE_GLIB_CFLAGS@
+NATIVE_GLIB_LIBS = @NATIVE_GLIB_LIBS@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENEXR_CFLAGS = @OPENEXR_CFLAGS@
+OPENEXR_LIBS = @OPENEXR_LIBS@
+OPENEXR_REQUIRED_VERSION = @OPENEXR_REQUIRED_VERSION@
+OPENJPEG_CFLAGS = @OPENJPEG_CFLAGS@
+OPENJPEG_LIBS = @OPENJPEG_LIBS@
+OPENJPEG_REQUIRED_VERSION = @OPENJPEG_REQUIRED_VERSION@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+PACKAGE = @PACKAGE@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANGOCAIRO_CFLAGS = @PANGOCAIRO_CFLAGS@
+PANGOCAIRO_LIBS = @PANGOCAIRO_LIBS@
+PANGOCAIRO_REQUIRED_VERSION = @PANGOCAIRO_REQUIRED_VERSION@
+PATHSEP = @PATHSEP@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PERL = @PERL@
+PERL_REQUIRED_VERSION = @PERL_REQUIRED_VERSION@
+PERL_VERSION = @PERL_VERSION@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PNG_CFLAGS = @PNG_CFLAGS@
+PNG_LIBS = @PNG_LIBS@
+POFILES = @POFILES@
+POPPLER_CFLAGS = @POPPLER_CFLAGS@
+POPPLER_DATA_CFLAGS = @POPPLER_DATA_CFLAGS@
+POPPLER_DATA_LIBS = @POPPLER_DATA_LIBS@
+POPPLER_DATA_REQUIRED_VERSION = @POPPLER_DATA_REQUIRED_VERSION@
+POPPLER_LIBS = @POPPLER_LIBS@
+POPPLER_REQUIRED_VERSION = @POPPLER_REQUIRED_VERSION@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+PYBIN_PATH = @PYBIN_PATH@
+PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@
+PYCAIRO_LIBS = @PYCAIRO_LIBS@
+PYGIMP_EXTRA_CFLAGS = @PYGIMP_EXTRA_CFLAGS@
+PYGTK_CFLAGS = @PYGTK_CFLAGS@
+PYGTK_CODEGEN = @PYGTK_CODEGEN@
+PYGTK_DEFSDIR = @PYGTK_DEFSDIR@
+PYGTK_LIBS = @PYGTK_LIBS@
+PYLINK_LIBS = @PYLINK_LIBS@
+PYTHON = @PYTHON@
+PYTHON2_REQUIRED_VERSION = @PYTHON2_REQUIRED_VERSION@
+PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
+PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_PLATFORM = @PYTHON_PLATFORM@
+PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_VERSION = @PYTHON_VERSION@
+RANLIB = @RANLIB@
+RSVG_REQUIRED_VERSION = @RSVG_REQUIRED_VERSION@
+RT_LIBS = @RT_LIBS@
+SCREENSHOT_LIBS = @SCREENSHOT_LIBS@
+SED = @SED@
+SENDMAIL = @SENDMAIL@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SOCKET_LIBS = @SOCKET_LIBS@
+SSE2_EXTRA_CFLAGS = @SSE2_EXTRA_CFLAGS@
+SSE4_1_EXTRA_CFLAGS = @SSE4_1_EXTRA_CFLAGS@
+SSE_EXTRA_CFLAGS = @SSE_EXTRA_CFLAGS@
+STRIP = @STRIP@
+SVG_CFLAGS = @SVG_CFLAGS@
+SVG_LIBS = @SVG_LIBS@
+SYMPREFIX = @SYMPREFIX@
+TIFF_LIBS = @TIFF_LIBS@
+USE_NLS = @USE_NLS@
+VERSION = @VERSION@
+WEBKIT_CFLAGS = @WEBKIT_CFLAGS@
+WEBKIT_LIBS = @WEBKIT_LIBS@
+WEBKIT_REQUIRED_VERSION = @WEBKIT_REQUIRED_VERSION@
+WEBPDEMUX_CFLAGS = @WEBPDEMUX_CFLAGS@
+WEBPDEMUX_LIBS = @WEBPDEMUX_LIBS@
+WEBPMUX_CFLAGS = @WEBPMUX_CFLAGS@
+WEBPMUX_LIBS = @WEBPMUX_LIBS@
+WEBP_CFLAGS = @WEBP_CFLAGS@
+WEBP_LIBS = @WEBP_LIBS@
+WEBP_REQUIRED_VERSION = @WEBP_REQUIRED_VERSION@
+WEB_PAGE = @WEB_PAGE@
+WIN32_LARGE_ADDRESS_AWARE = @WIN32_LARGE_ADDRESS_AWARE@
+WINDRES = @WINDRES@
+WMF_CFLAGS = @WMF_CFLAGS@
+WMF_CONFIG = @WMF_CONFIG@
+WMF_LIBS = @WMF_LIBS@
+WMF_REQUIRED_VERSION = @WMF_REQUIRED_VERSION@
+XDG_EMAIL = @XDG_EMAIL@
+XFIXES_CFLAGS = @XFIXES_CFLAGS@
+XFIXES_LIBS = @XFIXES_LIBS@
+XGETTEXT = @XGETTEXT@
+XGETTEXT_REQUIRED_VERSION = @XGETTEXT_REQUIRED_VERSION@
+XMC_CFLAGS = @XMC_CFLAGS@
+XMC_LIBS = @XMC_LIBS@
+XMKMF = @XMKMF@
+XMLLINT = @XMLLINT@
+XMU_LIBS = @XMU_LIBS@
+XPM_LIBS = @XPM_LIBS@
+XSLTPROC = @XSLTPROC@
+XVFB_RUN = @XVFB_RUN@
+X_CFLAGS = @X_CFLAGS@
+X_EXTRA_LIBS = @X_EXTRA_LIBS@
+X_LIBS = @X_LIBS@
+X_PRE_LIBS = @X_PRE_LIBS@
+Z_LIBS = @Z_LIBS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CC_FOR_BUILD = @ac_ct_CC_FOR_BUILD@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+gimpdatadir = @gimpdatadir@
+gimpdir = @gimpdir@
+gimplocaledir = @gimplocaledir@
+gimpplugindir = @gimpplugindir@
+gimpsysconfdir = @gimpsysconfdir@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+intltool__v_merge_options_ = @intltool__v_merge_options_@
+intltool__v_merge_options_0 = @intltool__v_merge_options_0@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+manpage_gimpdir = @manpage_gimpdir@
+mkdir_p = @mkdir_p@
+ms_librarian = @ms_librarian@
+mypaint_brushes_dir = @mypaint_brushes_dir@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pkgpyexecdir = @pkgpyexecdir@
+pkgpythondir = @pkgpythondir@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+pyexecdir = @pyexecdir@
+pythondir = @pythondir@
+runstatedir = @runstatedir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+@PLATFORM_WIN32_TRUE@no_undefined = -no-undefined
+@PLATFORM_WIN32_FALSE@libm = -lm
+@OS_WIN32_TRUE@gimpcolor_def = gimpcolor.def
+@OS_WIN32_TRUE@libgimpcolor_export_symbols = -export-symbols $(srcdir)/gimpcolor.def
+@MS_LIB_AVAILABLE_TRUE@noinst_DATA = gimpcolor-$(GIMP_API_VERSION).lib
+libgimpcolorincludedir = $(includedir)/gimp-$(GIMP_API_VERSION)/libgimpcolor
+AM_CPPFLAGS = \
+ -DG_LOG_DOMAIN=\"LibGimpColor\" \
+ -DGIMP_COLOR_COMPILATION \
+ -I$(top_srcdir) \
+ $(GEGL_CFLAGS) \
+ $(CAIRO_CFLAGS) \
+ $(GDK_PIXBUF_CFLAGS) \
+ $(LCMS_CFLAGS) \
+ -I$(includedir)
+
+EXTRA_DIST = \
+ gimpcolor.def
+
+lib_LTLIBRARIES = libgimpcolor-@GIMP_API_VERSION@.la
+libgimpcolor_@GIMP_API_VERSION@_la_SOURCES = \
+ gimpcolor.h \
+ gimpcolortypes.h \
+ gimpadaptivesupersample.c \
+ gimpadaptivesupersample.h \
+ gimpbilinear.c \
+ gimpbilinear.h \
+ gimpcairo.c \
+ gimpcairo.h \
+ gimpcmyk.c \
+ gimpcmyk.h \
+ gimpcolormanaged.c \
+ gimpcolormanaged.h \
+ gimpcolorprofile.c \
+ gimpcolorprofile.h \
+ gimpcolorspace.c \
+ gimpcolorspace.h \
+ gimpcolortransform.c \
+ gimpcolortransform.h \
+ gimphsl.c \
+ gimphsl.h \
+ gimphsv.c \
+ gimphsv.h \
+ gimppixbuf.c \
+ gimppixbuf.h \
+ gimprgb.c \
+ gimprgb.h \
+ gimprgb-parse.c
+
+libgimpcolorinclude_HEADERS = \
+ gimpcolor.h \
+ gimpcolortypes.h \
+ gimpadaptivesupersample.h \
+ gimpbilinear.h \
+ gimpcairo.h \
+ gimpcmyk.h \
+ gimpcolormanaged.h \
+ gimpcolorprofile.h \
+ gimpcolorspace.h \
+ gimpcolortransform.h \
+ gimphsl.h \
+ gimphsv.h \
+ gimppixbuf.h \
+ gimprgb.h
+
+libgimpcolor_@GIMP_API_VERSION@_la_LDFLAGS = \
+ -version-info $(LT_VERSION_INFO) \
+ $(no_undefined) \
+ $(libgimpcolor_export_symbols)
+
+EXTRA_libgimpcolor_@GIMP_API_VERSION@_la_DEPENDENCIES = $(gimpcolor_def)
+libgimpcolor_@GIMP_API_VERSION@_la_LIBADD = \
+ $(libgimpbase) \
+ $(GEGL_LIBS) \
+ $(CAIRO_LIBS) \
+ $(GDK_PIXBUF_LIBS) \
+ $(LCMS_LIBS) \
+ $(libm)
+
+
+#
+# test programs, not to be built by default and never installed
+#
+TESTS = test-color-parser$(EXEEXT)
+test_color_parser_DEPENDENCIES = \
+ $(libgimpbase) \
+ $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+
+test_color_parser_LDADD = \
+ $(CAIRO_LIBS) \
+ $(GLIB_LIBS) \
+ $(test_color_parser_DEPENDENCIES)
+
+CLEANFILES = $(EXTRA_PROGRAMS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu libgimpcolor/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --gnu libgimpcolor/Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-libLTLIBRARIES: $(lib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
+ }
+
+uninstall-libLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \
+ done
+
+clean-libLTLIBRARIES:
+ -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES)
+ @list='$(lib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgimpcolor-@GIMP_API_VERSION@.la: $(libgimpcolor_@GIMP_API_VERSION@_la_OBJECTS) $(libgimpcolor_@GIMP_API_VERSION@_la_DEPENDENCIES) $(EXTRA_libgimpcolor_@GIMP_API_VERSION@_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libgimpcolor_@GIMP_API_VERSION@_la_LINK) -rpath $(libdir) $(libgimpcolor_@GIMP_API_VERSION@_la_OBJECTS) $(libgimpcolor_@GIMP_API_VERSION@_la_LIBADD) $(LIBS)
+
+test-color-parser$(EXEEXT): $(test_color_parser_OBJECTS) $(test_color_parser_DEPENDENCIES) $(EXTRA_test_color_parser_DEPENDENCIES)
+ @rm -f test-color-parser$(EXEEXT)
+ $(AM_V_CCLD)$(LINK) $(test_color_parser_OBJECTS) $(test_color_parser_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpadaptivesupersample.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpbilinear.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpcairo.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpcmyk.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpcolormanaged.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpcolorprofile.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpcolorspace.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpcolortransform.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimphsl.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimphsv.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimppixbuf.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimprgb-parse.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimprgb.Plo@am__quote@ # am--include-marker
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-color-parser.Po@am__quote@ # am--include-marker
+
+$(am__depfiles_remade):
+ @$(MKDIR_P) $(@D)
+ @echo '# dummy' >$@-t && $(am__mv) $@-t $@
+
+am--depfiles: $(am__depfiles_remade)
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $<
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-libgimpcolorincludeHEADERS: $(libgimpcolorinclude_HEADERS)
+ @$(NORMAL_INSTALL)
+ @list='$(libgimpcolorinclude_HEADERS)'; test -n "$(libgimpcolorincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(libgimpcolorincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(libgimpcolorincludedir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(libgimpcolorincludedir)'"; \
+ $(INSTALL_HEADER) $$files "$(DESTDIR)$(libgimpcolorincludedir)" || exit $$?; \
+ done
+
+uninstall-libgimpcolorincludeHEADERS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(libgimpcolorinclude_HEADERS)'; test -n "$(libgimpcolorincludedir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(libgimpcolorincludedir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ elif test -n "$$redo_logs"; then \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary"$(AM_TESTSUITE_SUMMARY_HEADER)"$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+test-color-parser.log: test-color-parser$(EXEEXT)
+ @p='test-color-parser$(EXEEXT)'; \
+ b='test-color-parser'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) distdir-am
+
+distdir-am: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA) $(HEADERS)
+installdirs:
+ for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(libgimpcolorincludedir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -f ./$(DEPDIR)/gimpadaptivesupersample.Plo
+ -rm -f ./$(DEPDIR)/gimpbilinear.Plo
+ -rm -f ./$(DEPDIR)/gimpcairo.Plo
+ -rm -f ./$(DEPDIR)/gimpcmyk.Plo
+ -rm -f ./$(DEPDIR)/gimpcolormanaged.Plo
+ -rm -f ./$(DEPDIR)/gimpcolorprofile.Plo
+ -rm -f ./$(DEPDIR)/gimpcolorspace.Plo
+ -rm -f ./$(DEPDIR)/gimpcolortransform.Plo
+ -rm -f ./$(DEPDIR)/gimphsl.Plo
+ -rm -f ./$(DEPDIR)/gimphsv.Plo
+ -rm -f ./$(DEPDIR)/gimppixbuf.Plo
+ -rm -f ./$(DEPDIR)/gimprgb-parse.Plo
+ -rm -f ./$(DEPDIR)/gimprgb.Plo
+ -rm -f ./$(DEPDIR)/test-color-parser.Po
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-data-local install-libgimpcolorincludeHEADERS
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-libLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f ./$(DEPDIR)/gimpadaptivesupersample.Plo
+ -rm -f ./$(DEPDIR)/gimpbilinear.Plo
+ -rm -f ./$(DEPDIR)/gimpcairo.Plo
+ -rm -f ./$(DEPDIR)/gimpcmyk.Plo
+ -rm -f ./$(DEPDIR)/gimpcolormanaged.Plo
+ -rm -f ./$(DEPDIR)/gimpcolorprofile.Plo
+ -rm -f ./$(DEPDIR)/gimpcolorspace.Plo
+ -rm -f ./$(DEPDIR)/gimpcolortransform.Plo
+ -rm -f ./$(DEPDIR)/gimphsl.Plo
+ -rm -f ./$(DEPDIR)/gimphsv.Plo
+ -rm -f ./$(DEPDIR)/gimppixbuf.Plo
+ -rm -f ./$(DEPDIR)/gimprgb-parse.Plo
+ -rm -f ./$(DEPDIR)/gimprgb.Plo
+ -rm -f ./$(DEPDIR)/test-color-parser.Po
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-libLTLIBRARIES \
+ uninstall-libgimpcolorincludeHEADERS uninstall-local
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \
+ check-am clean clean-generic clean-libLTLIBRARIES \
+ clean-libtool cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am \
+ install-data-local install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-libLTLIBRARIES \
+ install-libgimpcolorincludeHEADERS install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-strip \
+ installcheck installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ recheck tags tags-am uninstall uninstall-am \
+ uninstall-libLTLIBRARIES uninstall-libgimpcolorincludeHEADERS \
+ uninstall-local
+
+.PRECIOUS: Makefile
+
+
+@OS_WIN32_TRUE@install-libtool-import-lib:
+@OS_WIN32_TRUE@ $(INSTALL) .libs/libgimpcolor-$(GIMP_API_VERSION).dll.a $(DESTDIR)$(libdir)
+@OS_WIN32_TRUE@ $(INSTALL) $(srcdir)/gimpcolor.def $(DESTDIR)$(libdir)
+
+@OS_WIN32_TRUE@uninstall-libtool-import-lib:
+@OS_WIN32_TRUE@ -rm $(DESTDIR)$(libdir)/libgimpcolor-$(GIMP_API_VERSION).dll.a
+@OS_WIN32_TRUE@ -rm $(DESTDIR)$(libdir)/gimpcolor.def
+@OS_WIN32_FALSE@install-libtool-import-lib:
+@OS_WIN32_FALSE@uninstall-libtool-import-lib:
+
+@MS_LIB_AVAILABLE_TRUE@install-ms-lib:
+@MS_LIB_AVAILABLE_TRUE@ $(INSTALL) gimpcolor-$(GIMP_API_VERSION).lib $(DESTDIR)$(libdir)
+
+@MS_LIB_AVAILABLE_TRUE@uninstall-ms-lib:
+@MS_LIB_AVAILABLE_TRUE@ -rm $(DESTDIR)$(libdir)/gimpcolor-$(GIMP_API_VERSION).lib
+
+@MS_LIB_AVAILABLE_TRUE@gimpcolor-@GIMP_API_VERSION@.lib: gimpcolor.def
+@MS_LIB_AVAILABLE_TRUE@ lib -name:libgimpcolor-$(GIMP_API_VERSION)-@LT_CURRENT_MINUS_AGE@.dll -def:gimpcolor.def -out:$@
+
+@MS_LIB_AVAILABLE_FALSE@install-ms-lib:
+@MS_LIB_AVAILABLE_FALSE@uninstall-ms-lib:
+
+install-data-local: install-ms-lib install-libtool-import-lib
+
+uninstall-local: uninstall-ms-lib uninstall-libtool-import-lib
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
diff --git a/libgimpcolor/gimpadaptivesupersample.c b/libgimpcolor/gimpadaptivesupersample.c
new file mode 100644
index 0000000..3b9bedc
--- /dev/null
+++ b/libgimpcolor/gimpadaptivesupersample.c
@@ -0,0 +1,394 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <glib-object.h>
+
+#include "libgimpmath/gimpmath.h"
+
+#include "gimpcolortypes.h"
+
+#include "gimpadaptivesupersample.h"
+#include "gimprgb.h"
+
+
+/**
+ * SECTION: gimpadaptivesupersample
+ * @title: GimpAdaptiveSupersample
+ * @short_description: Functions to perform adaptive supersampling on
+ * an area.
+ *
+ * Functions to perform adaptive supersampling on an area.
+ **/
+
+
+/*********************************************************************/
+/* Sumpersampling code (Quartic) */
+/* This code is *largely* based on the sources for POV-Ray 3.0. I am */
+/* grateful to the POV-Team for such a great program and for making */
+/* their sources available. All comments / bug reports / */
+/* etc. regarding this code should be addressed to me, not to the */
+/* POV-Ray team. Any bugs are my responsibility, not theirs. */
+/*********************************************************************/
+
+
+typedef struct _GimpSampleType GimpSampleType;
+
+struct _GimpSampleType
+{
+ guchar ready;
+ GimpRGB color;
+};
+
+
+static gulong
+gimp_render_sub_pixel (gint max_depth,
+ gint depth,
+ GimpSampleType **block,
+ gint x,
+ gint y,
+ gint x1,
+ gint y1,
+ gint x3,
+ gint y3,
+ gdouble threshold,
+ gint sub_pixel_size,
+ GimpRGB *color,
+ GimpRenderFunc render_func,
+ gpointer render_data)
+{
+ gint x2, y2; /* Coords of center sample */
+ gdouble dx1, dy1; /* Delta to upper left sample */
+ gdouble dx3, dy3; /* Delta to lower right sample */
+ GimpRGB c[4]; /* Sample colors */
+ gulong num_samples = 0;
+ gint cnt;
+
+ g_return_val_if_fail (render_func != NULL, 0);
+
+ /* Get offsets for corners */
+
+ dx1 = (gdouble) (x1 - sub_pixel_size / 2) / sub_pixel_size;
+ dx3 = (gdouble) (x3 - sub_pixel_size / 2) / sub_pixel_size;
+
+ dy1 = (gdouble) (y1 - sub_pixel_size / 2) / sub_pixel_size;
+ dy3 = (gdouble) (y3 - sub_pixel_size / 2) / sub_pixel_size;
+
+ /* Render upper left sample */
+
+ if (! block[y1][x1].ready)
+ {
+ num_samples++;
+
+ render_func (x + dx1, y + dy1, &c[0], render_data);
+
+ block[y1][x1].ready = TRUE;
+ block[y1][x1].color = c[0];
+ }
+ else
+ {
+ c[0] = block[y1][x1].color;
+ }
+
+ /* Render upper right sample */
+
+ if (! block[y1][x3].ready)
+ {
+ num_samples++;
+
+ render_func (x + dx3, y + dy1, &c[1], render_data);
+
+ block[y1][x3].ready = TRUE;
+ block[y1][x3].color = c[1];
+ }
+ else
+ {
+ c[1] = block[y1][x3].color;
+ }
+
+ /* Render lower left sample */
+
+ if (! block[y3][x1].ready)
+ {
+ num_samples++;
+
+ render_func (x + dx1, y + dy3, &c[2], render_data);
+
+ block[y3][x1].ready = TRUE;
+ block[y3][x1].color = c[2];
+ }
+ else
+ {
+ c[2] = block[y3][x1].color;
+ }
+
+ /* Render lower right sample */
+
+ if (! block[y3][x3].ready)
+ {
+ num_samples++;
+
+ render_func (x + dx3, y + dy3, &c[3], render_data);
+
+ block[y3][x3].ready = TRUE;
+ block[y3][x3].color = c[3];
+ }
+ else
+ {
+ c[3] = block[y3][x3].color;
+ }
+
+ /* Check for supersampling */
+
+ if (depth <= max_depth)
+ {
+ /* Check whether we have to supersample */
+
+ if ((gimp_rgba_distance (&c[0], &c[1]) >= threshold) ||
+ (gimp_rgba_distance (&c[0], &c[2]) >= threshold) ||
+ (gimp_rgba_distance (&c[0], &c[3]) >= threshold) ||
+ (gimp_rgba_distance (&c[1], &c[2]) >= threshold) ||
+ (gimp_rgba_distance (&c[1], &c[3]) >= threshold) ||
+ (gimp_rgba_distance (&c[2], &c[3]) >= threshold))
+ {
+ /* Calc coordinates of center subsample */
+
+ x2 = (x1 + x3) / 2;
+ y2 = (y1 + y3) / 2;
+
+ /* Render sub-blocks */
+
+ num_samples += gimp_render_sub_pixel (max_depth, depth + 1, block,
+ x, y, x1, y1, x2, y2,
+ threshold, sub_pixel_size,
+ &c[0],
+ render_func, render_data);
+
+ num_samples += gimp_render_sub_pixel (max_depth, depth + 1, block,
+ x, y, x2, y1, x3, y2,
+ threshold, sub_pixel_size,
+ &c[1],
+ render_func, render_data);
+
+ num_samples += gimp_render_sub_pixel (max_depth, depth + 1, block,
+ x, y, x1, y2, x2, y3,
+ threshold, sub_pixel_size,
+ &c[2],
+ render_func, render_data);
+
+ num_samples += gimp_render_sub_pixel (max_depth, depth + 1, block,
+ x, y, x2, y2, x3, y3,
+ threshold, sub_pixel_size,
+ &c[3],
+ render_func, render_data);
+ }
+ }
+
+ if (c[0].a == 0.0 || c[1].a == 0.0 || c[2].a == 0.0 || c[3].a == 0.0)
+ {
+ GimpRGB tmpcol;
+ gdouble weight;
+
+ gimp_rgb_set (&tmpcol, 0.0, 0.0, 0.0);
+
+ weight = 2.0;
+
+ for (cnt = 0; cnt < 4; cnt++)
+ {
+ if (c[cnt].a != 0.0)
+ {
+ tmpcol.r += c[cnt].r;
+ tmpcol.g += c[cnt].g;
+ tmpcol.b += c[cnt].b;
+
+ weight /= 2.0;
+ }
+ }
+
+ color->r = weight * tmpcol.r;
+ color->g = weight * tmpcol.g;
+ color->b = weight * tmpcol.b;
+ }
+ else
+ {
+ color->r = 0.25 * (c[0].r + c[1].r + c[2].r + c[3].r);
+ color->g = 0.25 * (c[0].g + c[1].g + c[2].g + c[3].g);
+ color->b = 0.25 * (c[0].b + c[1].b + c[2].b + c[3].b);
+ }
+
+ color->a = 0.25 * (c[0].a + c[1].a + c[2].a + c[3].a);
+
+ return num_samples;
+}
+
+gulong
+gimp_adaptive_supersample_area (gint x1,
+ gint y1,
+ gint x2,
+ gint y2,
+ gint max_depth,
+ gdouble threshold,
+ GimpRenderFunc render_func,
+ gpointer render_data,
+ GimpPutPixelFunc put_pixel_func,
+ gpointer put_pixel_data,
+ GimpProgressFunc progress_func,
+ gpointer progress_data)
+{
+ gint x, y, width; /* Counters, width of region */
+ gint xt, xtt, yt; /* Temporary counters */
+ gint sub_pixel_size; /* Number of samples per pixel (1D) */
+ GimpRGB color; /* Rendered pixel's color */
+ GimpSampleType tmp_sample; /* For swapping samples */
+ GimpSampleType *top_row, *bot_row, *tmp_row; /* Sample rows */
+ GimpSampleType **block; /* Sample block matrix */
+ gulong num_samples;
+
+ g_return_val_if_fail (render_func != NULL, 0);
+ g_return_val_if_fail (put_pixel_func != NULL, 0);
+
+ /* Initialize color */
+
+ gimp_rgba_set (&color, 0.0, 0.0, 0.0, 0.0);
+
+ /* Calculate sub-pixel size */
+
+ sub_pixel_size = 1 << max_depth;
+
+ /* Create row arrays */
+
+ width = x2 - x1 + 1;
+
+ top_row = gegl_scratch_new (GimpSampleType, sub_pixel_size * width + 1);
+ bot_row = gegl_scratch_new (GimpSampleType, sub_pixel_size * width + 1);
+
+ for (x = 0; x < (sub_pixel_size * width + 1); x++)
+ {
+ top_row[x].ready = FALSE;
+
+ gimp_rgba_set (&top_row[x].color, 0.0, 0.0, 0.0, 0.0);
+
+ bot_row[x].ready = FALSE;
+
+ gimp_rgba_set (&bot_row[x].color, 0.0, 0.0, 0.0, 0.0);
+ }
+
+ /* Allocate block matrix */
+
+ block = gegl_scratch_new (GimpSampleType *, sub_pixel_size + 1); /* Rows */
+
+ for (y = 0; y < (sub_pixel_size + 1); y++)
+ {
+ block[y] = gegl_scratch_new (GimpSampleType, sub_pixel_size + 1); /* Columns */
+
+ for (x = 0; x < (sub_pixel_size + 1); x++)
+ {
+ block[y][x].ready = FALSE;
+
+ gimp_rgba_set (&block[y][x].color, 0.0, 0.0, 0.0, 0.0);
+ }
+ }
+
+ /* Render region */
+
+ num_samples = 0;
+
+ for (y = y1; y <= y2; y++)
+ {
+ /* Clear the bottom row */
+
+ for (xt = 0; xt < (sub_pixel_size * width + 1); xt++)
+ bot_row[xt].ready = FALSE;
+
+ /* Clear first column */
+
+ for (yt = 0; yt < (sub_pixel_size + 1); yt++)
+ block[yt][0].ready = FALSE;
+
+ /* Render row */
+
+ for (x = x1; x <= x2; x++)
+ {
+ /* Initialize block by clearing all but first row/column */
+
+ for (yt = 1; yt < (sub_pixel_size + 1); yt++)
+ for (xt = 1; xt < (sub_pixel_size + 1); xt++)
+ block[yt][xt].ready = FALSE;
+
+ /* Copy samples from top row to block */
+
+ for (xtt = 0, xt = (x - x1) * sub_pixel_size;
+ xtt < (sub_pixel_size + 1);
+ xtt++, xt++)
+ block[0][xtt] = top_row[xt];
+
+ /* Render pixel on (x, y) */
+
+ num_samples += gimp_render_sub_pixel (max_depth, 1, block, x, y, 0, 0,
+ sub_pixel_size, sub_pixel_size,
+ threshold, sub_pixel_size,
+ &color,
+ render_func, render_data);
+
+ if (put_pixel_func)
+ (* put_pixel_func) (x, y, &color, put_pixel_data);
+
+ /* Copy block information to rows */
+
+ top_row[(x - x1 + 1) * sub_pixel_size] = block[0][sub_pixel_size];
+
+ for (xtt = 0, xt = (x - x1) * sub_pixel_size;
+ xtt < (sub_pixel_size + 1);
+ xtt++, xt++)
+ bot_row[xt] = block[sub_pixel_size][xtt];
+
+ /* Swap first and last columns */
+
+ for (yt = 0; yt < (sub_pixel_size + 1); yt++)
+ {
+ tmp_sample = block[yt][0];
+ block[yt][0] = block[yt][sub_pixel_size];
+ block[yt][sub_pixel_size] = tmp_sample;
+ }
+ }
+
+ /* Swap rows */
+
+ tmp_row = top_row;
+ top_row = bot_row;
+ bot_row = tmp_row;
+
+ /* Call progress display function (if any) */
+
+ if (progress_func != NULL)
+ (* progress_func) (y1, y2, y, progress_data);
+ }
+
+ /* Free memory */
+
+ for (y = 0; y < (sub_pixel_size + 1); y++)
+ gegl_scratch_free (block[y]);
+
+ gegl_scratch_free (block);
+ gegl_scratch_free (top_row);
+ gegl_scratch_free (bot_row);
+
+ return num_samples;
+}
diff --git a/libgimpcolor/gimpadaptivesupersample.h b/libgimpcolor/gimpadaptivesupersample.h
new file mode 100644
index 0000000..fdee486
--- /dev/null
+++ b/libgimpcolor/gimpadaptivesupersample.h
@@ -0,0 +1,50 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_ADAPTIVE_SUPERSAMPLE_H__
+#define __GIMP_ADAPTIVE_SUPERSAMPLE_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+/* adaptive supersampling function taken from LibGCK */
+
+
+gulong gimp_adaptive_supersample_area (gint x1,
+ gint y1,
+ gint x2,
+ gint y2,
+ gint max_depth,
+ gdouble threshold,
+ GimpRenderFunc render_func,
+ gpointer render_data,
+ GimpPutPixelFunc put_pixel_func,
+ gpointer put_pixel_data,
+ GimpProgressFunc progress_func,
+ gpointer progress_data);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_ADAPTIVE_SUPERSAMPLE_H__ */
diff --git a/libgimpcolor/gimpbilinear.c b/libgimpcolor/gimpbilinear.c
new file mode 100644
index 0000000..1de06b6
--- /dev/null
+++ b/libgimpcolor/gimpbilinear.c
@@ -0,0 +1,313 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+
+#include "libgimpmath/gimpmath.h"
+
+#include "gimpcolortypes.h"
+
+#include "gimpbilinear.h"
+
+
+/**
+ * SECTION: gimpbilinear
+ * @title: GimpBilinear
+ * @short_description: Utility functions for bilinear interpolation.
+ *
+ * Utility functions for bilinear interpolation.
+ **/
+
+
+gdouble
+gimp_bilinear (gdouble x,
+ gdouble y,
+ gdouble *values)
+{
+ gdouble m0, m1;
+
+ g_return_val_if_fail (values != NULL, 0.0);
+
+ x = fmod (x, 1.0);
+ y = fmod (y, 1.0);
+
+ if (x < 0.0)
+ x += 1.0;
+ if (y < 0.0)
+ y += 1.0;
+
+ m0 = (1.0 - x) * values[0] + x * values[1];
+ m1 = (1.0 - x) * values[2] + x * values[3];
+
+ return (1.0 - y) * m0 + y * m1;
+}
+
+guchar
+gimp_bilinear_8 (gdouble x,
+ gdouble y,
+ guchar *values)
+{
+ gdouble m0, m1;
+
+ g_return_val_if_fail (values != NULL, 0);
+
+ x = fmod (x, 1.0);
+ y = fmod (y, 1.0);
+
+ if (x < 0.0)
+ x += 1.0;
+ if (y < 0.0)
+ y += 1.0;
+
+ m0 = (1.0 - x) * values[0] + x * values[1];
+ m1 = (1.0 - x) * values[2] + x * values[3];
+
+ return (guchar) ((1.0 - y) * m0 + y * m1);
+}
+
+guint16
+gimp_bilinear_16 (gdouble x,
+ gdouble y,
+ guint16 *values)
+{
+ gdouble m0, m1;
+
+ g_return_val_if_fail (values != NULL, 0);
+
+ x = fmod (x, 1.0);
+ y = fmod (y, 1.0);
+
+ if (x < 0.0)
+ x += 1.0;
+ if (y < 0.0)
+ y += 1.0;
+
+ m0 = (1.0 - x) * values[0] + x * values[1];
+ m1 = (1.0 - x) * values[2] + x * values[3];
+
+ return (guint16) ((1.0 - y) * m0 + y * m1);
+}
+
+guint32
+gimp_bilinear_32 (gdouble x,
+ gdouble y,
+ guint32 *values)
+{
+ gdouble m0, m1;
+
+ g_return_val_if_fail (values != NULL, 0);
+
+ x = fmod (x, 1.0);
+ y = fmod (y, 1.0);
+
+ if (x < 0.0)
+ x += 1.0;
+ if (y < 0.0)
+ y += 1.0;
+
+ m0 = (1.0 - x) * values[0] + x * values[1];
+ m1 = (1.0 - x) * values[2] + x * values[3];
+
+ return (guint32) ((1.0 - y) * m0 + y * m1);
+}
+
+GimpRGB
+gimp_bilinear_rgb (gdouble x,
+ gdouble y,
+ GimpRGB *values)
+{
+ gdouble m0, m1;
+ gdouble ix, iy;
+ GimpRGB v = { 0, };
+
+ g_return_val_if_fail (values != NULL, v);
+
+ x = fmod(x, 1.0);
+ y = fmod(y, 1.0);
+
+ if (x < 0)
+ x += 1.0;
+ if (y < 0)
+ y += 1.0;
+
+ ix = 1.0 - x;
+ iy = 1.0 - y;
+
+ /* Red */
+
+ m0 = ix * values[0].r + x * values[1].r;
+ m1 = ix * values[2].r + x * values[3].r;
+
+ v.r = iy * m0 + y * m1;
+
+ /* Green */
+
+ m0 = ix * values[0].g + x * values[1].g;
+ m1 = ix * values[2].g + x * values[3].g;
+
+ v.g = iy * m0 + y * m1;
+
+ /* Blue */
+
+ m0 = ix * values[0].b + x * values[1].b;
+ m1 = ix * values[2].b + x * values[3].b;
+
+ v.b = iy * m0 + y * m1;
+
+ return v;
+}
+
+GimpRGB
+gimp_bilinear_rgba (gdouble x,
+ gdouble y,
+ GimpRGB *values)
+{
+ gdouble m0, m1;
+ gdouble ix, iy;
+ gdouble a0, a1, a2, a3, alpha;
+ GimpRGB v = { 0, };
+
+ g_return_val_if_fail (values != NULL, v);
+
+ x = fmod (x, 1.0);
+ y = fmod (y, 1.0);
+
+ if (x < 0)
+ x += 1.0;
+ if (y < 0)
+ y += 1.0;
+
+ ix = 1.0 - x;
+ iy = 1.0 - y;
+
+ a0 = values[0].a;
+ a1 = values[1].a;
+ a2 = values[2].a;
+ a3 = values[3].a;
+
+ /* Alpha */
+
+ m0 = ix * a0 + x * a1;
+ m1 = ix * a2 + x * a3;
+
+ alpha = v.a = iy * m0 + y * m1;
+
+ if (alpha > 0)
+ {
+ /* Red */
+
+ m0 = ix * a0 * values[0].r + x * a1 * values[1].r;
+ m1 = ix * a2 * values[2].r + x * a3 * values[3].r;
+
+ v.r = (iy * m0 + y * m1)/alpha;
+
+ /* Green */
+
+ m0 = ix * a0 * values[0].g + x * a1 * values[1].g;
+ m1 = ix * a2 * values[2].g + x * a3 * values[3].g;
+
+ v.g = (iy * m0 + y * m1)/alpha;
+
+ /* Blue */
+
+ m0 = ix * a0 * values[0].b + x * a1 * values[1].b;
+ m1 = ix * a2 * values[2].b + x * a3 * values[3].b;
+
+ v.b = (iy * m0 + y * m1)/alpha;
+ }
+
+ return v;
+}
+
+/**
+ * gimp_bilinear_pixels_8:
+ * @dest: Pixel, where interpolation result is to be stored.
+ * @x: x-coordinate (0.0 to 1.0).
+ * @y: y-coordinate (0.0 to 1.0).
+ * @bpp: Bytes per pixel. @dest and each @values item is an array of
+ * @bpp bytes.
+ * @has_alpha: %TRUE if the last channel is an alpha channel.
+ * @values: Array of four pointers to pixels.
+ *
+ * Computes bilinear interpolation of four pixels.
+ *
+ * When @has_alpha is %FALSE, it's identical to gimp_bilinear_8() on
+ * each channel separately. When @has_alpha is %TRUE, it handles
+ * alpha channel correctly.
+ *
+ * The pixels in @values correspond to corner x, y coordinates in the
+ * following order: [0,0], [1,0], [0,1], [1,1].
+ **/
+void
+gimp_bilinear_pixels_8 (guchar *dest,
+ gdouble x,
+ gdouble y,
+ guint bpp,
+ gboolean has_alpha,
+ guchar **values)
+{
+ guint i;
+
+ g_return_if_fail (dest != NULL);
+ g_return_if_fail (values != NULL);
+
+ x = fmod (x, 1.0);
+ y = fmod (y, 1.0);
+
+ if (x < 0.0)
+ x += 1.0;
+ if (y < 0.0)
+ y += 1.0;
+
+ if (has_alpha)
+ {
+ guint ai = bpp - 1;
+ gdouble alpha0 = values[0][ai];
+ gdouble alpha1 = values[1][ai];
+ gdouble alpha2 = values[2][ai];
+ gdouble alpha3 = values[3][ai];
+ gdouble alpha = ((1.0 - y) * ((1.0 - x) * alpha0 + x * alpha1)
+ + y * ((1.0 - x) * alpha2 + x * alpha3));
+
+ dest[ai] = (guchar) alpha;
+ if (dest[ai])
+ {
+ for (i = 0; i < ai; i++)
+ {
+ gdouble m0 = ((1.0 - x) * values[0][i] * alpha0
+ + x * values[1][i] * alpha1);
+ gdouble m1 = ((1.0 - x) * values[2][i] * alpha2
+ + x * values[3][i] * alpha3);
+
+ dest[i] = (guchar) (((1.0 - y) * m0 + y * m1) / alpha);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < bpp; i++)
+ {
+ gdouble m0 = (1.0 - x) * values[0][i] + x * values[1][i];
+ gdouble m1 = (1.0 - x) * values[2][i] + x * values[3][i];
+
+ dest[i] = (guchar) ((1.0 - y) * m0 + y * m1);
+ }
+ }
+}
diff --git a/libgimpcolor/gimpbilinear.h b/libgimpcolor/gimpbilinear.h
new file mode 100644
index 0000000..d56007c
--- /dev/null
+++ b/libgimpcolor/gimpbilinear.h
@@ -0,0 +1,63 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_BILINEAR_H__
+#define __GIMP_BILINEAR_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+/* bilinear interpolation functions taken from LibGCK */
+
+
+gdouble gimp_bilinear (gdouble x,
+ gdouble y,
+ gdouble *values);
+guchar gimp_bilinear_8 (gdouble x,
+ gdouble y,
+ guchar *values);
+guint16 gimp_bilinear_16 (gdouble x,
+ gdouble y,
+ guint16 *values);
+guint32 gimp_bilinear_32 (gdouble x,
+ gdouble y,
+ guint32 *values);
+GimpRGB gimp_bilinear_rgb (gdouble x,
+ gdouble y,
+ GimpRGB *values);
+GimpRGB gimp_bilinear_rgba (gdouble x,
+ gdouble y,
+ GimpRGB *values);
+
+GIMP_DEPRECATED
+void gimp_bilinear_pixels_8 (guchar *dest,
+ gdouble x,
+ gdouble y,
+ guint bpp,
+ gboolean has_alpha,
+ guchar **values);
+
+G_END_DECLS
+
+#endif /* __GIMP_BILINEAR_H__ */
diff --git a/libgimpcolor/gimpcairo.c b/libgimpcolor/gimpcairo.c
new file mode 100644
index 0000000..e1e57d9
--- /dev/null
+++ b/libgimpcolor/gimpcairo.c
@@ -0,0 +1,210 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpcairo.c
+ * Copyright (C) 2007 Sven Neumann <sven@gimp.org>
+ * 2010-2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <cairo.h>
+#include <gio/gio.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "gimpcolortypes.h"
+
+#include "gimpcairo.h"
+
+
+/**
+ * SECTION: gimpcairo
+ * @title: GimpCairo
+ * @short_description: Color utility functions for cairo
+ *
+ * Utility functions that make cairo easier to use with GIMP color
+ * data types.
+ **/
+
+
+/**
+ * gimp_cairo_set_source_rgb:
+ * @cr: Cairo context
+ * @color: GimpRGB color
+ *
+ * Sets the source pattern within @cr to the solid opaque color
+ * described by @color.
+ *
+ * This function calls cairo_set_source_rgb() for you.
+ *
+ * Since: 2.6
+ **/
+void
+gimp_cairo_set_source_rgb (cairo_t *cr,
+ const GimpRGB *color)
+{
+ cairo_set_source_rgb (cr, color->r, color->g, color->b);
+}
+
+/**
+ * gimp_cairo_set_source_rgba:
+ * @cr: Cairo context
+ * @color: GimpRGB color
+ *
+ * Sets the source pattern within @cr to the solid translucent color
+ * described by @color.
+ *
+ * This function calls cairo_set_source_rgba() for you.
+ *
+ * Since: 2.6
+ **/
+void
+gimp_cairo_set_source_rgba (cairo_t *cr,
+ const GimpRGB *color)
+{
+ cairo_set_source_rgba (cr, color->r, color->g, color->b, color->a);
+}
+
+/**
+ * gimp_cairo_checkerboard_create:
+ * @cr: Cairo context
+ * @size: check size
+ * @light: light check color or %NULL to use the default light gray
+ * @dark: dark check color or %NULL to use the default dark gray
+ *
+ * Create a repeating checkerboard pattern.
+ *
+ * Return value: a new Cairo pattern that can be used as a source on @cr.
+ *
+ * Since: 2.6
+ **/
+cairo_pattern_t *
+gimp_cairo_checkerboard_create (cairo_t *cr,
+ gint size,
+ const GimpRGB *light,
+ const GimpRGB *dark)
+{
+ cairo_t *context;
+ cairo_surface_t *surface;
+ cairo_pattern_t *pattern;
+
+ g_return_val_if_fail (cr != NULL, NULL);
+ g_return_val_if_fail (size > 0, NULL);
+
+ surface = cairo_surface_create_similar (cairo_get_target (cr),
+ CAIRO_CONTENT_COLOR,
+ 2 * size, 2 * size);
+ context = cairo_create (surface);
+
+ if (light)
+ gimp_cairo_set_source_rgb (context, light);
+ else
+ cairo_set_source_rgb (context,
+ GIMP_CHECK_LIGHT, GIMP_CHECK_LIGHT, GIMP_CHECK_LIGHT);
+
+ cairo_rectangle (context, 0, 0, size, size);
+ cairo_rectangle (context, size, size, size, size);
+ cairo_fill (context);
+
+ if (dark)
+ gimp_cairo_set_source_rgb (context, dark);
+ else
+ cairo_set_source_rgb (context,
+ GIMP_CHECK_DARK, GIMP_CHECK_DARK, GIMP_CHECK_DARK);
+
+ cairo_rectangle (context, 0, size, size, size);
+ cairo_rectangle (context, size, 0, size, size);
+ cairo_fill (context);
+
+ cairo_destroy (context);
+
+ pattern = cairo_pattern_create_for_surface (surface);
+ cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
+
+ cairo_surface_destroy (surface);
+
+ return pattern;
+}
+
+/**
+ * gimp_cairo_surface_get_format:
+ * @surface: a Cairo surface
+ *
+ * This function returns a #Babl format that corresponds to @surface's
+ * pixel format.
+ *
+ * Return value: the #Babl format of @surface.
+ *
+ * Since: 2.10
+ **/
+const Babl *
+gimp_cairo_surface_get_format (cairo_surface_t *surface)
+{
+ g_return_val_if_fail (surface != NULL, NULL);
+ g_return_val_if_fail (cairo_surface_get_type (surface) ==
+ CAIRO_SURFACE_TYPE_IMAGE, NULL);
+
+ switch (cairo_image_surface_get_format (surface))
+ {
+ case CAIRO_FORMAT_RGB24: return babl_format ("cairo-RGB24");
+ case CAIRO_FORMAT_ARGB32: return babl_format ("cairo-ARGB32");
+ case CAIRO_FORMAT_A8: return babl_format ("cairo-A8");
+
+ default:
+ break;
+ }
+
+ g_return_val_if_reached (NULL);
+}
+
+/**
+ * gimp_cairo_surface_create_buffer:
+ * @surface: a Cairo surface
+ *
+ * This function returns a #GeglBuffer which wraps @surface's pixels.
+ * It must only be called on image surfaces, calling it on other surface
+ * types is an error.
+ *
+ * Return value: a #GeglBuffer
+ *
+ * Since: 2.10
+ **/
+GeglBuffer *
+gimp_cairo_surface_create_buffer (cairo_surface_t *surface)
+{
+ const Babl *format;
+ gint width;
+ gint height;
+
+ g_return_val_if_fail (surface != NULL, NULL);
+ g_return_val_if_fail (cairo_surface_get_type (surface) ==
+ CAIRO_SURFACE_TYPE_IMAGE, NULL);
+
+ format = gimp_cairo_surface_get_format (surface);
+ width = cairo_image_surface_get_width (surface);
+ height = cairo_image_surface_get_height (surface);
+
+ return
+ gegl_buffer_linear_new_from_data (cairo_image_surface_get_data (surface),
+ format,
+ GEGL_RECTANGLE (0, 0, width, height),
+ cairo_image_surface_get_stride (surface),
+ (GDestroyNotify) cairo_surface_destroy,
+ cairo_surface_reference (surface));
+}
diff --git a/libgimpcolor/gimpcairo.h b/libgimpcolor/gimpcairo.h
new file mode 100644
index 0000000..d96e963
--- /dev/null
+++ b/libgimpcolor/gimpcairo.h
@@ -0,0 +1,159 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimpcairo.h
+ * Copyright (C) 2007 Sven Neumann <sven@gimp.org>
+ * 2010-2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This library 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.
+ *
+ * This library 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 this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_CAIRO_H__
+#define __GIMP_CAIRO_H__
+
+
+void gimp_cairo_set_source_rgb (cairo_t *cr,
+ const GimpRGB *color);
+void gimp_cairo_set_source_rgba (cairo_t *cr,
+ const GimpRGB *color);
+
+cairo_pattern_t * gimp_cairo_checkerboard_create (cairo_t *cr,
+ gint size,
+ const GimpRGB *light,
+ const GimpRGB *dark);
+
+const Babl * gimp_cairo_surface_get_format (cairo_surface_t *surface);
+GeglBuffer * gimp_cairo_surface_create_buffer (cairo_surface_t *surface);
+
+
+/* some useful macros for writing directly to a Cairo surface */
+
+/**
+ * GIMP_CAIRO_RGB24_SET_PIXEL:
+ * @d: pointer to the destination buffer
+ * @r: red component
+ * @g: green component
+ * @b: blue component
+ *
+ * Sets a single pixel in an Cairo image surface in %CAIRO_FORMAT_RGB24.
+ *
+ * Since: 2.6
+ **/
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define GIMP_CAIRO_RGB24_SET_PIXEL(d, r, g, b) \
+ G_STMT_START { d[0] = (b); d[1] = (g); d[2] = (r); } G_STMT_END
+#else
+#define GIMP_CAIRO_RGB24_SET_PIXEL(d, r, g, b) \
+ G_STMT_START { d[1] = (r); d[2] = (g); d[3] = (b); } G_STMT_END
+#endif
+
+
+/**
+ * GIMP_CAIRO_RGB24_GET_PIXEL:
+ * @s: pointer to the source buffer
+ * @r: red component
+ * @g: green component
+ * @b: blue component
+ *
+ * Gets a single pixel from a Cairo image surface in %CAIRO_FORMAT_RGB24.
+ *
+ * Since: 2.8
+ **/
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define GIMP_CAIRO_RGB24_GET_PIXEL(s, r, g, b) \
+ G_STMT_START { (b) = s[0]; (g) = s[1]; (r) = s[2]; } G_STMT_END
+#else
+#define GIMP_CAIRO_RGB24_GET_PIXEL(s, r, g, b) \
+ G_STMT_START { (r) = s[1]; (g) = s[2]; (b) = s[3]; } G_STMT_END
+#endif
+
+
+/**
+ * GIMP_CAIRO_ARGB32_SET_PIXEL:
+ * @d: pointer to the destination buffer
+ * @r: red component, not pre-multiplied
+ * @g: green component, not pre-multiplied
+ * @b: blue component, not pre-multiplied
+ * @a: alpha component
+ *
+ * Sets a single pixel in an Cairo image surface in %CAIRO_FORMAT_ARGB32.
+ *
+ * Since: 2.6
+ **/
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define GIMP_CAIRO_ARGB32_SET_PIXEL(d, r, g, b, a) \
+ G_STMT_START { \
+ const guint tr = (a) * (r) + 0x80; \
+ const guint tg = (a) * (g) + 0x80; \
+ const guint tb = (a) * (b) + 0x80; \
+ (d)[0] = (((tb) >> 8) + (tb)) >> 8; \
+ (d)[1] = (((tg) >> 8) + (tg)) >> 8; \
+ (d)[2] = (((tr) >> 8) + (tr)) >> 8; \
+ (d)[3] = (a); \
+ } G_STMT_END
+#else
+#define GIMP_CAIRO_ARGB32_SET_PIXEL(d, r, g, b, a) \
+ G_STMT_START { \
+ const guint tr = (a) * (r) + 0x80; \
+ const guint tg = (a) * (g) + 0x80; \
+ const guint tb = (a) * (b) + 0x80; \
+ (d)[0] = (a); \
+ (d)[1] = (((tr) >> 8) + (tr)) >> 8; \
+ (d)[2] = (((tg) >> 8) + (tg)) >> 8; \
+ (d)[3] = (((tb) >> 8) + (tb)) >> 8; \
+ } G_STMT_END
+#endif
+
+
+/**
+ * GIMP_CAIRO_ARGB32_GET_PIXEL:
+ * @s: pointer to the source buffer
+ * @r: red component, not pre-multiplied
+ * @g: green component, not pre-multiplied
+ * @b: blue component, not pre-multiplied
+ * @a: alpha component
+ *
+ * Gets a single pixel from a Cairo image surface in %CAIRO_FORMAT_ARGB32.
+ *
+ * Since: 2.8
+ **/
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+#define GIMP_CAIRO_ARGB32_GET_PIXEL(s, r, g, b, a) \
+ G_STMT_START { \
+ const guint tb = (s)[0]; \
+ const guint tg = (s)[1]; \
+ const guint tr = (s)[2]; \
+ const guint ta = (s)[3]; \
+ (r) = (tr << 8) / (ta + 1); \
+ (g) = (tg << 8) / (ta + 1); \
+ (b) = (tb << 8) / (ta + 1); \
+ (a) = ta; \
+ } G_STMT_END
+#else
+#define GIMP_CAIRO_ARGB32_GET_PIXEL(s, r, g, b, a) \
+ G_STMT_START { \
+ const guint ta = (s)[0]; \
+ const guint tr = (s)[1]; \
+ const guint tg = (s)[2]; \
+ const guint tb = (s)[3]; \
+ (r) = (tr << 8) / (ta + 1); \
+ (g) = (tg << 8) / (ta + 1); \
+ (b) = (tb << 8) / (ta + 1); \
+ (a) = ta; \
+ } G_STMT_END
+#endif
+
+
+#endif /* __GIMP_CAIRO_H__ */
diff --git a/libgimpcolor/gimpcmyk.c b/libgimpcolor/gimpcmyk.c
new file mode 100644
index 0000000..28b08eb
--- /dev/null
+++ b/libgimpcolor/gimpcmyk.c
@@ -0,0 +1,233 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+
+#include "libgimpmath/gimpmath.h"
+
+#include "gimpcolortypes.h"
+
+#include "gimpcmyk.h"
+
+
+/**
+ * SECTION: gimpcmyk
+ * @title: GimpCMYK
+ * @short_description: Definitions and Functions relating to CMYK colors.
+ *
+ * Definitions and Functions relating to CMYK colors.
+ **/
+
+
+/*
+ * GIMP_TYPE_CMYK
+ */
+
+static GimpCMYK * gimp_cmyk_copy (const GimpCMYK *cmyk);
+
+
+GType
+gimp_cmyk_get_type (void)
+{
+ static GType cmyk_type = 0;
+
+ if (!cmyk_type)
+ cmyk_type = g_boxed_type_register_static ("GimpCMYK",
+ (GBoxedCopyFunc) gimp_cmyk_copy,
+ (GBoxedFreeFunc) g_free);
+
+ return cmyk_type;
+}
+
+static GimpCMYK *
+gimp_cmyk_copy (const GimpCMYK *cmyk)
+{
+ return g_memdup (cmyk, sizeof (GimpCMYK));
+}
+
+
+/* CMYK functions */
+
+/**
+ * gimp_cmyk_set:
+ * @cmyk: A #GimpCMYK structure which will hold the specified CMYK value.
+ * @cyan: The Cyan channel of the CMYK value
+ * @magenta: The Magenta channel
+ * @yellow: The Yellow channel
+ * @black: The blacK channel
+ *
+ * Very basic initialiser for the internal #GimpCMYK structure. Channel
+ * values are doubles in the range 0 to 1.
+ **/
+void
+gimp_cmyk_set (GimpCMYK *cmyk,
+ gdouble cyan,
+ gdouble magenta,
+ gdouble yellow,
+ gdouble black)
+{
+ g_return_if_fail (cmyk != NULL);
+
+ cmyk->c = cyan;
+ cmyk->m = magenta;
+ cmyk->y = yellow;
+ cmyk->k = black;
+}
+
+/**
+ * gimp_cmyk_set_uchar:
+ * @cmyk: A #GimpCMYK structure which will hold the specified CMYK value.
+ * @cyan: The Cyan channel of the CMYK value
+ * @magenta: The Magenta channel
+ * @yellow: The Yellow channel
+ * @black: The blacK channel
+ *
+ * The same as gimp_cmyk_set(), except that channel values are
+ * unsigned chars in the range 0 to 255.
+ **/
+void
+gimp_cmyk_set_uchar (GimpCMYK *cmyk,
+ guchar cyan,
+ guchar magenta,
+ guchar yellow,
+ guchar black)
+{
+ g_return_if_fail (cmyk != NULL);
+
+ cmyk->c = (gdouble) cyan / 255.0;
+ cmyk->m = (gdouble) magenta / 255.0;
+ cmyk->y = (gdouble) yellow / 255.0;
+ cmyk->k = (gdouble) black / 255.0;
+}
+
+/**
+ * gimp_cmyk_get_uchar:
+ * @cmyk: A #GimpCMYK structure which will hold the specified CMYK value.
+ * @cyan: The Cyan channel of the CMYK value
+ * @magenta: The Magenta channel
+ * @yellow: The Yellow channel
+ * @black: The blacK channel
+ *
+ * Retrieve individual channel values from a #GimpCMYK structure. Channel
+ * values are pointers to unsigned chars in the range 0 to 255.
+ **/
+void
+gimp_cmyk_get_uchar (const GimpCMYK *cmyk,
+ guchar *cyan,
+ guchar *magenta,
+ guchar *yellow,
+ guchar *black)
+{
+ g_return_if_fail (cmyk != NULL);
+
+ if (cyan) *cyan = ROUND (CLAMP (cmyk->c, 0.0, 1.0) * 255.0);
+ if (magenta) *magenta = ROUND (CLAMP (cmyk->m, 0.0, 1.0) * 255.0);
+ if (yellow) *yellow = ROUND (CLAMP (cmyk->y, 0.0, 1.0) * 255.0);
+ if (black) *black = ROUND (CLAMP (cmyk->k, 0.0, 1.0) * 255.0);
+}
+
+
+/* CMYKA functions */
+
+/**
+ * gimp_cmyka_set:
+ * @cmyka: A #GimpCMYK structure which will hold the specified CMYKA value.
+ * @cyan: The Cyan channel of the CMYK value
+ * @magenta: The Magenta channel
+ * @yellow: The Yellow channel
+ * @black: The blacK channel
+ * @alpha: The Alpha channel
+ *
+ * Initialiser for the internal #GimpCMYK structure. Channel values are
+ * doubles in the range 0 to 1.
+ **/
+void
+gimp_cmyka_set (GimpCMYK *cmyka,
+ gdouble cyan,
+ gdouble magenta,
+ gdouble yellow,
+ gdouble black,
+ gdouble alpha)
+{
+ g_return_if_fail (cmyka != NULL);
+
+ cmyka->c = cyan;
+ cmyka->m = magenta;
+ cmyka->y = yellow;
+ cmyka->k = black;
+ cmyka->a = alpha;
+}
+
+/**
+ * gimp_cmyka_set_uchar:
+ * @cmyka: A #GimpCMYK structure which will hold the specified CMYKA value.
+ * @cyan: The Cyan channel of the CMYK value
+ * @magenta: The Magenta channel
+ * @yellow: The Yellow channel
+ * @black: The blacK channel
+ * @alpha: The Alpha channel
+ *
+ * The same as gimp_cmyka_set(), except that channel values are
+ * unsigned chars in the range 0 to 255.
+ **/
+void
+gimp_cmyka_set_uchar (GimpCMYK *cmyka,
+ guchar cyan,
+ guchar magenta,
+ guchar yellow,
+ guchar black,
+ guchar alpha)
+{
+ g_return_if_fail (cmyka != NULL);
+
+ cmyka->c = (gdouble) cyan / 255.0;
+ cmyka->m = (gdouble) magenta / 255.0;
+ cmyka->y = (gdouble) yellow / 255.0;
+ cmyka->k = (gdouble) black / 255.0;
+ cmyka->a = (gdouble) alpha / 255.0;
+}
+/**
+ * gimp_cmyka_get_uchar:
+ * @cmyka: A #GimpCMYK structure which will hold the specified CMYKA value.
+ * @cyan: The Cyan channel of the CMYK value
+ * @magenta: The Magenta channel
+ * @yellow: The Yellow channel
+ * @black: The blacK channel
+ * @alpha: The Alpha channel
+ *
+ * Retrieve individual channel values from a #GimpCMYK structure.
+ * Channel values are pointers to unsigned chars in the range 0 to 255.
+ **/
+void
+gimp_cmyka_get_uchar (const GimpCMYK *cmyka,
+ guchar *cyan,
+ guchar *magenta,
+ guchar *yellow,
+ guchar *black,
+ guchar *alpha)
+{
+ g_return_if_fail (cmyka != NULL);
+
+ if (cyan) *cyan = ROUND (CLAMP (cmyka->c, 0.0, 1.0) * 255.0);
+ if (magenta) *magenta = ROUND (CLAMP (cmyka->m, 0.0, 1.0) * 255.0);
+ if (yellow) *yellow = ROUND (CLAMP (cmyka->y, 0.0, 1.0) * 255.0);
+ if (black) *black = ROUND (CLAMP (cmyka->k, 0.0, 1.0) * 255.0);
+ if (alpha) *alpha = ROUND (CLAMP (cmyka->a, 0.0, 1.0) * 255.0);
+}
diff --git a/libgimpcolor/gimpcmyk.h b/libgimpcolor/gimpcmyk.h
new file mode 100644
index 0000000..cafb252
--- /dev/null
+++ b/libgimpcolor/gimpcmyk.h
@@ -0,0 +1,78 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_CMYK_H__
+#define __GIMP_CMYK_H__
+
+G_BEGIN_DECLS
+
+
+/* For information look into the C source or the html documentation */
+
+
+/*
+ * GIMP_TYPE_CMYK
+ */
+
+#define GIMP_TYPE_CMYK (gimp_cmyk_get_type ())
+
+GType gimp_cmyk_get_type (void) G_GNUC_CONST;
+
+void gimp_cmyk_set (GimpCMYK *cmyk,
+ gdouble cyan,
+ gdouble magenta,
+ gdouble yellow,
+ gdouble black);
+void gimp_cmyk_set_uchar (GimpCMYK *cmyk,
+ guchar cyan,
+ guchar magenta,
+ guchar yellow,
+ guchar black);
+void gimp_cmyk_get_uchar (const GimpCMYK *cmyk,
+ guchar *cyan,
+ guchar *magenta,
+ guchar *yellow,
+ guchar *black);
+
+void gimp_cmyka_set (GimpCMYK *cmyka,
+ gdouble cyan,
+ gdouble magenta,
+ gdouble yellow,
+ gdouble black,
+ gdouble alpha);
+void gimp_cmyka_set_uchar (GimpCMYK *cmyka,
+ guchar cyan,
+ guchar magenta,
+ guchar yellow,
+ guchar black,
+ guchar alpha);
+void gimp_cmyka_get_uchar (const GimpCMYK *cmyka,
+ guchar *cyan,
+ guchar *magenta,
+ guchar *yellow,
+ guchar *black,
+ guchar *alpha);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_CMYK_H__ */
diff --git a/libgimpcolor/gimpcolor.def b/libgimpcolor/gimpcolor.def
new file mode 100644
index 0000000..3feaf98
--- /dev/null
+++ b/libgimpcolor/gimpcolor.def
@@ -0,0 +1,128 @@
+EXPORTS
+ gimp_adaptive_supersample_area
+ gimp_bilinear
+ gimp_bilinear_16
+ gimp_bilinear_32
+ gimp_bilinear_8
+ gimp_bilinear_pixels_8
+ gimp_bilinear_rgb
+ gimp_bilinear_rgba
+ gimp_cairo_checkerboard_create
+ gimp_cairo_set_source_rgb
+ gimp_cairo_set_source_rgba
+ gimp_cairo_surface_create_buffer
+ gimp_cairo_surface_get_format
+ gimp_cmyk_get_type
+ gimp_cmyk_get_uchar
+ gimp_cmyk_set
+ gimp_cmyk_set_uchar
+ gimp_cmyk_to_rgb
+ gimp_cmyk_to_rgb_int
+ gimp_cmyka_get_uchar
+ gimp_cmyka_set
+ gimp_cmyka_set_uchar
+ gimp_color_managed_get_color_profile
+ gimp_color_managed_get_icc_profile
+ gimp_color_managed_get_type
+ gimp_color_managed_interface_get_type
+ gimp_color_managed_profile_changed
+ gimp_color_profile_get_copyright
+ gimp_color_profile_get_description
+ gimp_color_profile_get_format
+ gimp_color_profile_get_icc_profile
+ gimp_color_profile_get_label
+ gimp_color_profile_get_lcms_format
+ gimp_color_profile_get_lcms_profile
+ gimp_color_profile_get_manufacturer
+ gimp_color_profile_get_model
+ gimp_color_profile_get_space
+ gimp_color_profile_get_summary
+ gimp_color_profile_get_type
+ gimp_color_profile_is_cmyk
+ gimp_color_profile_is_equal
+ gimp_color_profile_is_gray
+ gimp_color_profile_is_linear
+ gimp_color_profile_is_rgb
+ gimp_color_profile_new_d50_gray_lab_trc
+ gimp_color_profile_new_d65_gray_linear
+ gimp_color_profile_new_d65_gray_srgb_trc
+ gimp_color_profile_new_from_file
+ gimp_color_profile_new_from_icc_profile
+ gimp_color_profile_new_from_lcms_profile
+ gimp_color_profile_new_linear_from_color_profile
+ gimp_color_profile_new_rgb_adobe
+ gimp_color_profile_new_rgb_srgb
+ gimp_color_profile_new_rgb_srgb_linear
+ gimp_color_profile_new_srgb_trc_from_color_profile
+ gimp_color_profile_save_to_file
+ gimp_color_transform_can_gegl_copy
+ gimp_color_transform_get_type
+ gimp_color_transform_new
+ gimp_color_transform_new_proofing
+ gimp_color_transform_process_buffer
+ gimp_color_transform_process_pixels
+ gimp_hsl_get_type
+ gimp_hsl_set
+ gimp_hsl_set_alpha
+ gimp_hsl_to_rgb
+ gimp_hsl_to_rgb_int
+ gimp_hsv_clamp
+ gimp_hsv_get_type
+ gimp_hsv_set
+ gimp_hsv_to_rgb
+ gimp_hsv_to_rgb4
+ gimp_hsv_to_rgb_int
+ gimp_hsva_set
+ gimp_hwb_to_rgb
+ gimp_param_rgb_get_type
+ gimp_param_spec_rgb
+ gimp_param_spec_rgb_get_default
+ gimp_param_spec_rgb_has_alpha
+ gimp_pixbuf_create_buffer
+ gimp_pixbuf_get_format
+ gimp_pixbuf_get_icc_profile
+ gimp_rgb_add
+ gimp_rgb_clamp
+ gimp_rgb_composite
+ gimp_rgb_distance
+ gimp_rgb_gamma
+ gimp_rgb_get_pixel
+ gimp_rgb_get_type
+ gimp_rgb_get_uchar
+ gimp_rgb_intensity
+ gimp_rgb_intensity_uchar
+ gimp_rgb_list_names
+ gimp_rgb_luminance
+ gimp_rgb_luminance_uchar
+ gimp_rgb_max
+ gimp_rgb_min
+ gimp_rgb_multiply
+ gimp_rgb_parse_css
+ gimp_rgb_parse_hex
+ gimp_rgb_parse_name
+ gimp_rgb_set
+ gimp_rgb_set_alpha
+ gimp_rgb_set_pixel
+ gimp_rgb_set_uchar
+ gimp_rgb_subtract
+ gimp_rgb_to_cmyk
+ gimp_rgb_to_cmyk_int
+ gimp_rgb_to_hsl
+ gimp_rgb_to_hsl_int
+ gimp_rgb_to_hsv
+ gimp_rgb_to_hsv4
+ gimp_rgb_to_hsv_int
+ gimp_rgb_to_hwb
+ gimp_rgb_to_l_int
+ gimp_rgba_add
+ gimp_rgba_distance
+ gimp_rgba_get_pixel
+ gimp_rgba_get_uchar
+ gimp_rgba_multiply
+ gimp_rgba_parse_css
+ gimp_rgba_set
+ gimp_rgba_set_pixel
+ gimp_rgba_set_uchar
+ gimp_rgba_subtract
+ gimp_value_get_rgb
+ gimp_value_set_rgb
diff --git a/libgimpcolor/gimpcolor.h b/libgimpcolor/gimpcolor.h
new file mode 100644
index 0000000..7e960a1
--- /dev/null
+++ b/libgimpcolor/gimpcolor.h
@@ -0,0 +1,41 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_COLOR_H__
+#define __GIMP_COLOR_H__
+
+#define __GIMP_COLOR_H_INSIDE__
+
+#include <libgimpcolor/gimpcolortypes.h>
+
+#include <libgimpcolor/gimpadaptivesupersample.h>
+#include <libgimpcolor/gimpbilinear.h>
+#include <libgimpcolor/gimpcairo.h>
+#include <libgimpcolor/gimpcolormanaged.h>
+#include <libgimpcolor/gimpcolorprofile.h>
+#include <libgimpcolor/gimpcolorspace.h>
+#include <libgimpcolor/gimpcolortransform.h>
+#include <libgimpcolor/gimpcmyk.h>
+#include <libgimpcolor/gimphsl.h>
+#include <libgimpcolor/gimphsv.h>
+#include <libgimpcolor/gimppixbuf.h>
+#include <libgimpcolor/gimprgb.h>
+
+#undef __GIMP_COLOR_H_INSIDE__
+
+#endif /* __GIMP_COLOR_H__ */
diff --git a/libgimpcolor/gimpcolormanaged.c b/libgimpcolor/gimpcolormanaged.c
new file mode 100644
index 0000000..60c6eb1
--- /dev/null
+++ b/libgimpcolor/gimpcolormanaged.c
@@ -0,0 +1,151 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * GimpColorManaged interface
+ * Copyright (C) 2007 Sven Neumann <sven@gimp.org>
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gio/gio.h>
+#include <gegl.h>
+
+#include "gimpcolortypes.h"
+
+#include "gimpcolormanaged.h"
+#include "gimpcolorprofile.h"
+
+
+/**
+ * SECTION: gimpcolormanaged
+ * @title: GimpColorManaged
+ * @short_description: An interface dealing with color profiles.
+ *
+ * An interface dealing with color profiles.
+ **/
+
+
+enum
+{
+ PROFILE_CHANGED,
+ LAST_SIGNAL
+};
+
+
+G_DEFINE_INTERFACE (GimpColorManaged, gimp_color_managed, G_TYPE_OBJECT)
+
+
+static guint gimp_color_managed_signals[LAST_SIGNAL] = { 0 };
+
+
+/* private functions */
+
+
+GType
+gimp_color_managed_interface_get_type (void)
+{
+ return gimp_color_managed_get_type ();
+}
+
+static void
+gimp_color_managed_default_init (GimpColorManagedInterface *iface)
+{
+ gimp_color_managed_signals[PROFILE_CHANGED] =
+ g_signal_new ("profile-changed",
+ G_TYPE_FROM_INTERFACE (iface),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GimpColorManagedInterface,
+ profile_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+}
+
+
+/* public functions */
+
+
+/**
+ * gimp_color_managed_get_icc_profile:
+ * @managed: an object the implements the #GimpColorManaged interface
+ * @len: return location for the number of bytes in the profile data
+ *
+ * Return value: A pointer to a blob of data that represents an ICC
+ * color profile.
+ *
+ * Since: 2.4
+ **/
+const guint8 *
+gimp_color_managed_get_icc_profile (GimpColorManaged *managed,
+ gsize *len)
+{
+ GimpColorManagedInterface *iface;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_MANAGED (managed), NULL);
+ g_return_val_if_fail (len != NULL, NULL);
+
+ *len = 0;
+
+ iface = GIMP_COLOR_MANAGED_GET_INTERFACE (managed);
+
+ if (iface->get_icc_profile)
+ return iface->get_icc_profile (managed, len);
+
+ return NULL;
+}
+
+/**
+ * gimp_color_managed_get_color_profile:
+ * @managed: an object the implements the #GimpColorManaged interface
+ *
+ * This function always returns a #GimpColorProfile and falls back to
+ * gimp_color_profile_new_rgb_srgb() if the method is not implemented.
+ *
+ * Return value: The @managed's #GimpColorProfile.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_managed_get_color_profile (GimpColorManaged *managed)
+{
+ GimpColorManagedInterface *iface;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_MANAGED (managed), NULL);
+
+ iface = GIMP_COLOR_MANAGED_GET_INTERFACE (managed);
+
+ if (iface->get_color_profile)
+ return iface->get_color_profile (managed);
+
+ return NULL;
+}
+
+/**
+ * gimp_color_managed_profile_changed:
+ * @managed: an object the implements the #GimpColorManaged interface
+ *
+ * Emits the "profile-changed" signal.
+ *
+ * Since: 2.4
+ **/
+void
+gimp_color_managed_profile_changed (GimpColorManaged *managed)
+{
+ g_return_if_fail (GIMP_IS_COLOR_MANAGED (managed));
+
+ g_signal_emit (managed, gimp_color_managed_signals[PROFILE_CHANGED], 0);
+}
diff --git a/libgimpcolor/gimpcolormanaged.h b/libgimpcolor/gimpcolormanaged.h
new file mode 100644
index 0000000..d24e0c8
--- /dev/null
+++ b/libgimpcolor/gimpcolormanaged.h
@@ -0,0 +1,82 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * GimpColorManaged interface
+ * Copyright (C) 2007 Sven Neumann <sven@gimp.org>
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_COLOR_MANAGED_H__
+#define __GIMP_COLOR_MANAGED_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+#define GIMP_TYPE_COLOR_MANAGED (gimp_color_managed_get_type ())
+#define GIMP_IS_COLOR_MANAGED(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_COLOR_MANAGED))
+#define GIMP_COLOR_MANAGED(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_COLOR_MANAGED, GimpColorManaged))
+#define GIMP_COLOR_MANAGED_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GIMP_TYPE_COLOR_MANAGED, GimpColorManagedInterface))
+
+
+typedef struct _GimpColorManagedInterface GimpColorManagedInterface;
+
+/**
+ * GimpColorManagedInterface:
+ * @base_iface: The parent interface
+ * @get_icc_profile: Returns the ICC profile of the pixels managed by
+ * the object
+ * @profile_changed: This signal is emitted when the object's color profile
+ * has changed
+ * @get_color_profile: Returns the #GimpColorProfile of the pixels managed
+ * by the object
+ **/
+struct _GimpColorManagedInterface
+{
+ GTypeInterface base_iface;
+
+ /* virtual functions */
+ const guint8 * (* get_icc_profile) (GimpColorManaged *managed,
+ gsize *len);
+
+ /* signals */
+ void (* profile_changed) (GimpColorManaged *managed);
+
+ /* virtual functions */
+ GimpColorProfile * (* get_color_profile) (GimpColorManaged *managed);
+};
+
+
+GType gimp_color_managed_get_type (void) G_GNUC_CONST;
+
+GIMP_DEPRECATED_FOR (gimp_color_managed_get_type)
+GType gimp_color_managed_interface_get_type (void) G_GNUC_CONST;
+
+const guint8 * gimp_color_managed_get_icc_profile (GimpColorManaged *managed,
+ gsize *len);
+GimpColorProfile * gimp_color_managed_get_color_profile (GimpColorManaged *managed);
+
+void gimp_color_managed_profile_changed (GimpColorManaged *managed);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_COLOR_MANAGED_IFACE_H__ */
diff --git a/libgimpcolor/gimpcolorprofile.c b/libgimpcolor/gimpcolorprofile.c
new file mode 100644
index 0000000..69236b4
--- /dev/null
+++ b/libgimpcolor/gimpcolorprofile.c
@@ -0,0 +1,1789 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimpcolorprofile.c
+ * Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
+ * Elle Stone <ellestone@ninedegreesbelow.com>
+ * Øyvind Kolås <pippin@gimp.org>
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <lcms2.h>
+
+#include <gio/gio.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "gimpcolortypes.h"
+
+#include "gimpcolorprofile.h"
+
+#include "libgimp/libgimp-intl.h"
+
+
+#ifndef TYPE_RGBA_DBL
+#define TYPE_RGBA_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(0))
+#endif
+
+#ifndef TYPE_GRAYA_HALF_FLT
+#define TYPE_GRAYA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(2))
+#endif
+
+#ifndef TYPE_GRAYA_FLT
+#define TYPE_GRAYA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(4))
+#endif
+
+#ifndef TYPE_GRAYA_DBL
+#define TYPE_GRAYA_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_GRAY)|EXTRA_SH(1)|CHANNELS_SH(1)|BYTES_SH(0))
+#endif
+
+#ifndef TYPE_CMYKA_DBL
+#define TYPE_CMYKA_DBL (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(0))
+#endif
+
+#ifndef TYPE_CMYKA_HALF_FLT
+#define TYPE_CMYKA_HALF_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(2))
+#endif
+
+#ifndef TYPE_CMYKA_FLT
+#define TYPE_CMYKA_FLT (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(4))
+#endif
+
+#ifndef TYPE_CMYKA_16
+#define TYPE_CMYKA_16 (COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(2))
+#endif
+
+
+/**
+ * SECTION: gimpcolorprofile
+ * @title: GimpColorProfile
+ * @short_description: Definitions and Functions relating to LCMS.
+ *
+ * Definitions and Functions relating to LCMS.
+ **/
+
+/**
+ * GimpColorProfile:
+ *
+ * Simply a typedef to #gpointer, but actually is a cmsHPROFILE. It's
+ * used in public GIMP APIs in order to avoid having to include LCMS
+ * headers.
+ **/
+
+
+struct _GimpColorProfilePrivate
+{
+ cmsHPROFILE lcms_profile;
+ guint8 *data;
+ gsize length;
+
+ gchar *description;
+ gchar *manufacturer;
+ gchar *model;
+ gchar *copyright;
+ gchar *label;
+ gchar *summary;
+};
+
+
+static void gimp_color_profile_finalize (GObject *object);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpColorProfile, gimp_color_profile, G_TYPE_OBJECT)
+
+#define parent_class gimp_color_profile_parent_class
+
+
+#define GIMP_COLOR_PROFILE_ERROR gimp_color_profile_error_quark ()
+
+static GQuark
+gimp_color_profile_error_quark (void)
+{
+ static GQuark quark = 0;
+
+ if (G_UNLIKELY (quark == 0))
+ quark = g_quark_from_static_string ("gimp-color-profile-error-quark");
+
+ return quark;
+}
+
+static void
+gimp_color_profile_class_init (GimpColorProfileClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gimp_color_profile_finalize;
+}
+
+static void
+gimp_color_profile_init (GimpColorProfile *profile)
+{
+ profile->priv = gimp_color_profile_get_instance_private (profile);
+}
+
+static void
+gimp_color_profile_finalize (GObject *object)
+{
+ GimpColorProfile *profile = GIMP_COLOR_PROFILE (object);
+
+ g_clear_pointer (&profile->priv->lcms_profile, cmsCloseProfile);
+
+ g_clear_pointer (&profile->priv->data, g_free);
+ profile->priv->length = 0;
+
+ g_clear_pointer (&profile->priv->description, g_free);
+ g_clear_pointer (&profile->priv->manufacturer, g_free);
+ g_clear_pointer (&profile->priv->model, g_free);
+ g_clear_pointer (&profile->priv->copyright, g_free);
+ g_clear_pointer (&profile->priv->label, g_free);
+ g_clear_pointer (&profile->priv->summary, g_free);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+/**
+ * gimp_color_profile_new_from_file:
+ * @file: a #GFile
+ * @error: return location for #GError
+ *
+ * This function opens an ICC color profile from @file.
+ *
+ * Return value: the #GimpColorProfile, or %NULL. On error, %NULL is
+ * returned and @error is set.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_from_file (GFile *file,
+ GError **error)
+{
+ GimpColorProfile *profile = NULL;
+ cmsHPROFILE lcms_profile = NULL;
+ guint8 *data = NULL;
+ gsize length = 0;
+ gchar *path;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ path = g_file_get_path (file);
+
+ if (path)
+ {
+ GMappedFile *mapped;
+
+ mapped = g_mapped_file_new (path, FALSE, error);
+ g_free (path);
+
+ if (! mapped)
+ return NULL;
+
+ length = g_mapped_file_get_length (mapped);
+ data = g_memdup (g_mapped_file_get_contents (mapped), length);
+
+ lcms_profile = cmsOpenProfileFromMem (data, length);
+
+ g_mapped_file_unref (mapped);
+ }
+ else
+ {
+ GFileInfo *info;
+
+ info = g_file_query_info (file,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, error);
+ if (info)
+ {
+ GInputStream *input;
+
+ length = g_file_info_get_size (info);
+ data = g_malloc (length);
+
+ g_object_unref (info);
+
+ input = G_INPUT_STREAM (g_file_read (file, NULL, error));
+
+ if (input)
+ {
+ gsize bytes_read;
+
+ if (g_input_stream_read_all (input, data, length,
+ &bytes_read, NULL, error) &&
+ bytes_read == length)
+ {
+ lcms_profile = cmsOpenProfileFromMem (data, length);
+ }
+
+ g_object_unref (input);
+ }
+ }
+ }
+
+ if (lcms_profile)
+ {
+ profile = g_object_new (GIMP_TYPE_COLOR_PROFILE, NULL);
+
+ profile->priv->lcms_profile = lcms_profile;
+ profile->priv->data = data;
+ profile->priv->length = length;
+ }
+ else
+ {
+ if (data)
+ g_free (data);
+
+ if (error && *error == NULL)
+ {
+ g_set_error (error, GIMP_COLOR_PROFILE_ERROR, 0,
+ _("'%s' does not appear to be an ICC color profile"),
+ gimp_file_get_utf8_name (file));
+ }
+ }
+
+ return profile;
+}
+
+/**
+ * gimp_color_profile_new_from_icc_profile:
+ * @data: pointer to memory containing an ICC profile
+ * @length: length of the profile in memory, in bytes
+ * @error: return location for #GError
+ *
+ * This function opens an ICC color profile from memory. On error,
+ * %NULL is returned and @error is set.
+ *
+ * Return value: the #GimpColorProfile, or %NULL.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_from_icc_profile (const guint8 *data,
+ gsize length,
+ GError **error)
+{
+ cmsHPROFILE lcms_profile = 0;
+ GimpColorProfile *profile = NULL;
+
+ g_return_val_if_fail (data != NULL || length == 0, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ if (length > 0)
+ lcms_profile = cmsOpenProfileFromMem (data, length);
+
+ if (lcms_profile)
+ {
+ profile = g_object_new (GIMP_TYPE_COLOR_PROFILE, NULL);
+
+ profile->priv->lcms_profile = lcms_profile;
+ profile->priv->data = g_memdup (data, length);
+ profile->priv->length = length;
+ }
+ else
+ {
+ g_set_error_literal (error, GIMP_COLOR_PROFILE_ERROR, 0,
+ _("Data does not appear to be an ICC color profile"));
+ }
+
+ return profile;
+}
+
+/**
+ * gimp_color_profile_new_from_lcms_profile:
+ * @lcms_profile: an LCMS cmsHPROFILE pointer
+ * @error: return location for #GError
+ *
+ * This function creates a GimpColorProfile from a cmsHPROFILE. On
+ * error, %NULL is returned and @error is set. The passed
+ * @lcms_profile pointer is not retained by the created
+ * #GimpColorProfile.
+ *
+ * Return value: the #GimpColorProfile, or %NULL.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_from_lcms_profile (gpointer lcms_profile,
+ GError **error)
+{
+ cmsUInt32Number size;
+
+ g_return_val_if_fail (lcms_profile != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ if (cmsSaveProfileToMem (lcms_profile, NULL, &size))
+ {
+ guint8 *data = g_malloc (size);
+
+ if (cmsSaveProfileToMem (lcms_profile, data, &size))
+ {
+ gsize length = size;
+
+ lcms_profile = cmsOpenProfileFromMem (data, length);
+
+ if (lcms_profile)
+ {
+ GimpColorProfile *profile;
+
+ profile = g_object_new (GIMP_TYPE_COLOR_PROFILE, NULL);
+
+ profile->priv->lcms_profile = lcms_profile;
+ profile->priv->data = data;
+ profile->priv->length = length;
+
+ return profile;
+ }
+ }
+
+ g_free (data);
+ }
+
+ g_set_error_literal (error, GIMP_COLOR_PROFILE_ERROR, 0,
+ _("Could not save color profile to memory"));
+
+ return NULL;
+}
+
+/**
+ * gimp_color_profile_save_to_file:
+ * @profile: a #GimpColorProfile
+ * @file: a #GFile
+ * @error: return location for #GError
+ *
+ * This function saves @profile to @file as ICC profile.
+ *
+ * Return value: %TRUE on success, %FALSE if an error occurred.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_color_profile_save_to_file (GimpColorProfile *profile,
+ GFile *file,
+ GError **error)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
+ g_return_val_if_fail (G_IS_FILE (file), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ return g_file_replace_contents (file,
+ (const gchar *) profile->priv->data,
+ profile->priv->length,
+ NULL, FALSE,
+ G_FILE_CREATE_NONE,
+ NULL,
+ NULL,
+ error);
+}
+
+/**
+ * gimp_color_profile_get_icc_profile:
+ * @profile: a #GimpColorProfile
+ * @length: return location for the number of bytes
+ *
+ * This function returns @profile as ICC profile data. The returned
+ * memory belongs to @profile and must not be modified or freed.
+ *
+ * Return value: a pointer to the IIC profile data.
+ *
+ * Since: 2.10
+ **/
+const guint8 *
+gimp_color_profile_get_icc_profile (GimpColorProfile *profile,
+ gsize *length)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+ g_return_val_if_fail (length != NULL, NULL);
+
+ *length = profile->priv->length;
+
+ return profile->priv->data;
+}
+
+/**
+ * gimp_color_profile_get_lcms_profile:
+ * @profile: a #GimpColorProfile
+ *
+ * This function returns @profile's cmsHPROFILE. The returned
+ * value belongs to @profile and must not be modified or freed.
+ *
+ * Return value: a pointer to the cmsHPROFILE.
+ *
+ * Since: 2.10
+ **/
+gpointer
+gimp_color_profile_get_lcms_profile (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ return profile->priv->lcms_profile;
+}
+
+static gchar *
+gimp_color_profile_get_info (GimpColorProfile *profile,
+ cmsInfoType info)
+{
+ cmsUInt32Number size;
+ gchar *text = NULL;
+
+ size = cmsGetProfileInfoASCII (profile->priv->lcms_profile, info,
+ "en", "US", NULL, 0);
+ if (size > 0)
+ {
+ gchar *data = g_new (gchar, size + 1);
+
+ size = cmsGetProfileInfoASCII (profile->priv->lcms_profile, info,
+ "en", "US", data, size);
+ if (size > 0)
+ text = gimp_any_to_utf8 (data, -1, NULL);
+
+ g_free (data);
+ }
+
+ return text;
+}
+
+/**
+ * gimp_color_profile_get_description:
+ * @profile: a #GimpColorProfile
+ *
+ * Return value: a string containing @profile's description. The
+ * returned value belongs to @profile and must not be
+ * modified or freed.
+ *
+ * Since: 2.10
+ **/
+const gchar *
+gimp_color_profile_get_description (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ if (! profile->priv->description)
+ profile->priv->description =
+ gimp_color_profile_get_info (profile, cmsInfoDescription);
+
+ return profile->priv->description;
+}
+
+/**
+ * gimp_color_profile_get_manufacturer:
+ * @profile: a #GimpColorProfile
+ *
+ * Return value: a string containing @profile's manufacturer. The
+ * returned value belongs to @profile and must not be
+ * modified or freed.
+ *
+ * Since: 2.10
+ **/
+const gchar *
+gimp_color_profile_get_manufacturer (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ if (! profile->priv->manufacturer)
+ profile->priv->manufacturer =
+ gimp_color_profile_get_info (profile, cmsInfoManufacturer);
+
+ return profile->priv->manufacturer;
+}
+
+/**
+ * gimp_color_profile_get_model:
+ * @profile: a #GimpColorProfile
+ *
+ * Return value: a string containing @profile's model. The returned
+ * value belongs to @profile and must not be modified or
+ * freed.
+ *
+ * Since: 2.10
+ **/
+const gchar *
+gimp_color_profile_get_model (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ if (! profile->priv->model)
+ profile->priv->model =
+ gimp_color_profile_get_info (profile, cmsInfoModel);
+
+ return profile->priv->model;
+}
+
+/**
+ * gimp_color_profile_get_copyright:
+ * @profile: a #GimpColorProfile
+ *
+ * Return value: a string containing @profile's copyright. The
+ * returned value belongs to @profile and must not be
+ * modified or freed.
+ *
+ * Since: 2.10
+ **/
+const gchar *
+gimp_color_profile_get_copyright (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ if (! profile->priv->copyright)
+ profile->priv->copyright =
+ gimp_color_profile_get_info (profile, cmsInfoCopyright);
+
+ return profile->priv->copyright;
+}
+
+/**
+ * gimp_color_profile_get_label:
+ * @profile: a #GimpColorProfile
+ *
+ * This function returns a string containing @profile's "title", a
+ * string that can be used to label the profile in a user interface.
+ *
+ * Unlike gimp_color_profile_get_description(), this function always
+ * returns a string (as a fallback, it returns "(unnamed profile)").
+ *
+ * Return value: the @profile's label. The returned value belongs to
+ * @profile and must not be modified or freed.
+ *
+ * Since: 2.10
+ **/
+const gchar *
+gimp_color_profile_get_label (GimpColorProfile *profile)
+{
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ if (! profile->priv->label)
+ {
+ const gchar *label = gimp_color_profile_get_description (profile);
+
+ if (! label || ! strlen (label))
+ label = _("(unnamed profile)");
+
+ profile->priv->label = g_strdup (label);
+ }
+
+ return profile->priv->label;
+}
+
+/**
+ * gimp_color_profile_get_summary:
+ * @profile: a #GimpColorProfile
+ *
+ * This function return a string containing a multi-line summary of
+ * @profile's description, model, manufacturer and copyright, to be
+ * used as detailed information about the profile in a user
+ * interface.
+ *
+ * Return value: the @profile's summary. The returned value belongs to
+ * @profile and must not be modified or freed.
+ *
+ * Since: 2.10
+ **/
+const gchar *
+gimp_color_profile_get_summary (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ if (! profile->priv->summary)
+ {
+ GString *string = g_string_new (NULL);
+ const gchar *text;
+
+ text = gimp_color_profile_get_description (profile);
+ if (text)
+ g_string_append (string, text);
+
+ text = gimp_color_profile_get_model (profile);
+ if (text)
+ {
+ if (string->len > 0)
+ g_string_append (string, "\n");
+
+ g_string_append_printf (string, _("Model: %s"), text);
+ }
+
+ text = gimp_color_profile_get_manufacturer (profile);
+ if (text)
+ {
+ if (string->len > 0)
+ g_string_append (string, "\n");
+
+ g_string_append_printf (string, _("Manufacturer: %s"), text);
+ }
+
+ text = gimp_color_profile_get_copyright (profile);
+ if (text)
+ {
+ if (string->len > 0)
+ g_string_append (string, "\n");
+
+ g_string_append_printf (string, _("Copyright: %s"), text);
+ }
+
+ profile->priv->summary = g_string_free (string, FALSE);
+ }
+
+ return profile->priv->summary;
+}
+
+/**
+ * gimp_color_profile_is_equal:
+ * @profile1: a #GimpColorProfile
+ * @profile2: a #GimpColorProfile
+ *
+ * Compares two profiles.
+ *
+ * Return value: %TRUE if the profiles are equal, %FALSE otherwise.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_color_profile_is_equal (GimpColorProfile *profile1,
+ GimpColorProfile *profile2)
+{
+ const gsize header_len = sizeof (cmsICCHeader);
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile1), FALSE);
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile2), FALSE);
+
+ return profile1 == profile2 ||
+ (profile1->priv->length == profile2->priv->length &&
+ memcmp (profile1->priv->data + header_len,
+ profile2->priv->data + header_len,
+ profile1->priv->length - header_len) == 0);
+}
+
+/**
+ * gimp_color_profile_is_rgb:
+ * @profile: a #GimpColorProfile
+ *
+ * Return value: %TRUE if the profile's color space is RGB, %FALSE
+ * otherwise.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_color_profile_is_rgb (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
+
+ return (cmsGetColorSpace (profile->priv->lcms_profile) == cmsSigRgbData);
+}
+
+/**
+ * gimp_color_profile_is_gray:
+ * @profile: a #GimpColorProfile
+ *
+ * Return value: %TRUE if the profile's color space is grayscale, %FALSE
+ * otherwise.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_color_profile_is_gray (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
+
+ return (cmsGetColorSpace (profile->priv->lcms_profile) == cmsSigGrayData);
+}
+
+/**
+ * gimp_color_profile_is_cmyk:
+ * @profile: a #GimpColorProfile
+ *
+ * Return value: %TRUE if the profile's color space is CMYK, %FALSE
+ * otherwise.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_color_profile_is_cmyk (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
+
+ return (cmsGetColorSpace (profile->priv->lcms_profile) == cmsSigCmykData);
+}
+
+
+/**
+ * gimp_color_profile_is_linear:
+ * @profile: a #GimpColorProfile
+ *
+ * This function determines is the ICC profile represented by a GimpColorProfile
+ * is a linear RGB profile or not, some profiles that are LUTs though linear
+ * will also return FALSE;
+ *
+ * Return value: %TRUE if the profile is a matrix shaping profile with linear
+ * TRCs, %FALSE otherwise.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_color_profile_is_linear (GimpColorProfile *profile)
+{
+ cmsHPROFILE prof;
+ cmsToneCurve *curve;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
+
+ prof = profile->priv->lcms_profile;
+
+ if (! cmsIsMatrixShaper (prof))
+ return FALSE;
+
+ if (cmsIsCLUT (prof, INTENT_PERCEPTUAL, LCMS_USED_AS_INPUT))
+ return FALSE;
+
+ if (cmsIsCLUT (prof, INTENT_PERCEPTUAL, LCMS_USED_AS_OUTPUT))
+ return FALSE;
+
+ if (gimp_color_profile_is_rgb (profile))
+ {
+ curve = cmsReadTag(prof, cmsSigRedTRCTag);
+ if (curve == NULL || ! cmsIsToneCurveLinear (curve))
+ return FALSE;
+
+ curve = cmsReadTag (prof, cmsSigGreenTRCTag);
+ if (curve == NULL || ! cmsIsToneCurveLinear (curve))
+ return FALSE;
+
+ curve = cmsReadTag (prof, cmsSigBlueTRCTag);
+ if (curve == NULL || ! cmsIsToneCurveLinear (curve))
+ return FALSE;
+ }
+ else if (gimp_color_profile_is_gray (profile))
+ {
+ curve = cmsReadTag(prof, cmsSigGrayTRCTag);
+ if (curve == NULL || ! cmsIsToneCurveLinear (curve))
+ return FALSE;
+ }
+ else
+ {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+gimp_color_profile_set_tag (cmsHPROFILE profile,
+ cmsTagSignature sig,
+ const gchar *tag)
+{
+ cmsMLU *mlu;
+
+ mlu = cmsMLUalloc (NULL, 1);
+ cmsMLUsetASCII (mlu, "en", "US", tag);
+ cmsWriteTag (profile, sig, mlu);
+ cmsMLUfree (mlu);
+}
+
+static gboolean
+gimp_color_profile_get_rgb_matrix_colorants (GimpColorProfile *profile,
+ GimpMatrix3 *matrix)
+{
+ cmsHPROFILE lcms_profile;
+ cmsCIEXYZ *red;
+ cmsCIEXYZ *green;
+ cmsCIEXYZ *blue;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), FALSE);
+
+ lcms_profile = profile->priv->lcms_profile;
+
+ red = cmsReadTag (lcms_profile, cmsSigRedColorantTag);
+ green = cmsReadTag (lcms_profile, cmsSigGreenColorantTag);
+ blue = cmsReadTag (lcms_profile, cmsSigBlueColorantTag);
+
+ if (red && green && blue)
+ {
+ if (matrix)
+ {
+ matrix->coeff[0][0] = red->X;
+ matrix->coeff[0][1] = red->Y;
+ matrix->coeff[0][2] = red->Z;
+
+ matrix->coeff[1][0] = green->X;
+ matrix->coeff[1][1] = green->Y;
+ matrix->coeff[1][2] = green->Z;
+
+ matrix->coeff[2][0] = blue->X;
+ matrix->coeff[2][1] = blue->Y;
+ matrix->coeff[2][2] = blue->Z;
+ }
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+gimp_color_profile_make_tag (cmsHPROFILE profile,
+ cmsTagSignature sig,
+ const gchar *gimp_tag,
+ const gchar *gimp_prefix,
+ const gchar *gimp_prefix_alt,
+ const gchar *original_tag)
+{
+ if (! original_tag || ! strlen (original_tag) ||
+ ! strcmp (original_tag, gimp_tag))
+ {
+ /* if there is no original tag (or it is the same as the new
+ * tag), just use the new tag
+ */
+
+ gimp_color_profile_set_tag (profile, sig, gimp_tag);
+ }
+ else
+ {
+ /* otherwise prefix the existing tag with a gimp prefix
+ * indicating that the profile has been generated
+ */
+
+ if (g_str_has_prefix (original_tag, gimp_prefix))
+ {
+ /* don't add multiple GIMP prefixes */
+ gimp_color_profile_set_tag (profile, sig, original_tag);
+ }
+ else if (gimp_prefix_alt &&
+ g_str_has_prefix (original_tag, gimp_prefix_alt))
+ {
+ /* replace GIMP prefix_alt by prefix */
+ gchar *new_tag = g_strconcat (gimp_prefix,
+ original_tag + strlen (gimp_prefix_alt),
+ NULL);
+
+ gimp_color_profile_set_tag (profile, sig, new_tag);
+ g_free (new_tag);
+ }
+ else
+ {
+ gchar *new_tag = g_strconcat (gimp_prefix,
+ original_tag,
+ NULL);
+
+ gimp_color_profile_set_tag (profile, sig, new_tag);
+ g_free (new_tag);
+ }
+ }
+}
+
+static GimpColorProfile *
+gimp_color_profile_new_from_color_profile (GimpColorProfile *profile,
+ gboolean linear)
+{
+ GimpColorProfile *new_profile;
+ cmsHPROFILE target_profile;
+ GimpMatrix3 matrix = { { { 0, } } };
+ cmsCIEXYZ *whitepoint;
+ cmsToneCurve *curve;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ if (gimp_color_profile_is_rgb (profile))
+ {
+ if (! gimp_color_profile_get_rgb_matrix_colorants (profile, &matrix))
+ return NULL;
+ }
+ else if (! gimp_color_profile_is_gray (profile))
+ {
+ return NULL;
+ }
+
+ whitepoint = cmsReadTag (profile->priv->lcms_profile,
+ cmsSigMediaWhitePointTag);
+
+ target_profile = cmsCreateProfilePlaceholder (0);
+
+ cmsSetProfileVersion (target_profile, 4.3);
+ cmsSetDeviceClass (target_profile, cmsSigDisplayClass);
+ cmsSetPCS (target_profile, cmsSigXYZData);
+
+ cmsWriteTag (target_profile, cmsSigMediaWhitePointTag, whitepoint);
+
+ if (linear)
+ {
+ /* linear light */
+ curve = cmsBuildGamma (NULL, 1.00);
+
+ gimp_color_profile_make_tag (target_profile, cmsSigProfileDescriptionTag,
+ "linear TRC from unnamed profile",
+ "linear TRC from ",
+ "sRGB TRC from ",
+ gimp_color_profile_get_description (profile));
+ }
+ else
+ {
+ cmsFloat64Number srgb_parameters[5] =
+ { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 };
+
+ /* sRGB curve */
+ curve = cmsBuildParametricToneCurve (NULL, 4, srgb_parameters);
+
+ gimp_color_profile_make_tag (target_profile, cmsSigProfileDescriptionTag,
+ "sRGB TRC from unnamed profile",
+ "sRGB TRC from ",
+ "linear TRC from ",
+ gimp_color_profile_get_description (profile));
+ }
+
+ if (gimp_color_profile_is_rgb (profile))
+ {
+ cmsCIEXYZ red;
+ cmsCIEXYZ green;
+ cmsCIEXYZ blue;
+
+ cmsSetColorSpace (target_profile, cmsSigRgbData);
+
+ red.X = matrix.coeff[0][0];
+ red.Y = matrix.coeff[0][1];
+ red.Z = matrix.coeff[0][2];
+
+ green.X = matrix.coeff[1][0];
+ green.Y = matrix.coeff[1][1];
+ green.Z = matrix.coeff[1][2];
+
+ blue.X = matrix.coeff[2][0];
+ blue.Y = matrix.coeff[2][1];
+ blue.Z = matrix.coeff[2][2];
+
+ cmsWriteTag (target_profile, cmsSigRedColorantTag, &red);
+ cmsWriteTag (target_profile, cmsSigGreenColorantTag, &green);
+ cmsWriteTag (target_profile, cmsSigBlueColorantTag, &blue);
+
+ cmsWriteTag (target_profile, cmsSigRedTRCTag, curve);
+ cmsWriteTag (target_profile, cmsSigGreenTRCTag, curve);
+ cmsWriteTag (target_profile, cmsSigBlueTRCTag, curve);
+ }
+ else
+ {
+ cmsSetColorSpace (target_profile, cmsSigGrayData);
+
+ cmsWriteTag (target_profile, cmsSigGrayTRCTag, curve);
+ }
+
+ cmsFreeToneCurve (curve);
+
+ gimp_color_profile_make_tag (target_profile, cmsSigDeviceMfgDescTag,
+ "GIMP",
+ "GIMP from ", NULL,
+ gimp_color_profile_get_manufacturer (profile));
+ gimp_color_profile_make_tag (target_profile, cmsSigDeviceModelDescTag,
+ "Generated by GIMP",
+ "GIMP from ", NULL,
+ gimp_color_profile_get_model (profile));
+ gimp_color_profile_make_tag (target_profile, cmsSigCopyrightTag,
+ "Public Domain",
+ "GIMP from ", NULL,
+ gimp_color_profile_get_copyright (profile));
+
+ new_profile = gimp_color_profile_new_from_lcms_profile (target_profile, NULL);
+
+ cmsCloseProfile (target_profile);
+
+ return new_profile;
+}
+
+/**
+ * gimp_color_profile_new_srgb_trc_from_color_profile:
+ * @profile: a #GimpColorProfile
+ *
+ * This function creates a new RGB #GimpColorProfile with a sRGB gamma
+ * TRC and @profile's RGB chromacities and whitepoint.
+ *
+ * Return value: the new #GimpColorProfile, or %NULL if @profile is not
+ * an RGB profile or not matrix-based.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_srgb_trc_from_color_profile (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ return gimp_color_profile_new_from_color_profile (profile, FALSE);
+}
+
+/**
+ * gimp_color_profile_new_linear_from_color_profile:
+ * @profile: a #GimpColorProfile
+ *
+ * This function creates a new RGB #GimpColorProfile with a linear TRC
+ * and @profile's RGB chromacities and whitepoint.
+ *
+ * Return value: the new #GimpColorProfile, or %NULL if @profile is not
+ * an RGB profile or not matrix-based.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_linear_from_color_profile (GimpColorProfile *profile)
+{
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+
+ return gimp_color_profile_new_from_color_profile (profile, TRUE);
+}
+
+static cmsHPROFILE *
+gimp_color_profile_new_rgb_srgb_internal (void)
+{
+ cmsHPROFILE profile;
+
+ /* white point is D65 from the sRGB specs */
+ cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
+
+ /* primaries are ITU‐R BT.709‐5 (xYY), which are also the primaries
+ * from the sRGB specs, modified to properly account for hexadecimal
+ * quantization during the profile making process.
+ */
+ cmsCIExyYTRIPLE primaries =
+ {
+ /* R { 0.6400, 0.3300, 1.0 }, */
+ /* G { 0.3000, 0.6000, 1.0 }, */
+ /* B { 0.1500, 0.0600, 1.0 } */
+ /* R */ { 0.639998686, 0.330010138, 1.0 },
+ /* G */ { 0.300003784, 0.600003357, 1.0 },
+ /* B */ { 0.150002046, 0.059997204, 1.0 }
+ };
+
+ cmsFloat64Number srgb_parameters[5] =
+ { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 };
+
+ cmsToneCurve *curve[3];
+
+ /* sRGB curve */
+ curve[0] = curve[1] = curve[2] = cmsBuildParametricToneCurve (NULL, 4,
+ srgb_parameters);
+
+ profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
+
+ cmsFreeToneCurve (curve[0]);
+
+ gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
+ "GIMP built-in sRGB");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
+ "GIMP");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
+ "sRGB");
+ gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
+ "Public Domain");
+
+ /* The following line produces a V2 profile with a point curve TRC.
+ * Profiles with point curve TRCs can't be used in LCMS2 unbounded
+ * mode ICC profile conversions. A V2 profile might be appropriate
+ * for embedding in sRGB images saved to disk, if the image is to be
+ * opened by an image editing application that doesn't understand V4
+ * profiles.
+ *
+ * cmsSetProfileVersion (srgb_profile, 2.1);
+ */
+
+ return profile;
+}
+
+/**
+ * gimp_color_profile_new_rgb_srgb:
+ *
+ * This function is a replacement for cmsCreate_sRGBProfile() and
+ * returns an sRGB profile that is functionally the same as the
+ * ArgyllCMS sRGB.icm profile. "Functionally the same" means it has
+ * the same red, green, and blue colorants and the V4 "chad"
+ * equivalent of the ArgyllCMS V2 white point. The profile TRC is also
+ * functionally equivalent to the ArgyllCMS sRGB.icm TRC and is the
+ * same as the LCMS sRGB built-in profile TRC.
+ *
+ * The actual primaries in the sRGB specification are
+ * red xy: {0.6400, 0.3300, 1.0}
+ * green xy: {0.3000, 0.6000, 1.0}
+ * blue xy: {0.1500, 0.0600, 1.0}
+ *
+ * The sRGB primaries given below are "pre-quantized" to compensate
+ * for hexadecimal quantization during the profile-making process.
+ * Unless the profile-making code compensates for this quantization,
+ * the resulting profile's red, green, and blue colorants will deviate
+ * slightly from the correct XYZ values.
+ *
+ * LCMS2 doesn't compensate for hexadecimal quantization. The
+ * "pre-quantized" primaries below were back-calculated from the
+ * ArgyllCMS sRGB.icm profile. The resulting sRGB profile's colorants
+ * exactly matches the ArgyllCMS sRGB.icm profile colorants.
+ *
+ * Return value: the sRGB #GimpColorProfile.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_rgb_srgb (void)
+{
+ static GimpColorProfile *profile = NULL;
+
+ const guint8 *data;
+ gsize length;
+
+ if (G_UNLIKELY (profile == NULL))
+ {
+ cmsHPROFILE lcms_profile = gimp_color_profile_new_rgb_srgb_internal ();
+
+ profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
+
+ cmsCloseProfile (lcms_profile);
+ }
+
+ data = gimp_color_profile_get_icc_profile (profile, &length);
+
+ return gimp_color_profile_new_from_icc_profile (data, length, NULL);
+}
+
+static cmsHPROFILE
+gimp_color_profile_new_rgb_srgb_linear_internal (void)
+{
+ cmsHPROFILE profile;
+
+ /* white point is D65 from the sRGB specs */
+ cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
+
+ /* primaries are ITU‐R BT.709‐5 (xYY), which are also the primaries
+ * from the sRGB specs, modified to properly account for hexadecimal
+ * quantization during the profile making process.
+ */
+ cmsCIExyYTRIPLE primaries =
+ {
+ /* R { 0.6400, 0.3300, 1.0 }, */
+ /* G { 0.3000, 0.6000, 1.0 }, */
+ /* B { 0.1500, 0.0600, 1.0 } */
+ /* R */ { 0.639998686, 0.330010138, 1.0 },
+ /* G */ { 0.300003784, 0.600003357, 1.0 },
+ /* B */ { 0.150002046, 0.059997204, 1.0 }
+ };
+
+ cmsToneCurve *curve[3];
+
+ /* linear light */
+ curve[0] = curve[1] = curve[2] = cmsBuildGamma (NULL, 1.0);
+
+ profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
+
+ cmsFreeToneCurve (curve[0]);
+
+ gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
+ "GIMP built-in Linear sRGB");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
+ "GIMP");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
+ "Linear sRGB");
+ gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
+ "Public Domain");
+
+ return profile;
+}
+
+/**
+ * gimp_color_profile_new_rgb_srgb_linear:
+ *
+ * This function creates a profile for babl_model("RGB"). Please
+ * somebody write something smarter here.
+ *
+ * Return value: the linear RGB #GimpColorProfile.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_rgb_srgb_linear (void)
+{
+ static GimpColorProfile *profile = NULL;
+
+ const guint8 *data;
+ gsize length;
+
+ if (G_UNLIKELY (profile == NULL))
+ {
+ cmsHPROFILE lcms_profile = gimp_color_profile_new_rgb_srgb_linear_internal ();
+
+ profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
+
+ cmsCloseProfile (lcms_profile);
+ }
+
+ data = gimp_color_profile_get_icc_profile (profile, &length);
+
+ return gimp_color_profile_new_from_icc_profile (data, length, NULL);
+}
+
+static cmsHPROFILE *
+gimp_color_profile_new_rgb_adobe_internal (void)
+{
+ cmsHPROFILE profile;
+
+ /* white point is D65 from the sRGB specs */
+ cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
+
+ /* AdobeRGB1998 and sRGB have the same white point.
+ *
+ * The primaries below are technically correct, but because of
+ * hexadecimal rounding these primaries don't make a profile that
+ * matches the original.
+ *
+ * cmsCIExyYTRIPLE primaries = {
+ * { 0.6400, 0.3300, 1.0 },
+ * { 0.2100, 0.7100, 1.0 },
+ * { 0.1500, 0.0600, 1.0 }
+ * };
+ */
+ cmsCIExyYTRIPLE primaries =
+ {
+ { 0.639996511, 0.329996864, 1.0 },
+ { 0.210005295, 0.710004866, 1.0 },
+ { 0.149997606, 0.060003644, 1.0 }
+ };
+
+ cmsToneCurve *curve[3];
+
+ /* gamma 2.2 */
+ curve[0] = curve[1] = curve[2] = cmsBuildGamma (NULL, 2.19921875);
+
+ profile = cmsCreateRGBProfile (&whitepoint, &primaries, curve);
+
+ cmsFreeToneCurve (curve[0]);
+
+ gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
+ "Compatible with Adobe RGB (1998)");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
+ "GIMP");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
+ "Compatible with Adobe RGB (1998)");
+ gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
+ "Public Domain");
+
+ return profile;
+}
+
+/**
+ * gimp_color_profile_new_rgb_adobe:
+ *
+ * This function creates a profile compatible with AbobeRGB (1998).
+ *
+ * Return value: the AdobeRGB-compatible #GimpColorProfile.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_rgb_adobe (void)
+{
+ static GimpColorProfile *profile = NULL;
+
+ const guint8 *data;
+ gsize length;
+
+ if (G_UNLIKELY (profile == NULL))
+ {
+ cmsHPROFILE lcms_profile = gimp_color_profile_new_rgb_adobe_internal ();
+
+ profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
+
+ cmsCloseProfile (lcms_profile);
+ }
+
+ data = gimp_color_profile_get_icc_profile (profile, &length);
+
+ return gimp_color_profile_new_from_icc_profile (data, length, NULL);
+}
+
+static cmsHPROFILE *
+gimp_color_profile_new_d65_gray_srgb_trc_internal (void)
+{
+ cmsHPROFILE profile;
+
+ /* white point is D65 from the sRGB specs */
+ cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
+
+ cmsFloat64Number srgb_parameters[5] =
+ { 2.4, 1.0 / 1.055, 0.055 / 1.055, 1.0 / 12.92, 0.04045 };
+
+ cmsToneCurve *curve = cmsBuildParametricToneCurve (NULL, 4,
+ srgb_parameters);
+
+ profile = cmsCreateGrayProfile (&whitepoint, curve);
+
+ cmsFreeToneCurve (curve);
+
+ gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
+ "GIMP built-in D65 Grayscale with sRGB TRC");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
+ "GIMP");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
+ "D65 Grayscale with sRGB TRC");
+ gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
+ "Public Domain");
+
+ return profile;
+}
+
+/**
+ * gimp_color_profile_new_d65_gray_srgb_trc
+ *
+ * This function creates a grayscale #GimpColorProfile with an
+ * sRGB TRC. See gimp_color_profile_new_rgb_srgb().
+ *
+ * Return value: the sRGB-gamma grayscale #GimpColorProfile.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_d65_gray_srgb_trc (void)
+{
+ static GimpColorProfile *profile = NULL;
+
+ const guint8 *data;
+ gsize length;
+
+ if (G_UNLIKELY (profile == NULL))
+ {
+ cmsHPROFILE lcms_profile = gimp_color_profile_new_d65_gray_srgb_trc_internal ();
+
+ profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
+
+ cmsCloseProfile (lcms_profile);
+ }
+
+ data = gimp_color_profile_get_icc_profile (profile, &length);
+
+ return gimp_color_profile_new_from_icc_profile (data, length, NULL);
+}
+
+static cmsHPROFILE
+gimp_color_profile_new_d65_gray_linear_internal (void)
+{
+ cmsHPROFILE profile;
+
+ /* white point is D65 from the sRGB specs */
+ cmsCIExyY whitepoint = { 0.3127, 0.3290, 1.0 };
+
+ cmsToneCurve *curve = cmsBuildGamma (NULL, 1.0);
+
+ profile = cmsCreateGrayProfile (&whitepoint, curve);
+
+ cmsFreeToneCurve (curve);
+
+ gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
+ "GIMP built-in D65 Linear Grayscale");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
+ "GIMP");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
+ "D65 Linear Grayscale");
+ gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
+ "Public Domain");
+
+ return profile;
+}
+
+/**
+ * gimp_color_profile_new_d65_gray_srgb_gray:
+ *
+ * This function creates a profile for babl_model("Y"). Please
+ * somebody write something smarter here.
+ *
+ * Return value: the linear grayscale #GimpColorProfile.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_d65_gray_linear (void)
+{
+ static GimpColorProfile *profile = NULL;
+
+ const guint8 *data;
+ gsize length;
+
+ if (G_UNLIKELY (profile == NULL))
+ {
+ cmsHPROFILE lcms_profile = gimp_color_profile_new_d65_gray_linear_internal ();
+
+ profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
+
+ cmsCloseProfile (lcms_profile);
+ }
+
+ data = gimp_color_profile_get_icc_profile (profile, &length);
+
+ return gimp_color_profile_new_from_icc_profile (data, length, NULL);
+}
+
+static cmsHPROFILE *
+gimp_color_profile_new_d50_gray_lab_trc_internal (void)
+{
+ cmsHPROFILE profile;
+
+ /* white point is D50 from the ICC profile illuminant specs */
+ cmsCIExyY whitepoint = {0.345702915, 0.358538597, 1.0};
+
+ cmsFloat64Number lab_parameters[5] =
+ { 3.0, 1.0 / 1.16, 0.16 / 1.16, 2700.0 / 24389.0, 0.08000 };
+
+ cmsToneCurve *curve = cmsBuildParametricToneCurve (NULL, 4,
+ lab_parameters);
+
+ profile = cmsCreateGrayProfile (&whitepoint, curve);
+
+ cmsFreeToneCurve (curve);
+
+ gimp_color_profile_set_tag (profile, cmsSigProfileDescriptionTag,
+ "GIMP built-in D50 Grayscale with LAB L TRC");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceMfgDescTag,
+ "GIMP");
+ gimp_color_profile_set_tag (profile, cmsSigDeviceModelDescTag,
+ "D50 Grayscale with LAB L TRC");
+ gimp_color_profile_set_tag (profile, cmsSigCopyrightTag,
+ "Public Domain");
+
+ return profile;
+}
+
+
+/**
+ * gimp_color_profile_new_d50_gray_lab_trc
+ *
+ * This function creates a grayscale #GimpColorProfile with the
+ * D50 ICC profile illuminant as the profile white point and the
+ * LAB companding curve as the TRC.
+ *
+ * Return value: a gray profile with the D50 ICC profile illuminant
+ * as the profile white point and the LAB companding curve as the TRC.
+ * as the TRC.
+ *
+ * Since: 2.10
+ **/
+GimpColorProfile *
+gimp_color_profile_new_d50_gray_lab_trc (void)
+{
+ static GimpColorProfile *profile = NULL;
+
+ const guint8 *data;
+ gsize length;
+
+ if (G_UNLIKELY (profile == NULL))
+ {
+ cmsHPROFILE lcms_profile = gimp_color_profile_new_d50_gray_lab_trc_internal ();
+
+ profile = gimp_color_profile_new_from_lcms_profile (lcms_profile, NULL);
+
+ cmsCloseProfile (lcms_profile);
+ }
+
+ data = gimp_color_profile_get_icc_profile (profile, &length);
+
+ return gimp_color_profile_new_from_icc_profile (data, length, NULL);
+}
+
+/**
+ * gimp_color_profile_get_space:
+ * @profile: a #GimpColorProfile
+ * @intent: a #GimpColorRenderingIntent
+ * @error: return location for #GError
+ *
+ * This function returns the #Babl space of @profile, for the
+ * specified @intent.
+ *
+ * Return value: the new #Babl space.
+ *
+ * Since: 2.10.6
+ **/
+const Babl *
+gimp_color_profile_get_space (GimpColorProfile *profile,
+ GimpColorRenderingIntent intent,
+ GError **error)
+{
+ const Babl *space;
+ const gchar *babl_error = NULL;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ space = babl_icc_make_space ((const gchar *) profile->priv->data,
+ profile->priv->length,
+ (BablIccIntent) intent,
+ &babl_error);
+
+ if (! space)
+ g_set_error (error, GIMP_COLOR_PROFILE_ERROR, 0,
+ "%s: %s",
+ gimp_color_profile_get_label (profile), babl_error);
+
+ return space;
+}
+
+/**
+ * gimp_color_profile_get_format:
+ * @profile: a #GimpColorProfile
+ * @format: a #Babl format
+ * @intent: a #GimpColorRenderingIntent
+ * @error: return location for #GError
+ *
+ * This function takes a #GimpColorProfile and a #Babl format and
+ * returns a new #Babl format with @profile's RGB primaries and TRC,
+ * and @format's pixel layout.
+ *
+ * Return value: the new #Babl format.
+ *
+ * Since: 2.10
+ **/
+const Babl *
+gimp_color_profile_get_format (GimpColorProfile *profile,
+ const Babl *format,
+ GimpColorRenderingIntent intent,
+ GError **error)
+{
+ const Babl *space;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (profile), NULL);
+ g_return_val_if_fail (format != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ space = gimp_color_profile_get_space (profile, intent, error);
+
+ if (! space)
+ return NULL;
+
+ return babl_format_with_space (babl_get_name (format), space);
+}
+
+/**
+ * gimp_color_profile_get_lcms_format:
+ * @format: a #Babl format
+ * @lcms_format: return location for an lcms format
+ *
+ * This function takes a #Babl format and returns the lcms format to
+ * be used with that @format. It also returns a #Babl format to be
+ * used instead of the passed @format, which usually is the same as
+ * @format, unless lcms doesn't support @format.
+ *
+ * Note that this function currently only supports RGB, RGBA, R'G'B',
+ * R'G'B'A, Y, YA, Y', Y'A and the cairo-RGB24 and cairo-ARGB32 formats.
+ *
+ * Return value: the #Babl format to be used instead of @format, or %NULL
+ * if the passed @format is not supported at all.
+ *
+ * Since: 2.10
+ **/
+const Babl *
+gimp_color_profile_get_lcms_format (const Babl *format,
+ guint32 *lcms_format)
+{
+ const Babl *output_format = NULL;
+ const Babl *type;
+ const Babl *model;
+ gboolean has_alpha;
+ gboolean rgb = FALSE;
+ gboolean gray = FALSE;
+ gboolean cmyk = FALSE;
+ gboolean linear = FALSE;
+
+ g_return_val_if_fail (format != NULL, NULL);
+ g_return_val_if_fail (lcms_format != NULL, NULL);
+
+ has_alpha = babl_format_has_alpha (format);
+ type = babl_format_get_type (format, 0);
+ model = babl_format_get_model (format);
+
+ if (format == babl_format ("cairo-RGB24"))
+ {
+#if G_BYTE_ORDER == G_LITTLE_ENDIAN
+ *lcms_format = TYPE_BGRA_8;
+#else
+ *lcms_format = TYPE_ARGB_8;
+#endif
+
+ return format;
+ }
+ else if (format == babl_format ("cairo-ARGB32"))
+ {
+ rgb = TRUE;
+ }
+ else if (model == babl_model ("RGB") ||
+ model == babl_model ("RGBA") ||
+ model == babl_model ("RaGaBaA"))
+ {
+ rgb = TRUE;
+ linear = TRUE;
+ }
+ else if (model == babl_model ("R'G'B'") ||
+ model == babl_model ("R'G'B'A") ||
+ model == babl_model ("R'aG'aB'aA"))
+ {
+ rgb = TRUE;
+ }
+ else if (model == babl_model ("Y") ||
+ model == babl_model ("YA") ||
+ model == babl_model ("YaA"))
+ {
+ gray = TRUE;
+ linear = TRUE;
+ }
+ else if (model == babl_model ("Y'") ||
+ model == babl_model ("Y'A") ||
+ model == babl_model ("Y'aA"))
+ {
+ gray = TRUE;
+ }
+ else if (model == babl_model ("CMYK"))
+#if 0
+ /* FIXME missing from babl */
+ || model == babl_model ("CMYKA"))
+#endif
+ {
+ cmyk = TRUE;
+ }
+ else if (model == babl_model ("CIE Lab") ||
+ model == babl_model ("CIE Lab alpha") ||
+ model == babl_model ("CIE LCH(ab)") ||
+ model == babl_model ("CIE LCH(ab) alpha"))
+ {
+ if (has_alpha)
+ {
+ *lcms_format = TYPE_RGBA_FLT;
+
+ return babl_format ("RGBA float");
+ }
+ else
+ {
+ *lcms_format = TYPE_RGB_FLT;
+
+ return babl_format ("RGB float");
+ }
+ }
+ else if (babl_format_is_palette (format))
+ {
+ if (has_alpha)
+ {
+ *lcms_format = TYPE_RGBA_8;
+
+ return babl_format ("R'G'B'A u8");
+ }
+ else
+ {
+ *lcms_format = TYPE_RGB_8;
+
+ return babl_format ("R'G'B' u8");
+ }
+ }
+ else
+ {
+ g_printerr ("format not supported: %s\n"
+ "has_alpha = %s\n"
+ "type = %s\n"
+ "model = %s\n",
+ babl_get_name (format),
+ has_alpha ? "TRUE" : "FALSE",
+ babl_get_name (type),
+ babl_get_name (model));
+ g_return_val_if_reached (NULL);
+ }
+
+ *lcms_format = 0;
+
+ #define FIND_FORMAT_FOR_TYPE(babl_t, lcms_t) \
+ do \
+ { \
+ if (has_alpha) \
+ { \
+ if (rgb) \
+ { \
+ *lcms_format = TYPE_RGBA_##lcms_t; \
+ \
+ if (linear) \
+ output_format = babl_format ("RGBA " babl_t); \
+ else \
+ output_format = babl_format ("R'G'B'A " babl_t); \
+ } \
+ else if (gray) \
+ { \
+ *lcms_format = TYPE_GRAYA_##lcms_t; \
+ \
+ if (linear) \
+ output_format = babl_format ("YA " babl_t); \
+ else \
+ output_format = babl_format ("Y'A " babl_t); \
+ } \
+ else if (cmyk) \
+ { \
+ *lcms_format = TYPE_CMYKA_##lcms_t; \
+ \
+ output_format = format; \
+ } \
+ } \
+ else \
+ { \
+ if (rgb) \
+ { \
+ *lcms_format = TYPE_RGB_##lcms_t; \
+ \
+ if (linear) \
+ output_format = babl_format ("RGB " babl_t); \
+ else \
+ output_format = babl_format ("R'G'B' " babl_t); \
+ } \
+ else if (gray) \
+ { \
+ *lcms_format = TYPE_GRAY_##lcms_t; \
+ \
+ if (linear) \
+ output_format = babl_format ("Y " babl_t); \
+ else \
+ output_format = babl_format ("Y' " babl_t); \
+ } \
+ else if (cmyk) \
+ { \
+ *lcms_format = TYPE_CMYK_##lcms_t; \
+ \
+ output_format = format; \
+ } \
+ } \
+ } \
+ while (FALSE)
+
+ if (type == babl_type ("u8"))
+ FIND_FORMAT_FOR_TYPE ("u8", 8);
+ else if (type == babl_type ("u16"))
+ FIND_FORMAT_FOR_TYPE ("u16", 16);
+ else if (type == babl_type ("half")) /* 16-bit floating point (half) */
+ FIND_FORMAT_FOR_TYPE ("half", HALF_FLT);
+ else if (type == babl_type ("float"))
+ FIND_FORMAT_FOR_TYPE ("float", FLT);
+ else if (type == babl_type ("double"))
+ FIND_FORMAT_FOR_TYPE ("double", DBL);
+
+ if (*lcms_format == 0)
+ {
+ g_printerr ("%s: format %s not supported, "
+ "falling back to float\n",
+ G_STRFUNC, babl_get_name (format));
+
+ rgb = ! gray;
+
+ FIND_FORMAT_FOR_TYPE ("float", FLT);
+
+ g_return_val_if_fail (output_format != NULL, NULL);
+ }
+
+ #undef FIND_FORMAT_FOR_TYPE
+
+ return output_format;
+}
diff --git a/libgimpcolor/gimpcolorprofile.h b/libgimpcolor/gimpcolorprofile.h
new file mode 100644
index 0000000..c09470b
--- /dev/null
+++ b/libgimpcolor/gimpcolorprofile.h
@@ -0,0 +1,128 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimpcolorprofile.h
+ * Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
+ * Elle Stone <ellestone@ninedegreesbelow.com>
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_COLOR_PROFILE_H__
+#define __GIMP_COLOR_PROFILE_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+#define GIMP_TYPE_COLOR_PROFILE (gimp_color_profile_get_type ())
+#define GIMP_COLOR_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_COLOR_PROFILE, GimpColorProfile))
+#define GIMP_COLOR_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_COLOR_PROFILE, GimpColorProfileClass))
+#define GIMP_IS_COLOR_PROFILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_COLOR_PROFILE))
+#define GIMP_IS_COLOR_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_COLOR_PROFILE))
+#define GIMP_COLOR_PROFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_COLOR_PROFILE, GimpColorProfileClass))
+
+
+typedef struct _GimpColorProfileClass GimpColorProfileClass;
+typedef struct _GimpColorProfilePrivate GimpColorProfilePrivate;
+
+struct _GimpColorProfile
+{
+ GObject parent_instance;
+
+ GimpColorProfilePrivate *priv;
+};
+
+struct _GimpColorProfileClass
+{
+ GObjectClass parent_class;
+
+ /* Padding for future expansion */
+ void (* _gimp_reserved1) (void);
+ void (* _gimp_reserved2) (void);
+ void (* _gimp_reserved3) (void);
+ void (* _gimp_reserved4) (void);
+};
+
+
+GType gimp_color_profile_get_type (void) G_GNUC_CONST;
+
+GimpColorProfile * gimp_color_profile_new_rgb_srgb (void);
+GimpColorProfile * gimp_color_profile_new_rgb_srgb_linear (void);
+GimpColorProfile * gimp_color_profile_new_rgb_adobe (void);
+
+GimpColorProfile * gimp_color_profile_new_d65_gray_srgb_trc (void);
+GimpColorProfile * gimp_color_profile_new_d65_gray_linear (void);
+GimpColorProfile * gimp_color_profile_new_d50_gray_lab_trc (void);
+
+GimpColorProfile *
+ gimp_color_profile_new_srgb_trc_from_color_profile (GimpColorProfile *profile);
+GimpColorProfile *
+ gimp_color_profile_new_linear_from_color_profile (GimpColorProfile *profile);
+
+GimpColorProfile * gimp_color_profile_new_from_file (GFile *file,
+ GError **error);
+
+GimpColorProfile * gimp_color_profile_new_from_icc_profile (const guint8 *data,
+ gsize length,
+ GError **error);
+GimpColorProfile * gimp_color_profile_new_from_lcms_profile (gpointer lcms_profile,
+ GError **error);
+
+gboolean gimp_color_profile_save_to_file (GimpColorProfile *profile,
+ GFile *file,
+ GError **error);
+
+const guint8 * gimp_color_profile_get_icc_profile (GimpColorProfile *profile,
+ gsize *length);
+gpointer gimp_color_profile_get_lcms_profile (GimpColorProfile *profile);
+
+const gchar * gimp_color_profile_get_description (GimpColorProfile *profile);
+const gchar * gimp_color_profile_get_manufacturer (GimpColorProfile *profile);
+const gchar * gimp_color_profile_get_model (GimpColorProfile *profile);
+const gchar * gimp_color_profile_get_copyright (GimpColorProfile *profile);
+
+const gchar * gimp_color_profile_get_label (GimpColorProfile *profile);
+const gchar * gimp_color_profile_get_summary (GimpColorProfile *profile);
+
+gboolean gimp_color_profile_is_equal (GimpColorProfile *profile1,
+ GimpColorProfile *profile2);
+
+gboolean gimp_color_profile_is_rgb (GimpColorProfile *profile);
+gboolean gimp_color_profile_is_gray (GimpColorProfile *profile);
+gboolean gimp_color_profile_is_cmyk (GimpColorProfile *profile);
+
+gboolean gimp_color_profile_is_linear (GimpColorProfile *profile);
+
+const Babl * gimp_color_profile_get_space (GimpColorProfile *profile,
+ GimpColorRenderingIntent intent,
+ GError **error);
+const Babl * gimp_color_profile_get_format (GimpColorProfile *profile,
+ const Babl *format,
+ GimpColorRenderingIntent intent,
+ GError **error);
+
+const Babl * gimp_color_profile_get_lcms_format (const Babl *format,
+ guint32 *lcms_format);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_COLOR_PROFILE_H__ */
diff --git a/libgimpcolor/gimpcolorspace.c b/libgimpcolor/gimpcolorspace.c
new file mode 100644
index 0000000..b8885ce
--- /dev/null
+++ b/libgimpcolor/gimpcolorspace.c
@@ -0,0 +1,1103 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <babl/babl.h>
+#include <glib-object.h>
+
+#include "libgimpmath/gimpmath.h"
+
+#include "gimpcolortypes.h"
+
+#include "gimpcolorspace.h"
+#include "gimprgb.h"
+#include "gimphsv.h"
+
+
+
+/**
+ * SECTION: gimpcolorspace
+ * @title: GimpColorSpace
+ * @short_description: Utility functions which convert colors between
+ * different color models.
+ *
+ * When programming pixel data manipulation functions you will often
+ * use algorithms operating on a color model different from the one
+ * GIMP uses. This file provides utility functions to convert colors
+ * between different color spaces.
+ **/
+
+
+#define GIMP_HSV_UNDEFINED -1.0
+#define GIMP_HSL_UNDEFINED -1.0
+
+/*********************************
+ * color conversion routines *
+ *********************************/
+
+
+/* GimpRGB functions */
+
+
+/**
+ * gimp_rgb_to_hsv:
+ * @rgb: A color value in the RGB colorspace
+ * @hsv: The value converted to the HSV colorspace
+ *
+ * Does a conversion from RGB to HSV (Hue, Saturation,
+ * Value) colorspace.
+ **/
+void
+gimp_rgb_to_hsv (const GimpRGB *rgb,
+ GimpHSV *hsv)
+{
+ gdouble max, min, delta;
+
+ g_return_if_fail (rgb != NULL);
+ g_return_if_fail (hsv != NULL);
+
+ max = gimp_rgb_max (rgb);
+ min = gimp_rgb_min (rgb);
+
+ hsv->v = max;
+ delta = max - min;
+
+ if (delta > 0.0001)
+ {
+ hsv->s = delta / max;
+
+ if (rgb->r == max)
+ {
+ hsv->h = (rgb->g - rgb->b) / delta;
+ if (hsv->h < 0.0)
+ hsv->h += 6.0;
+ }
+ else if (rgb->g == max)
+ {
+ hsv->h = 2.0 + (rgb->b - rgb->r) / delta;
+ }
+ else
+ {
+ hsv->h = 4.0 + (rgb->r - rgb->g) / delta;
+ }
+
+ hsv->h /= 6.0;
+ }
+ else
+ {
+ hsv->s = 0.0;
+ hsv->h = 0.0;
+ }
+
+ hsv->a = rgb->a;
+}
+
+/**
+ * gimp_hsv_to_rgb:
+ * @hsv: A color value in the HSV colorspace
+ * @rgb: The returned RGB value.
+ *
+ * Converts a color value from HSV to RGB colorspace
+ **/
+void
+gimp_hsv_to_rgb (const GimpHSV *hsv,
+ GimpRGB *rgb)
+{
+ gint i;
+ gdouble f, w, q, t;
+
+ gdouble hue;
+
+ g_return_if_fail (rgb != NULL);
+ g_return_if_fail (hsv != NULL);
+
+ if (hsv->s == 0.0)
+ {
+ rgb->r = hsv->v;
+ rgb->g = hsv->v;
+ rgb->b = hsv->v;
+ }
+ else
+ {
+ hue = hsv->h;
+
+ if (hue == 1.0)
+ hue = 0.0;
+
+ hue *= 6.0;
+
+ i = (gint) hue;
+ f = hue - i;
+ w = hsv->v * (1.0 - hsv->s);
+ q = hsv->v * (1.0 - (hsv->s * f));
+ t = hsv->v * (1.0 - (hsv->s * (1.0 - f)));
+
+ switch (i)
+ {
+ case 0:
+ rgb->r = hsv->v;
+ rgb->g = t;
+ rgb->b = w;
+ break;
+ case 1:
+ rgb->r = q;
+ rgb->g = hsv->v;
+ rgb->b = w;
+ break;
+ case 2:
+ rgb->r = w;
+ rgb->g = hsv->v;
+ rgb->b = t;
+ break;
+ case 3:
+ rgb->r = w;
+ rgb->g = q;
+ rgb->b = hsv->v;
+ break;
+ case 4:
+ rgb->r = t;
+ rgb->g = w;
+ rgb->b = hsv->v;
+ break;
+ case 5:
+ rgb->r = hsv->v;
+ rgb->g = w;
+ rgb->b = q;
+ break;
+ }
+ }
+
+ rgb->a = hsv->a;
+}
+
+
+/**
+ * gimp_rgb_to_hsl:
+ * @rgb: A color value in the RGB colorspace
+ * @hsl: The value converted to HSL
+ *
+ * Convert an RGB color value to a HSL (Hue, Saturation, Lightness)
+ * color value.
+ **/
+void
+gimp_rgb_to_hsl (const GimpRGB *rgb,
+ GimpHSL *hsl)
+{
+ gdouble max, min, delta;
+
+ g_return_if_fail (rgb != NULL);
+ g_return_if_fail (hsl != NULL);
+
+ max = gimp_rgb_max (rgb);
+ min = gimp_rgb_min (rgb);
+
+ hsl->l = (max + min) / 2.0;
+
+ if (max == min)
+ {
+ hsl->s = 0.0;
+ hsl->h = GIMP_HSL_UNDEFINED;
+ }
+ else
+ {
+ if (hsl->l <= 0.5)
+ hsl->s = (max - min) / (max + min);
+ else
+ hsl->s = (max - min) / (2.0 - max - min);
+
+ delta = max - min;
+
+ if (delta == 0.0)
+ delta = 1.0;
+
+ if (rgb->r == max)
+ {
+ hsl->h = (rgb->g - rgb->b) / delta;
+ }
+ else if (rgb->g == max)
+ {
+ hsl->h = 2.0 + (rgb->b - rgb->r) / delta;
+ }
+ else
+ {
+ hsl->h = 4.0 + (rgb->r - rgb->g) / delta;
+ }
+
+ hsl->h /= 6.0;
+
+ if (hsl->h < 0.0)
+ hsl->h += 1.0;
+ }
+
+ hsl->a = rgb->a;
+}
+
+static inline gdouble
+gimp_hsl_value (gdouble n1,
+ gdouble n2,
+ gdouble hue)
+{
+ gdouble val;
+
+ if (hue > 6.0)
+ hue -= 6.0;
+ else if (hue < 0.0)
+ hue += 6.0;
+
+ if (hue < 1.0)
+ val = n1 + (n2 - n1) * hue;
+ else if (hue < 3.0)
+ val = n2;
+ else if (hue < 4.0)
+ val = n1 + (n2 - n1) * (4.0 - hue);
+ else
+ val = n1;
+
+ return val;
+}
+
+
+/**
+ * gimp_hsl_to_rgb:
+ * @hsl: A color value in the HSL colorspace
+ * @rgb: The value converted to a value in the RGB colorspace
+ *
+ * Convert a HSL color value to an RGB color value.
+ **/
+void
+gimp_hsl_to_rgb (const GimpHSL *hsl,
+ GimpRGB *rgb)
+{
+ g_return_if_fail (hsl != NULL);
+ g_return_if_fail (rgb != NULL);
+
+ if (hsl->s == 0)
+ {
+ /* achromatic case */
+ rgb->r = hsl->l;
+ rgb->g = hsl->l;
+ rgb->b = hsl->l;
+ }
+ else
+ {
+ gdouble m1, m2;
+
+ if (hsl->l <= 0.5)
+ m2 = hsl->l * (1.0 + hsl->s);
+ else
+ m2 = hsl->l + hsl->s - hsl->l * hsl->s;
+
+ m1 = 2.0 * hsl->l - m2;
+
+ rgb->r = gimp_hsl_value (m1, m2, hsl->h * 6.0 + 2.0);
+ rgb->g = gimp_hsl_value (m1, m2, hsl->h * 6.0);
+ rgb->b = gimp_hsl_value (m1, m2, hsl->h * 6.0 - 2.0);
+ }
+
+ rgb->a = hsl->a;
+}
+
+
+/**
+ * gimp_rgb_to_cmyk:
+ * @rgb: A value in the RGB colorspace
+ * @pullout: A scaling value (0-1) indicating how much black should be
+ * pulled out
+ * @cmyk: The input value naively converted to the CMYK colorspace
+ *
+ * Does a naive conversion from RGB to CMYK colorspace. A simple
+ * formula that doesn't take any color-profiles into account is used.
+ * The amount of black pullout how can be controlled via the @pullout
+ * parameter. A @pullout value of 0 makes this a conversion to CMY.
+ * A value of 1 causes the maximum amount of black to be pulled out.
+ **/
+void
+gimp_rgb_to_cmyk (const GimpRGB *rgb,
+ gdouble pullout,
+ GimpCMYK *cmyk)
+{
+ gdouble c, m, y, k;
+
+ g_return_if_fail (rgb != NULL);
+ g_return_if_fail (cmyk != NULL);
+
+ c = 1.0 - rgb->r;
+ m = 1.0 - rgb->g;
+ y = 1.0 - rgb->b;
+
+ k = 1.0;
+ if (c < k) k = c;
+ if (m < k) k = m;
+ if (y < k) k = y;
+
+ k *= pullout;
+
+ if (k < 1.0)
+ {
+ cmyk->c = (c - k) / (1.0 - k);
+ cmyk->m = (m - k) / (1.0 - k);
+ cmyk->y = (y - k) / (1.0 - k);
+ }
+ else
+ {
+ cmyk->c = 0.0;
+ cmyk->m = 0.0;
+ cmyk->y = 0.0;
+ }
+
+ cmyk->k = k;
+ cmyk->a = rgb->a;
+}
+
+/**
+ * gimp_cmyk_to_rgb:
+ * @cmyk: A color value in the CMYK colorspace
+ * @rgb: The value converted to the RGB colorspace
+ *
+ * Does a simple transformation from the CMYK colorspace to the RGB
+ * colorspace, without taking color profiles into account.
+ **/
+void
+gimp_cmyk_to_rgb (const GimpCMYK *cmyk,
+ GimpRGB *rgb)
+{
+ gdouble c, m, y, k;
+
+ g_return_if_fail (cmyk != NULL);
+ g_return_if_fail (rgb != NULL);
+
+ k = cmyk->k;
+
+ if (k < 1.0)
+ {
+ c = cmyk->c * (1.0 - k) + k;
+ m = cmyk->m * (1.0 - k) + k;
+ y = cmyk->y * (1.0 - k) + k;
+ }
+ else
+ {
+ c = 1.0;
+ m = 1.0;
+ y = 1.0;
+ }
+
+ rgb->r = 1.0 - c;
+ rgb->g = 1.0 - m;
+ rgb->b = 1.0 - y;
+ rgb->a = cmyk->a;
+}
+
+
+#define GIMP_RETURN_RGB(x, y, z) { rgb->r = x; rgb->g = y; rgb->b = z; return; }
+
+/****************************************************************************
+ * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms.
+ * Pure red always maps to 6 in this implementation. Therefore UNDEFINED can
+ * be defined as 0 in situations where only unsigned numbers are desired.
+ ****************************************************************************/
+
+/**
+ * gimp_rgb_to_hwb:
+ * @rgb: A color value in the RGB colorspace
+ * @hue: The hue value of the above color, in the range 0 to 6
+ * @whiteness: The whiteness value of the above color, in the range 0 to 1
+ * @blackness: The blackness value of the above color, in the range 0 to 1
+ *
+ * Theoretically, hue 0 (pure red) is identical to hue 6 in these transforms.
+ * Pure red always maps to 6 in this implementation. Therefore UNDEFINED can
+ * be defined as 0 in situations where only unsigned numbers are desired.
+ *
+ * RGB are each on [0, 1]. Whiteness and Blackness are returned in the
+ * range [0, 1] and H is returned in the range [0, 6]. If W == 1 - B, H is
+ * undefined.
+ **/
+void
+gimp_rgb_to_hwb (const GimpRGB *rgb,
+ gdouble *hue,
+ gdouble *whiteness,
+ gdouble *blackness)
+{
+ /* RGB are each on [0, 1]. W and B are returned on [0, 1] and H is */
+ /* returned on [0, 6]. Exception: H is returned UNDEFINED if W == 1 - B. */
+ /* ====================================================================== */
+
+ gdouble R = rgb->r, G = rgb->g, B = rgb->b, w, v, b, f;
+ gint i;
+
+ w = gimp_rgb_min (rgb);
+ v = gimp_rgb_max (rgb);
+ b = 1.0 - v;
+
+ if (v == w)
+ {
+ *hue = GIMP_HSV_UNDEFINED;
+ *whiteness = w;
+ *blackness = b;
+ }
+ else
+ {
+ f = (R == w) ? G - B : ((G == w) ? B - R : R - G);
+ i = (R == w) ? 3.0 : ((G == w) ? 5.0 : 1.0);
+
+ *hue = (360.0 / 6.0) * (i - f / (v - w));
+ *whiteness = w;
+ *blackness = b;
+ }
+}
+
+/**
+ * gimp_hwb_to_rgb:
+ * @hue: A hue value, in the range 0 to 6
+ * @whiteness: A whiteness value, in the range 0 to 1
+ * @blackness: A blackness value, in the range 0 to 1
+ * @rgb: The above color converted to the RGB colorspace
+ *
+ * H is defined in the range [0, 6] or UNDEFINED, B and W are both in the
+ * range [0, 1]. The returned RGB values are all in the range [0, 1].
+ **/
+void
+gimp_hwb_to_rgb (gdouble hue,
+ gdouble whiteness,
+ gdouble blackness,
+ GimpRGB *rgb)
+{
+ /* H is given on [0, 6] or UNDEFINED. whiteness and
+ * blackness are given on [0, 1].
+ * RGB are each returned on [0, 1].
+ */
+
+ gdouble h = hue, w = whiteness, b = blackness, v, n, f;
+ gint i;
+
+ h = 6.0 * h/ 360.0;
+
+ v = 1.0 - b;
+ if (h == GIMP_HSV_UNDEFINED)
+ {
+ rgb->r = v;
+ rgb->g = v;
+ rgb->b = v;
+ }
+ else
+ {
+ i = floor (h);
+ f = h - i;
+
+ if (i & 1)
+ f = 1.0 - f; /* if i is odd */
+
+ n = w + f * (v - w); /* linear interpolation between w and v */
+
+ switch (i)
+ {
+ case 6:
+ case 0: GIMP_RETURN_RGB (v, n, w);
+ break;
+ case 1: GIMP_RETURN_RGB (n, v, w);
+ break;
+ case 2: GIMP_RETURN_RGB (w, v, n);
+ break;
+ case 3: GIMP_RETURN_RGB (w, n, v);
+ break;
+ case 4: GIMP_RETURN_RGB (n, w, v);
+ break;
+ case 5: GIMP_RETURN_RGB (v, w, n);
+ break;
+ }
+ }
+
+}
+
+
+/* gint functions */
+
+/**
+ * gimp_rgb_to_hsv_int:
+ * @red: The red channel value, returns the Hue channel
+ * @green: The green channel value, returns the Saturation channel
+ * @blue: The blue channel value, returns the Value channel
+ *
+ * The arguments are pointers to int representing channel values in
+ * the RGB colorspace, and the values pointed to are all in the range
+ * [0, 255].
+ *
+ * The function changes the arguments to point to the HSV value
+ * corresponding, with the returned values in the following
+ * ranges: H [0, 359], S [0, 255], V [0, 255].
+ **/
+void
+gimp_rgb_to_hsv_int (gint *red,
+ gint *green,
+ gint *blue)
+{
+ gdouble r, g, b;
+ gdouble h, s, v;
+ gint min;
+ gdouble delta;
+
+ r = *red;
+ g = *green;
+ b = *blue;
+
+ if (r > g)
+ {
+ v = MAX (r, b);
+ min = MIN (g, b);
+ }
+ else
+ {
+ v = MAX (g, b);
+ min = MIN (r, b);
+ }
+
+ delta = v - min;
+
+ if (v == 0.0)
+ s = 0.0;
+ else
+ s = delta / v;
+
+ if (s == 0.0)
+ {
+ h = 0.0;
+ }
+ else
+ {
+ if (r == v)
+ h = 60.0 * (g - b) / delta;
+ else if (g == v)
+ h = 120 + 60.0 * (b - r) / delta;
+ else
+ h = 240 + 60.0 * (r - g) / delta;
+
+ if (h < 0.0)
+ h += 360.0;
+
+ if (h > 360.0)
+ h -= 360.0;
+ }
+
+ *red = ROUND (h);
+ *green = ROUND (s * 255.0);
+ *blue = ROUND (v);
+
+ /* avoid the ambiguity of returning different values for the same color */
+ if (*red == 360)
+ *red = 0;
+}
+
+/**
+ * gimp_hsv_to_rgb_int:
+ * @hue: The hue channel, returns the red channel
+ * @saturation: The saturation channel, returns the green channel
+ * @value: The value channel, returns the blue channel
+ *
+ * The arguments are pointers to int, with the values pointed to in the
+ * following ranges: H [0, 360], S [0, 255], V [0, 255].
+ *
+ * The function changes the arguments to point to the RGB value
+ * corresponding, with the returned values all in the range [0, 255].
+ **/
+void
+gimp_hsv_to_rgb_int (gint *hue,
+ gint *saturation,
+ gint *value)
+{
+ gdouble h, s, v, h_temp;
+ gdouble f, p, q, t;
+ gint i;
+
+ if (*saturation == 0)
+ {
+ *hue = *value;
+ *saturation = *value;
+ *value = *value;
+ }
+ else
+ {
+ h = *hue;
+ s = *saturation / 255.0;
+ v = *value / 255.0;
+
+ if (h == 360)
+ h_temp = 0;
+ else
+ h_temp = h;
+
+ h_temp = h_temp / 60.0;
+ i = floor (h_temp);
+ f = h_temp - i;
+ p = v * (1.0 - s);
+ q = v * (1.0 - (s * f));
+ t = v * (1.0 - (s * (1.0 - f)));
+
+ switch (i)
+ {
+ case 0:
+ *hue = ROUND (v * 255.0);
+ *saturation = ROUND (t * 255.0);
+ *value = ROUND (p * 255.0);
+ break;
+
+ case 1:
+ *hue = ROUND (q * 255.0);
+ *saturation = ROUND (v * 255.0);
+ *value = ROUND (p * 255.0);
+ break;
+
+ case 2:
+ *hue = ROUND (p * 255.0);
+ *saturation = ROUND (v * 255.0);
+ *value = ROUND (t * 255.0);
+ break;
+
+ case 3:
+ *hue = ROUND (p * 255.0);
+ *saturation = ROUND (q * 255.0);
+ *value = ROUND (v * 255.0);
+ break;
+
+ case 4:
+ *hue = ROUND (t * 255.0);
+ *saturation = ROUND (p * 255.0);
+ *value = ROUND (v * 255.0);
+ break;
+
+ case 5:
+ *hue = ROUND (v * 255.0);
+ *saturation = ROUND (p * 255.0);
+ *value = ROUND (q * 255.0);
+ break;
+ }
+ }
+}
+
+/**
+ * gimp_rgb_to_hsl_int:
+ * @red: Red channel, returns Hue channel
+ * @green: Green channel, returns Lightness channel
+ * @blue: Blue channel, returns Saturation channel
+ *
+ * The arguments are pointers to int representing channel values in the
+ * RGB colorspace, and the values pointed to are all in the range [0, 255].
+ *
+ * The function changes the arguments to point to the corresponding HLS
+ * value with the values pointed to in the following ranges: H [0, 360],
+ * L [0, 255], S [0, 255].
+ **/
+void
+gimp_rgb_to_hsl_int (gint *red,
+ gint *green,
+ gint *blue)
+{
+ gint r, g, b;
+ gdouble h, s, l;
+ gint min, max;
+ gint delta;
+
+ r = *red;
+ g = *green;
+ b = *blue;
+
+ if (r > g)
+ {
+ max = MAX (r, b);
+ min = MIN (g, b);
+ }
+ else
+ {
+ max = MAX (g, b);
+ min = MIN (r, b);
+ }
+
+ l = (max + min) / 2.0;
+
+ if (max == min)
+ {
+ s = 0.0;
+ h = 0.0;
+ }
+ else
+ {
+ delta = (max - min);
+
+ if (l < 128)
+ s = 255 * (gdouble) delta / (gdouble) (max + min);
+ else
+ s = 255 * (gdouble) delta / (gdouble) (511 - max - min);
+
+ if (r == max)
+ h = (g - b) / (gdouble) delta;
+ else if (g == max)
+ h = 2 + (b - r) / (gdouble) delta;
+ else
+ h = 4 + (r - g) / (gdouble) delta;
+
+ h = h * 42.5;
+
+ if (h < 0)
+ h += 255;
+ else if (h > 255)
+ h -= 255;
+ }
+
+ *red = ROUND (h);
+ *green = ROUND (s);
+ *blue = ROUND (l);
+}
+
+/**
+ * gimp_rgb_to_l_int:
+ * @red: Red channel
+ * @green: Green channel
+ * @blue: Blue channel
+ *
+ * Calculates the lightness value of an RGB triplet with the formula
+ * L = (max(R, G, B) + min (R, G, B)) / 2
+ *
+ * Return value: Luminance value corresponding to the input RGB value
+ **/
+gint
+gimp_rgb_to_l_int (gint red,
+ gint green,
+ gint blue)
+{
+ gint min, max;
+
+ if (red > green)
+ {
+ max = MAX (red, blue);
+ min = MIN (green, blue);
+ }
+ else
+ {
+ max = MAX (green, blue);
+ min = MIN (red, blue);
+ }
+
+ return ROUND ((max + min) / 2.0);
+}
+
+static inline gint
+gimp_hsl_value_int (gdouble n1,
+ gdouble n2,
+ gdouble hue)
+{
+ gdouble value;
+
+ if (hue > 255)
+ hue -= 255;
+ else if (hue < 0)
+ hue += 255;
+
+ if (hue < 42.5)
+ value = n1 + (n2 - n1) * (hue / 42.5);
+ else if (hue < 127.5)
+ value = n2;
+ else if (hue < 170)
+ value = n1 + (n2 - n1) * ((170 - hue) / 42.5);
+ else
+ value = n1;
+
+ return ROUND (value * 255.0);
+}
+
+/**
+ * gimp_hsl_to_rgb_int:
+ * @hue: Hue channel, returns Red channel
+ * @saturation: Saturation channel, returns Green channel
+ * @lightness: Lightness channel, returns Blue channel
+ *
+ * The arguments are pointers to int, with the values pointed to in the
+ * following ranges: H [0, 360], L [0, 255], S [0, 255].
+ *
+ * The function changes the arguments to point to the RGB value
+ * corresponding, with the returned values all in the range [0, 255].
+ **/
+void
+gimp_hsl_to_rgb_int (gint *hue,
+ gint *saturation,
+ gint *lightness)
+{
+ gdouble h, s, l;
+
+ h = *hue;
+ s = *saturation;
+ l = *lightness;
+
+ if (s == 0)
+ {
+ /* achromatic case */
+ *hue = l;
+ *lightness = l;
+ *saturation = l;
+ }
+ else
+ {
+ gdouble m1, m2;
+
+ if (l < 128)
+ m2 = (l * (255 + s)) / 65025.0;
+ else
+ m2 = (l + s - (l * s) / 255.0) / 255.0;
+
+ m1 = (l / 127.5) - m2;
+
+ /* chromatic case */
+ *hue = gimp_hsl_value_int (m1, m2, h + 85);
+ *saturation = gimp_hsl_value_int (m1, m2, h);
+ *lightness = gimp_hsl_value_int (m1, m2, h - 85);
+ }
+}
+
+/**
+ * gimp_rgb_to_cmyk_int:
+ * @red: the red channel; returns the cyan value (0-255)
+ * @green: the green channel; returns the magenta value (0-255)
+ * @blue: the blue channel; returns the yellow value (0-255)
+ * @pullout: the percentage of black to pull out (0-100); returns
+ * the black value (0-255)
+ *
+ * Does a naive conversion from RGB to CMYK colorspace. A simple
+ * formula that doesn't take any color-profiles into account is used.
+ * The amount of black pullout how can be controlled via the @pullout
+ * parameter. A @pullout value of 0 makes this a conversion to CMY.
+ * A value of 100 causes the maximum amount of black to be pulled out.
+ **/
+void
+gimp_rgb_to_cmyk_int (gint *red,
+ gint *green,
+ gint *blue,
+ gint *pullout)
+{
+ gint c, m, y;
+
+ c = 255 - *red;
+ m = 255 - *green;
+ y = 255 - *blue;
+
+ if (*pullout == 0)
+ {
+ *red = c;
+ *green = m;
+ *blue = y;
+ }
+ else
+ {
+ gint k = 255;
+
+ if (c < k) k = c;
+ if (m < k) k = m;
+ if (y < k) k = y;
+
+ k = (k * CLAMP (*pullout, 0, 100)) / 100;
+
+ *red = ((c - k) << 8) / (256 - k);
+ *green = ((m - k) << 8) / (256 - k);
+ *blue = ((y - k) << 8) / (256 - k);
+ *pullout = k;
+ }
+}
+
+/**
+ * gimp_cmyk_to_rgb_int:
+ * @cyan: the cyan channel; returns the red value (0-255)
+ * @magenta: the magenta channel; returns the green value (0-255)
+ * @yellow: the yellow channel; returns the blue value (0-255)
+ * @black: the black channel (0-255); doesn't change
+ *
+ * Does a naive conversion from CMYK to RGB colorspace. A simple
+ * formula that doesn't take any color-profiles into account is used.
+ **/
+void
+gimp_cmyk_to_rgb_int (gint *cyan,
+ gint *magenta,
+ gint *yellow,
+ gint *black)
+{
+ gint c, m, y, k;
+
+ c = *cyan;
+ m = *magenta;
+ y = *yellow;
+ k = *black;
+
+ if (k)
+ {
+ c = ((c * (256 - k)) >> 8) + k;
+ m = ((m * (256 - k)) >> 8) + k;
+ y = ((y * (256 - k)) >> 8) + k;
+ }
+
+ *cyan = 255 - c;
+ *magenta = 255 - m;
+ *yellow = 255 - y;
+}
+
+/**
+ * gimp_rgb_to_hsv4:
+ * @rgb: RGB triplet, rgb[0] is red channel, rgb[1] is green,
+ * rgb[2] is blue (0..255)
+ * @hue: Pointer to hue channel (0..1)
+ * @saturation: Pointer to saturation channel (0..1)
+ * @value: Pointer to value channel (0..1)
+ **/
+void
+gimp_rgb_to_hsv4 (const guchar *rgb,
+ gdouble *hue,
+ gdouble *saturation,
+ gdouble *value)
+{
+ gdouble red, green, blue;
+ gdouble h, s, v;
+ gdouble min, max;
+ gdouble delta;
+
+ red = rgb[0] / 255.0;
+ green = rgb[1] / 255.0;
+ blue = rgb[2] / 255.0;
+
+ if (red > green)
+ {
+ max = MAX (red, blue);
+ min = MIN (green, blue);
+ }
+ else
+ {
+ max = MAX (green, blue);
+ min = MIN (red, blue);
+ }
+
+ v = max;
+
+ if (max != 0.0)
+ s = (max - min) / max;
+ else
+ s = 0.0;
+
+ if (s == 0.0)
+ h = 0.0;
+ else
+ {
+ delta = max - min;
+
+ if (delta == 0.0)
+ delta = 1.0;
+
+ if (red == max)
+ h = (green - blue) / delta;
+ else if (green == max)
+ h = 2 + (blue - red) / delta;
+ else
+ h = 4 + (red - green) / delta;
+
+ h /= 6.0;
+
+ if (h < 0.0)
+ h += 1.0;
+ else if (h > 1.0)
+ h -= 1.0;
+ }
+
+ *hue = h;
+ *saturation = s;
+ *value = v;
+}
+
+/**
+ * gimp_hsv_to_rgb4:
+ * @rgb: RGB triplet, rgb[0] is red channel, rgb[1] is green,
+ * rgb[2] is blue (0..255)
+ * @hue: Hue channel (0..1)
+ * @saturation: Saturation channel (0..1)
+ * @value: Value channel (0..1)
+ **/
+void
+gimp_hsv_to_rgb4 (guchar *rgb,
+ gdouble hue,
+ gdouble saturation,
+ gdouble value)
+{
+ gdouble h, s, v;
+ gdouble f, p, q, t;
+
+ if (saturation == 0.0)
+ {
+ hue = value;
+ saturation = value;
+ /*value = value;*/
+ }
+ else
+ {
+ h = hue * 6.0;
+ s = saturation;
+ v = value;
+
+ if (h == 6.0)
+ h = 0.0;
+
+ f = h - (gint) h;
+ p = v * (1.0 - s);
+ q = v * (1.0 - s * f);
+ t = v * (1.0 - s * (1.0 - f));
+
+ switch ((int) h)
+ {
+ case 0:
+ hue = v;
+ saturation = t;
+ value = p;
+ break;
+
+ case 1:
+ hue = q;
+ saturation = v;
+ value = p;
+ break;
+
+ case 2:
+ hue = p;
+ saturation = v;
+ value = t;
+ break;
+
+ case 3:
+ hue = p;
+ saturation = q;
+ value = v;
+ break;
+
+ case 4:
+ hue = t;
+ saturation = p;
+ value = v;
+ break;
+
+ case 5:
+ hue = v;
+ saturation = p;
+ value = q;
+ break;
+ }
+ }
+
+ rgb[0] = ROUND (hue * 255.0);
+ rgb[1] = ROUND (saturation * 255.0);
+ rgb[2] = ROUND (value * 255.0);
+}
diff --git a/libgimpcolor/gimpcolorspace.h b/libgimpcolor/gimpcolorspace.h
new file mode 100644
index 0000000..ae06536
--- /dev/null
+++ b/libgimpcolor/gimpcolorspace.h
@@ -0,0 +1,121 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_COLOR_SPACE_H__
+#define __GIMP_COLOR_SPACE_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+/* Color conversion routines */
+
+
+/* GimpRGB function */
+
+void gimp_rgb_to_hsv (const GimpRGB *rgb,
+ GimpHSV *hsv);
+void gimp_rgb_to_hsl (const GimpRGB *rgb,
+ GimpHSL *hsl);
+void gimp_rgb_to_cmyk (const GimpRGB *rgb,
+ gdouble pullout,
+ GimpCMYK *cmyk);
+
+void gimp_hsv_to_rgb (const GimpHSV *hsv,
+ GimpRGB *rgb);
+void gimp_hsl_to_rgb (const GimpHSL *hsl,
+ GimpRGB *rgb);
+void gimp_cmyk_to_rgb (const GimpCMYK *cmyk,
+ GimpRGB *rgb);
+
+GIMP_DEPRECATED
+void gimp_rgb_to_hwb (const GimpRGB *rgb,
+ gdouble *hue,
+ gdouble *whiteness,
+ gdouble *blackness);
+
+GIMP_DEPRECATED
+void gimp_hwb_to_rgb (gdouble hue,
+ gdouble whiteness,
+ gdouble blackness,
+ GimpRGB *rgb);
+
+
+/* gint functions */
+
+GIMP_DEPRECATED_FOR (gimp_rgb_to_hsv)
+void gimp_rgb_to_hsv_int (gint *red /* returns hue */,
+ gint *green /* returns saturation */,
+ gint *blue /* returns value */);
+
+GIMP_DEPRECATED_FOR (gimp_hsv_to_rgb)
+void gimp_hsv_to_rgb_int (gint *hue /* returns red */,
+ gint *saturation /* returns green */,
+ gint *value /* returns blue */);
+
+GIMP_DEPRECATED_FOR (gimp_rgb_to_cmyk)
+void gimp_rgb_to_cmyk_int (gint *red /* returns cyan */,
+ gint *green /* returns magenta */,
+ gint *blue /* returns yellow */,
+ gint *pullout /* returns black */);
+
+GIMP_DEPRECATED_FOR (gimp_cmyk_to_rgb)
+void gimp_cmyk_to_rgb_int (gint *cyan /* returns red */,
+ gint *magenta /* returns green */,
+ gint *yellow /* returns blue */,
+ gint *black /* not changed */);
+
+GIMP_DEPRECATED_FOR (gimp_rgb_to_hsl)
+void gimp_rgb_to_hsl_int (gint *red /* returns hue */,
+ gint *green /* returns saturation */,
+ gint *blue /* returns lightness */);
+
+GIMP_DEPRECATED_FOR (gimp_rgb_to_hsl)
+gint gimp_rgb_to_l_int (gint red,
+ gint green,
+ gint blue);
+
+GIMP_DEPRECATED_FOR (gimp_hsl_to_rgb)
+void gimp_hsl_to_rgb_int (gint *hue /* returns red */,
+ gint *saturation /* returns green */,
+ gint *lightness /* returns blue */);
+
+
+/* gdouble functions */
+
+GIMP_DEPRECATED_FOR (gimp_rgb_to_hsv)
+void gimp_rgb_to_hsv4 (const guchar *rgb,
+ gdouble *hue,
+ gdouble *saturation,
+ gdouble *value);
+
+GIMP_DEPRECATED_FOR (gimp_hsv_to_rgb)
+void gimp_hsv_to_rgb4 (guchar *rgb,
+ gdouble hue,
+ gdouble saturation,
+ gdouble value);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_COLOR_SPACE_H__ */
diff --git a/libgimpcolor/gimpcolortransform.c b/libgimpcolor/gimpcolortransform.c
new file mode 100644
index 0000000..b01f739
--- /dev/null
+++ b/libgimpcolor/gimpcolortransform.c
@@ -0,0 +1,596 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimpcolortransform.c
+ * Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
+ * Elle Stone <ellestone@ninedegreesbelow.com>
+ * Øyvind Kolås <pippin@gimp.org>
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <lcms2.h>
+
+#include <gio/gio.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+#include "libgimpconfig/gimpconfig.h"
+
+#include "gimpcolortypes.h"
+
+#include "gimpcolorprofile.h"
+#include "gimpcolortransform.h"
+
+#include "libgimp/libgimp-intl.h"
+
+
+/**
+ * SECTION: gimpcolortransform
+ * @title: GimpColorTransform
+ * @short_description: Definitions and Functions relating to LCMS.
+ *
+ * Definitions and Functions relating to LCMS.
+ **/
+
+/**
+ * GimpColorTransform:
+ *
+ * Simply a typedef to #gpointer, but actually is a cmsHTRANSFORM. It's
+ * used in public GIMP APIs in order to avoid having to include LCMS
+ * headers.
+ **/
+
+
+enum
+{
+ PROGRESS,
+ LAST_SIGNAL
+};
+
+
+struct _GimpColorTransformPrivate
+{
+ GimpColorProfile *src_profile;
+ const Babl *src_format;
+ const Babl *src_space_format;
+
+ GimpColorProfile *dest_profile;
+ const Babl *dest_format;
+ const Babl *dest_space_format;
+
+ cmsHTRANSFORM transform;
+ const Babl *fish;
+};
+
+
+static void gimp_color_transform_finalize (GObject *object);
+
+
+G_DEFINE_TYPE_WITH_PRIVATE (GimpColorTransform, gimp_color_transform,
+ G_TYPE_OBJECT)
+
+#define parent_class gimp_color_transform_parent_class
+
+static guint gimp_color_transform_signals[LAST_SIGNAL] = { 0 };
+
+static gchar *lcms_last_error = NULL;
+
+
+static void
+lcms_error_clear (void)
+{
+ if (lcms_last_error)
+ {
+ g_free (lcms_last_error);
+ lcms_last_error = NULL;
+ }
+}
+
+static void
+lcms_error_handler (cmsContext ContextID,
+ cmsUInt32Number ErrorCode,
+ const gchar *text)
+{
+ lcms_error_clear ();
+
+ lcms_last_error = g_strdup_printf ("lcms2 error %d: %s", ErrorCode, text);
+}
+
+static void
+gimp_color_transform_class_init (GimpColorTransformClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = gimp_color_transform_finalize;
+
+ gimp_color_transform_signals[PROGRESS] =
+ g_signal_new ("progress",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (GimpColorTransformClass,
+ progress),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__DOUBLE,
+ G_TYPE_NONE, 1,
+ G_TYPE_DOUBLE);
+
+ cmsSetLogErrorHandler (lcms_error_handler);
+}
+
+static void
+gimp_color_transform_init (GimpColorTransform *transform)
+{
+ transform->priv = gimp_color_transform_get_instance_private (transform);
+}
+
+static void
+gimp_color_transform_finalize (GObject *object)
+{
+ GimpColorTransform *transform = GIMP_COLOR_TRANSFORM (object);
+
+ g_clear_object (&transform->priv->src_profile);
+ g_clear_object (&transform->priv->dest_profile);
+
+ g_clear_pointer (&transform->priv->transform, cmsDeleteTransform);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+
+/**
+ * gimp_color_transform_new:
+ * @src_profile: the source #GimpColorProfile
+ * @src_format: the source #Babl format
+ * @dest_profile: the destination #GimpColorProfile
+ * @dest_format: the destination #Babl format
+ * @rendering_intent: the rendering intent
+ * @flags: transform flags
+ *
+ * This function creates an color transform.
+ *
+ * Return value: the #GimpColorTransform, or %NULL if no transform is needed
+ * to convert between pixels of @src_profile and @dest_profile.
+ *
+ * Since: 2.10
+ **/
+GimpColorTransform *
+gimp_color_transform_new (GimpColorProfile *src_profile,
+ const Babl *src_format,
+ GimpColorProfile *dest_profile,
+ const Babl *dest_format,
+ GimpColorRenderingIntent rendering_intent,
+ GimpColorTransformFlags flags)
+{
+ GimpColorTransform *transform;
+ GimpColorTransformPrivate *priv;
+ cmsHPROFILE src_lcms;
+ cmsHPROFILE dest_lcms;
+ cmsUInt32Number lcms_src_format;
+ cmsUInt32Number lcms_dest_format;
+ GError *error = NULL;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (src_profile), NULL);
+ g_return_val_if_fail (src_format != NULL, NULL);
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (dest_profile), NULL);
+ g_return_val_if_fail (dest_format != NULL, NULL);
+
+ if (gimp_color_transform_can_gegl_copy (src_profile, dest_profile))
+ return NULL;
+
+ transform = g_object_new (GIMP_TYPE_COLOR_TRANSFORM, NULL);
+
+ priv = transform->priv;
+
+ priv->src_space_format = gimp_color_profile_get_format (src_profile,
+ src_format,
+ BABL_ICC_INTENT_RELATIVE_COLORIMETRIC,
+ &error);
+ if (! priv->src_space_format)
+ {
+ g_printerr ("%s: error making src format: %s\n",
+ G_STRFUNC, error->message);
+ g_clear_error (&error);
+ }
+
+ priv->dest_space_format = gimp_color_profile_get_format (dest_profile,
+ dest_format,
+ rendering_intent,
+ &error);
+ if (! priv->dest_space_format)
+ {
+ g_printerr ("%s: error making dest format: %s\n",
+ G_STRFUNC, error->message);
+ g_clear_error (&error);
+ }
+
+ if (! g_getenv ("GIMP_COLOR_TRANSFORM_DISABLE_BABL") &&
+ priv->src_space_format && priv->dest_space_format)
+ {
+ priv->src_format = src_format;
+ priv->dest_format = dest_format;
+ priv->fish = babl_fish (priv->src_space_format,
+ priv->dest_space_format);
+
+ g_printerr ("%s: using babl for '%s' -> '%s'\n",
+ G_STRFUNC,
+ gimp_color_profile_get_label (src_profile),
+ gimp_color_profile_get_label (dest_profile));
+
+ return transform;
+ }
+
+ priv->src_space_format = NULL;
+ priv->dest_space_format = NULL;
+
+ priv->src_format = gimp_color_profile_get_lcms_format (src_format,
+ &lcms_src_format);
+ priv->dest_format = gimp_color_profile_get_lcms_format (dest_format,
+ &lcms_dest_format);
+
+ src_lcms = gimp_color_profile_get_lcms_profile (src_profile);
+ dest_lcms = gimp_color_profile_get_lcms_profile (dest_profile);
+
+ lcms_error_clear ();
+
+ priv->transform = cmsCreateTransform (src_lcms, lcms_src_format,
+ dest_lcms, lcms_dest_format,
+ rendering_intent,
+ flags |
+ cmsFLAGS_COPY_ALPHA);
+
+ if (lcms_last_error)
+ {
+ if (priv->transform)
+ {
+ cmsDeleteTransform (priv->transform);
+ priv->transform = NULL;
+ }
+
+ g_printerr ("%s\n", lcms_last_error);
+ }
+
+ if (! priv->transform)
+ {
+ g_object_unref (transform);
+ transform = NULL;
+ }
+
+ return transform;
+}
+
+/**
+ * gimp_color_transform_new_proofing:
+ * @src_profile: the source #GimpColorProfile
+ * @src_format: the source #Babl format
+ * @dest_profile: the destination #GimpColorProfile
+ * @dest_format: the destination #Babl format
+ * @proof_profile: the proof #GimpColorProfile
+ * @proof_intent: the proof intent
+ * @display_intent: the display intent
+ * @flags: transform flags
+ *
+ * This function creates a simulation / proofing color transform.
+ *
+ * Return value: the #GimpColorTransform, or %NULL.
+ *
+ * Since: 2.10
+ **/
+GimpColorTransform *
+gimp_color_transform_new_proofing (GimpColorProfile *src_profile,
+ const Babl *src_format,
+ GimpColorProfile *dest_profile,
+ const Babl *dest_format,
+ GimpColorProfile *proof_profile,
+ GimpColorRenderingIntent proof_intent,
+ GimpColorRenderingIntent display_intent,
+ GimpColorTransformFlags flags)
+{
+ GimpColorTransform *transform;
+ GimpColorTransformPrivate *priv;
+ cmsHPROFILE src_lcms;
+ cmsHPROFILE dest_lcms;
+ cmsHPROFILE proof_lcms;
+ cmsUInt32Number lcms_src_format;
+ cmsUInt32Number lcms_dest_format;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (src_profile), NULL);
+ g_return_val_if_fail (src_format != NULL, NULL);
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (dest_profile), NULL);
+ g_return_val_if_fail (dest_format != NULL, NULL);
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (proof_profile), NULL);
+
+ transform = g_object_new (GIMP_TYPE_COLOR_TRANSFORM, NULL);
+
+ priv = transform->priv;
+
+ src_lcms = gimp_color_profile_get_lcms_profile (src_profile);
+ dest_lcms = gimp_color_profile_get_lcms_profile (dest_profile);
+ proof_lcms = gimp_color_profile_get_lcms_profile (proof_profile);
+
+ priv->src_format = gimp_color_profile_get_lcms_format (src_format,
+ &lcms_src_format);
+ priv->dest_format = gimp_color_profile_get_lcms_format (dest_format,
+ &lcms_dest_format);
+
+ lcms_error_clear ();
+
+ priv->transform = cmsCreateProofingTransform (src_lcms, lcms_src_format,
+ dest_lcms, lcms_dest_format,
+ proof_lcms,
+ proof_intent,
+ display_intent,
+ flags |
+ cmsFLAGS_SOFTPROOFING |
+ cmsFLAGS_COPY_ALPHA);
+
+ if (lcms_last_error)
+ {
+ if (priv->transform)
+ {
+ cmsDeleteTransform (priv->transform);
+ priv->transform = NULL;
+ }
+
+ g_printerr ("%s\n", lcms_last_error);
+ }
+
+ if (! priv->transform)
+ {
+ g_object_unref (transform);
+ transform = NULL;
+ }
+
+ return transform;
+}
+
+/**
+ * gimp_color_transform_process_pixels:
+ * @transform: a #GimpColorTransform
+ * @src_format: #Babl format of @src_pixels
+ * @src_pixels: pointer to the source pixels
+ * @dest_format: #Babl format of @dest_pixels
+ * @dest_pixels: pointer to the destination pixels
+ * @length: number of pixels to process
+ *
+ * This function transforms a contiguous line of pixels.
+ *
+ * Since: 2.10
+ **/
+void
+gimp_color_transform_process_pixels (GimpColorTransform *transform,
+ const Babl *src_format,
+ gconstpointer src_pixels,
+ const Babl *dest_format,
+ gpointer dest_pixels,
+ gsize length)
+{
+ GimpColorTransformPrivate *priv;
+ gpointer *src;
+ gpointer *dest;
+
+ g_return_if_fail (GIMP_IS_COLOR_TRANSFORM (transform));
+ g_return_if_fail (src_format != NULL);
+ g_return_if_fail (src_pixels != NULL);
+ g_return_if_fail (dest_format != NULL);
+ g_return_if_fail (dest_pixels != NULL);
+
+ priv = transform->priv;
+
+ if (src_format != priv->src_format)
+ {
+ src = g_malloc (length * babl_format_get_bytes_per_pixel (priv->src_format));
+
+ babl_process (babl_fish (src_format,
+ priv->src_format),
+ src_pixels, src, length);
+ }
+ else
+ {
+ src = (gpointer) src_pixels;
+ }
+
+ if (dest_format != priv->dest_format)
+ {
+ dest = g_malloc (length * babl_format_get_bytes_per_pixel (priv->dest_format));
+ }
+ else
+ {
+ dest = dest_pixels;
+ }
+
+ if (priv->transform)
+ {
+ cmsDoTransform (priv->transform, src, dest, length);
+ }
+ else
+ {
+ babl_process (priv->fish, src, dest, length);
+ }
+
+ if (src_format != priv->src_format)
+ {
+ g_free (src);
+ }
+
+ if (dest_format != priv->dest_format)
+ {
+ babl_process (babl_fish (priv->dest_format,
+ dest_format),
+ dest, dest_pixels, length);
+
+ g_free (dest);
+ }
+}
+
+/**
+ * gimp_color_transform_process_buffer:
+ * @transform: a #GimpColorTransform
+ * @src_buffer: source #GeglBuffer
+ * @src_rect: rectangle in @src_buffer
+ * @dest_buffer: destination #GeglBuffer
+ * @dest_rect: rectangle in @dest_buffer
+ *
+ * This function transforms buffer into another buffer.
+ *
+ * Since: 2.10
+ **/
+void
+gimp_color_transform_process_buffer (GimpColorTransform *transform,
+ GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect)
+{
+ GimpColorTransformPrivate *priv;
+ GeglBufferIterator *iter;
+ gint total_pixels;
+ gint done_pixels = 0;
+
+ g_return_if_fail (GIMP_IS_COLOR_TRANSFORM (transform));
+ g_return_if_fail (GEGL_IS_BUFFER (src_buffer));
+ g_return_if_fail (GEGL_IS_BUFFER (dest_buffer));
+
+ priv = transform->priv;
+
+ if (src_rect)
+ {
+ total_pixels = src_rect->width * src_rect->height;
+ }
+ else
+ {
+ total_pixels = (gegl_buffer_get_width (src_buffer) *
+ gegl_buffer_get_height (src_buffer));
+ }
+
+ if (src_buffer != dest_buffer)
+ {
+ iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0,
+ priv->src_format,
+ GEGL_ACCESS_READ,
+ GEGL_ABYSS_NONE, 2);
+
+ gegl_buffer_iterator_add (iter, dest_buffer, dest_rect, 0,
+ priv->dest_format,
+ GEGL_ACCESS_WRITE,
+ GEGL_ABYSS_NONE);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ if (priv->transform)
+ {
+ cmsDoTransform (priv->transform,
+ iter->items[0].data, iter->items[1].data, iter->length);
+ }
+ else
+ {
+ babl_process (priv->fish,
+ iter->items[0].data, iter->items[1].data, iter->length);
+ }
+
+ done_pixels += iter->items[0].roi.width * iter->items[0].roi.height;
+
+ g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0,
+ (gdouble) done_pixels /
+ (gdouble) total_pixels);
+ }
+ }
+ else
+ {
+ iter = gegl_buffer_iterator_new (src_buffer, src_rect, 0,
+ priv->src_format,
+ GEGL_ACCESS_READWRITE,
+ GEGL_ABYSS_NONE, 1);
+
+ while (gegl_buffer_iterator_next (iter))
+ {
+ if (priv->transform)
+ {
+ cmsDoTransform (priv->transform,
+ iter->items[0].data, iter->items[0].data, iter->length);
+ }
+ else
+ {
+ babl_process (priv->fish,
+ iter->items[0].data, iter->items[0].data, iter->length);
+ }
+
+ done_pixels += iter->items[0].roi.width * iter->items[0].roi.height;
+
+ g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0,
+ (gdouble) done_pixels /
+ (gdouble) total_pixels);
+ }
+ }
+
+ g_signal_emit (transform, gimp_color_transform_signals[PROGRESS], 0,
+ 1.0);
+}
+
+/**
+ * gimp_color_transform_can_gegl_copy:
+ * @src_profile: source #GimpColorProfile
+ * @dest_profile: destination #GimpColorProfile
+ *
+ * This function checks if a GimpColorTransform is needed at all.
+ *
+ * Return value: %TRUE if pixels can be correctly converted between
+ * @src_profile and @dest_profile by simply using
+ * gegl_buffer_copy(), babl_process() or similar.
+ *
+ * Since: 2.10
+ **/
+gboolean
+gimp_color_transform_can_gegl_copy (GimpColorProfile *src_profile,
+ GimpColorProfile *dest_profile)
+{
+ static GimpColorProfile *srgb_profile = NULL;
+ static GimpColorProfile *srgb_linear_profile = NULL;
+ static GimpColorProfile *gray_profile = NULL;
+ static GimpColorProfile *gray_linear_profile = NULL;
+
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (src_profile), FALSE);
+ g_return_val_if_fail (GIMP_IS_COLOR_PROFILE (dest_profile), FALSE);
+
+ if (gimp_color_profile_is_equal (src_profile, dest_profile))
+ return TRUE;
+
+ if (! srgb_profile)
+ {
+ srgb_profile = gimp_color_profile_new_rgb_srgb ();
+ srgb_linear_profile = gimp_color_profile_new_rgb_srgb_linear ();
+ gray_profile = gimp_color_profile_new_d65_gray_srgb_trc ();
+ gray_linear_profile = gimp_color_profile_new_d65_gray_linear ();
+ }
+
+ if ((gimp_color_profile_is_equal (src_profile, srgb_profile) ||
+ gimp_color_profile_is_equal (src_profile, srgb_linear_profile) ||
+ gimp_color_profile_is_equal (src_profile, gray_profile) ||
+ gimp_color_profile_is_equal (src_profile, gray_linear_profile))
+ &&
+ (gimp_color_profile_is_equal (dest_profile, srgb_profile) ||
+ gimp_color_profile_is_equal (dest_profile, srgb_linear_profile) ||
+ gimp_color_profile_is_equal (dest_profile, gray_profile) ||
+ gimp_color_profile_is_equal (dest_profile, gray_linear_profile)))
+ {
+ return TRUE;
+ }
+
+ return FALSE;
+}
diff --git a/libgimpcolor/gimpcolortransform.h b/libgimpcolor/gimpcolortransform.h
new file mode 100644
index 0000000..c579470
--- /dev/null
+++ b/libgimpcolor/gimpcolortransform.h
@@ -0,0 +1,127 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimpcolortransform.h
+ * Copyright (C) 2014 Michael Natterer <mitch@gimp.org>
+ * Elle Stone <ellestone@ninedegreesbelow.com>
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_COLOR_TRANSFORM_H__
+#define __GIMP_COLOR_TRANSFORM_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+/**
+ * GimpColorTransformFlags:
+ * @GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE: optimize for accuracy rather
+ * than for speed
+ * @GIMP_COLOR_TRANSFORM_FLAGS_GAMUT_CHECK: mark out of gamut colors in the
+ * transform result
+ * @GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION: do black point
+ * compensation
+ *
+ * Flags for modifying #GimpColorTransform's behavior.
+ **/
+typedef enum
+{
+ GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE = 0x0100,
+ GIMP_COLOR_TRANSFORM_FLAGS_GAMUT_CHECK = 0x1000,
+ GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION = 0x2000,
+} GimpColorTransformFlags;
+
+
+#define GIMP_TYPE_COLOR_TRANSFORM (gimp_color_transform_get_type ())
+#define GIMP_COLOR_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_COLOR_TRANSFORM, GimpColorTransform))
+#define GIMP_COLOR_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_COLOR_TRANSFORM, GimpColorTransformClass))
+#define GIMP_IS_COLOR_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_COLOR_TRANSFORM))
+#define GIMP_IS_COLOR_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_COLOR_TRANSFORM))
+#define GIMP_COLOR_TRANSFORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_COLOR_TRANSFORM, GimpColorTransformClass))
+
+
+typedef struct _GimpColorTransformClass GimpColorTransformClass;
+typedef struct _GimpColorTransformPrivate GimpColorTransformPrivate;
+
+struct _GimpColorTransform
+{
+ GObject parent_instance;
+
+ GimpColorTransformPrivate *priv;
+};
+
+struct _GimpColorTransformClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (* progress) (GimpColorTransform *transform,
+ gdouble fraction);
+
+ /* Padding for future expansion */
+ void (* _gimp_reserved1) (void);
+ void (* _gimp_reserved2) (void);
+ void (* _gimp_reserved3) (void);
+ void (* _gimp_reserved4) (void);
+};
+
+
+GType gimp_color_transform_get_type (void) G_GNUC_CONST;
+
+GimpColorTransform *
+ gimp_color_transform_new (GimpColorProfile *src_profile,
+ const Babl *src_format,
+ GimpColorProfile *dest_profile,
+ const Babl *dest_format,
+ GimpColorRenderingIntent rendering_intent,
+ GimpColorTransformFlags flags);
+
+GimpColorTransform *
+ gimp_color_transform_new_proofing (GimpColorProfile *src_profile,
+ const Babl *src_format,
+ GimpColorProfile *dest_profile,
+ const Babl *dest_format,
+ GimpColorProfile *proof_profile,
+ GimpColorRenderingIntent proof_intent,
+ GimpColorRenderingIntent display_intent,
+ GimpColorTransformFlags flags);
+
+void gimp_color_transform_process_pixels (GimpColorTransform *transform,
+ const Babl *src_format,
+ gconstpointer src_pixels,
+ const Babl *dest_format,
+ gpointer dest_pixels,
+ gsize length);
+
+void gimp_color_transform_process_buffer (GimpColorTransform *transform,
+ GeglBuffer *src_buffer,
+ const GeglRectangle *src_rect,
+ GeglBuffer *dest_buffer,
+ const GeglRectangle *dest_rect);
+
+gboolean gimp_color_transform_can_gegl_copy (GimpColorProfile *src_profile,
+ GimpColorProfile *dest_profile);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_COLOR_TRANSFORM_H__ */
diff --git a/libgimpcolor/gimpcolortypes.h b/libgimpcolor/gimpcolortypes.h
new file mode 100644
index 0000000..565df1b
--- /dev/null
+++ b/libgimpcolor/gimpcolortypes.h
@@ -0,0 +1,126 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_COLOR_TYPES_H__
+#define __GIMP_COLOR_TYPES_H__
+
+
+#include <libgimpbase/gimpbasetypes.h>
+#include <libgimpconfig/gimpconfigtypes.h>
+
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+typedef struct _GimpColorManaged GimpColorManaged; /* dummy typedef */
+typedef struct _GimpColorProfile GimpColorProfile;
+typedef struct _GimpColorTransform GimpColorTransform;
+
+
+/* usually we don't keep the structure definitions in the types file
+ * but GimpRGB appears in too many header files...
+ */
+
+typedef struct _GimpRGB GimpRGB;
+typedef struct _GimpHSV GimpHSV;
+typedef struct _GimpHSL GimpHSL;
+typedef struct _GimpCMYK GimpCMYK;
+
+/**
+ * GimpRGB:
+ * @r: the red component
+ * @g: the green component
+ * @b: the blue component
+ * @a: the alpha component
+ *
+ * Used to keep RGB and RGBA colors. All components are in a range of
+ * [0.0..1.0].
+ **/
+struct _GimpRGB
+{
+ gdouble r, g, b, a;
+};
+
+/**
+ * GimpHSV:
+ * @h: the hue component
+ * @s: the saturation component
+ * @v: the value component
+ * @a: the alpha component
+ *
+ * Used to keep HSV and HSVA colors. All components are in a range of
+ * [0.0..1.0].
+ **/
+struct _GimpHSV
+{
+ gdouble h, s, v, a;
+};
+
+/**
+ * GimpHSL:
+ * @h: the hue component
+ * @s: the saturation component
+ * @l: the lightness component
+ * @a: the alpha component
+ *
+ * Used to keep HSL and HSLA colors. All components are in a range of
+ * [0.0..1.0].
+ **/
+struct _GimpHSL
+{
+ gdouble h, s, l, a;
+};
+
+/**
+ * GimpCMYK:
+ * @c: the cyan component
+ * @m: the magenta component
+ * @y: the yellow component
+ * @k: the black component
+ * @a: the alpha component
+ *
+ * Used to keep CMYK and CMYKA colors. All components are in a range
+ * of [0.0..1.0]. An alpha value is somewhat useless in the CMYK
+ * colorspace, but we keep one around anyway so color conversions
+ * going to CMYK and back can preserve alpha.
+ **/
+struct _GimpCMYK
+{
+ gdouble c, m, y, k, a;
+};
+
+
+typedef void (* GimpRenderFunc) (gdouble x,
+ gdouble y,
+ GimpRGB *color,
+ gpointer data);
+typedef void (* GimpPutPixelFunc) (gint x,
+ gint y,
+ GimpRGB *color,
+ gpointer data);
+typedef void (* GimpProgressFunc) (gint min,
+ gint max,
+ gint current,
+ gpointer data);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_COLOR_TYPES_H__ */
diff --git a/libgimpcolor/gimphsl.c b/libgimpcolor/gimphsl.c
new file mode 100644
index 0000000..050a40d
--- /dev/null
+++ b/libgimpcolor/gimphsl.c
@@ -0,0 +1,93 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+
+#include "gimpcolortypes.h"
+
+#include "gimphsl.h"
+
+
+/*
+ * GIMP_TYPE_HSL
+ */
+
+static GimpHSL * gimp_hsl_copy (const GimpHSL *hsl);
+
+
+GType
+gimp_hsl_get_type (void)
+{
+ static GType hsl_type = 0;
+
+ if (!hsl_type)
+ hsl_type = g_boxed_type_register_static ("GimpHSL",
+ (GBoxedCopyFunc) gimp_hsl_copy,
+ (GBoxedFreeFunc) g_free);
+
+ return hsl_type;
+}
+
+static GimpHSL *
+gimp_hsl_copy (const GimpHSL *hsl)
+{
+ return g_memdup (hsl, sizeof (GimpHSL));
+}
+
+
+/* HSL functions */
+
+/**
+ * gimp_hsl_set:
+ * @hsl:
+ * @h:
+ * @s:
+ * @l:
+ *
+ * Since: 2.8
+ **/
+void
+gimp_hsl_set (GimpHSL *hsl,
+ gdouble h,
+ gdouble s,
+ gdouble l)
+{
+ g_return_if_fail (hsl != NULL);
+
+ hsl->h = h;
+ hsl->s = s;
+ hsl->l = l;
+}
+
+/**
+ * gimp_hsl_set_alpha:
+ * @hsl:
+ * @a:
+ *
+ * Since: 2.10
+ **/
+void
+gimp_hsl_set_alpha (GimpHSL *hsl,
+ gdouble a)
+{
+ g_return_if_fail (hsl != NULL);
+
+ hsl->a = a;
+}
diff --git a/libgimpcolor/gimphsl.h b/libgimpcolor/gimphsl.h
new file mode 100644
index 0000000..f2a4cfb
--- /dev/null
+++ b/libgimpcolor/gimphsl.h
@@ -0,0 +1,49 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_HSL_H__
+#define __GIMP_HSL_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+/*
+ * GIMP_TYPE_HSL
+ */
+
+#define GIMP_TYPE_HSL (gimp_hsl_get_type ())
+
+GType gimp_hsl_get_type (void) G_GNUC_CONST;
+
+void gimp_hsl_set (GimpHSL *hsl,
+ gdouble h,
+ gdouble s,
+ gdouble l);
+void gimp_hsl_set_alpha (GimpHSL *hsl,
+ gdouble a);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_HSL_H__ */
diff --git a/libgimpcolor/gimphsv.c b/libgimpcolor/gimphsv.c
new file mode 100644
index 0000000..56bfbd7
--- /dev/null
+++ b/libgimpcolor/gimphsv.c
@@ -0,0 +1,107 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <glib-object.h>
+
+#include "gimpcolortypes.h"
+
+#include "gimphsv.h"
+
+
+/**
+ * SECTION: gimphsv
+ * @title: GimpHSV
+ * @short_description: Definitions and Functions relating to HSV colors.
+ *
+ * Definitions and Functions relating to HSV colors.
+ **/
+
+
+/*
+ * GIMP_TYPE_HSV
+ */
+
+static GimpHSV * gimp_hsv_copy (const GimpHSV *hsv);
+
+
+GType
+gimp_hsv_get_type (void)
+{
+ static GType hsv_type = 0;
+
+ if (!hsv_type)
+ hsv_type = g_boxed_type_register_static ("GimpHSV",
+ (GBoxedCopyFunc) gimp_hsv_copy,
+ (GBoxedFreeFunc) g_free);
+
+ return hsv_type;
+}
+
+static GimpHSV *
+gimp_hsv_copy (const GimpHSV *hsv)
+{
+ return g_memdup (hsv, sizeof (GimpHSV));
+}
+
+
+/* HSV functions */
+
+void
+gimp_hsv_set (GimpHSV *hsv,
+ gdouble h,
+ gdouble s,
+ gdouble v)
+{
+ g_return_if_fail (hsv != NULL);
+
+ hsv->h = h;
+ hsv->s = s;
+ hsv->v = v;
+}
+
+void
+gimp_hsv_clamp (GimpHSV *hsv)
+{
+ g_return_if_fail (hsv != NULL);
+
+ hsv->h -= (gint) hsv->h;
+
+ if (hsv->h < 0)
+ hsv->h += 1.0;
+
+ hsv->s = CLAMP (hsv->s, 0.0, 1.0);
+ hsv->v = CLAMP (hsv->v, 0.0, 1.0);
+ hsv->a = CLAMP (hsv->a, 0.0, 1.0);
+}
+
+void
+gimp_hsva_set (GimpHSV *hsva,
+ gdouble h,
+ gdouble s,
+ gdouble v,
+ gdouble a)
+{
+ g_return_if_fail (hsva != NULL);
+
+ hsva->h = h;
+ hsva->s = s;
+ hsva->v = v;
+ hsva->a = a;
+}
diff --git a/libgimpcolor/gimphsv.h b/libgimpcolor/gimphsv.h
new file mode 100644
index 0000000..7063d7b
--- /dev/null
+++ b/libgimpcolor/gimphsv.h
@@ -0,0 +1,54 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_HSV_H__
+#define __GIMP_HSV_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+/*
+ * GIMP_TYPE_HSV
+ */
+
+#define GIMP_TYPE_HSV (gimp_hsv_get_type ())
+
+GType gimp_hsv_get_type (void) G_GNUC_CONST;
+
+void gimp_hsv_set (GimpHSV *hsv,
+ gdouble hue,
+ gdouble saturation,
+ gdouble value);
+void gimp_hsv_clamp (GimpHSV *hsv);
+
+void gimp_hsva_set (GimpHSV *hsva,
+ gdouble hue,
+ gdouble saturation,
+ gdouble value,
+ gdouble alpha);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_HSV_H__ */
diff --git a/libgimpcolor/gimppixbuf.c b/libgimpcolor/gimppixbuf.c
new file mode 100644
index 0000000..235b84d
--- /dev/null
+++ b/libgimpcolor/gimppixbuf.c
@@ -0,0 +1,152 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimppixbuf.c
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include "gimpcolortypes.h"
+
+#include "gimppixbuf.h"
+
+
+/**
+ * SECTION: gimppixbuf
+ * @title: GimpPixbuf
+ * @short_description: Definitions and Functions relating to GdkPixbuf.
+ *
+ * Definitions and Functions relating to GdkPixbuf.
+ **/
+
+/**
+ * gimp_pixbuf_get_format:
+ * @pixbuf: a #GdkPixbuf
+ *
+ * Returns the Babl format that corresponds to the @pixbuf's pixel format.
+ *
+ * Return value: the @pixbuf's pixel format
+ *
+ * Since: 2.10
+ **/
+const Babl *
+gimp_pixbuf_get_format (GdkPixbuf *pixbuf)
+{
+ g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+ switch (gdk_pixbuf_get_n_channels (pixbuf))
+ {
+ case 3: return babl_format ("R'G'B' u8");
+ case 4: return babl_format ("R'G'B'A u8");
+ }
+
+ g_return_val_if_reached (NULL);
+}
+
+/**
+ * gimp_pixbuf_create_buffer:
+ * @pixbuf: a #GdkPixbuf
+ *
+ * Returns a #GeglBuffer that's either backed by the @pixbuf's pixels,
+ * or a copy of them. This function tries to not copy the @pixbuf's
+ * pixels. If the pixbuf's rowstride is a multiple of its bpp, a
+ * simple reference to the @pixbuf's pixels is made and @pixbuf will
+ * be kept around for as long as the buffer exists; otherwise the
+ * pixels are copied.
+ *
+ * Return value: a new #GeglBuffer.
+ *
+ * Since: 2.10
+ **/
+GeglBuffer *
+gimp_pixbuf_create_buffer (GdkPixbuf *pixbuf)
+{
+ gint width;
+ gint height;
+ gint rowstride;
+ gint bpp;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+
+ width = gdk_pixbuf_get_width (pixbuf);
+ height = gdk_pixbuf_get_height (pixbuf);
+ rowstride = gdk_pixbuf_get_rowstride (pixbuf);
+ bpp = gdk_pixbuf_get_n_channels (pixbuf);
+
+ if ((rowstride % bpp) == 0)
+ {
+ return gegl_buffer_linear_new_from_data (gdk_pixbuf_get_pixels (pixbuf),
+ gimp_pixbuf_get_format (pixbuf),
+ GEGL_RECTANGLE (0, 0,
+ width, height),
+ rowstride,
+ (GDestroyNotify) g_object_unref,
+ g_object_ref (pixbuf));
+ }
+ else
+ {
+ GeglBuffer *buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0,
+ width, height),
+ gimp_pixbuf_get_format (pixbuf));
+
+ gegl_buffer_set (buffer, NULL, 0, NULL,
+ gdk_pixbuf_get_pixels (pixbuf),
+ gdk_pixbuf_get_rowstride (pixbuf));
+
+ return buffer;
+ }
+}
+
+/**
+ * gimp_pixbuf_get_icc_profile:
+ * @pixbuf: a #GdkPixbuf
+ * @length: return location for the ICC profile's length
+ *
+ * Returns the ICC profile attached to the @pixbuf, or %NULL if there
+ * is none.
+ *
+ * Return value: The ICC profile data, or %NULL. The value should be freed
+ * with g_free().
+ *
+ * Since: 2.10
+ **/
+guint8 *
+gimp_pixbuf_get_icc_profile (GdkPixbuf *pixbuf,
+ gsize *length)
+{
+ const gchar *icc_base64;
+
+ g_return_val_if_fail (GDK_IS_PIXBUF (pixbuf), NULL);
+ g_return_val_if_fail (length != NULL, NULL);
+
+ icc_base64 = gdk_pixbuf_get_option (pixbuf, "icc-profile");
+
+ if (icc_base64)
+ {
+ guint8 *icc_data;
+
+ icc_data = g_base64_decode (icc_base64, length);
+
+ return icc_data;
+ }
+
+ return NULL;
+}
diff --git a/libgimpcolor/gimppixbuf.h b/libgimpcolor/gimppixbuf.h
new file mode 100644
index 0000000..6cc590c
--- /dev/null
+++ b/libgimpcolor/gimppixbuf.h
@@ -0,0 +1,43 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimppixbuf.h
+ * Copyright (C) 2012 Michael Natterer <mitch@gimp.org>
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_PIXBUF_H__
+#define __GIMP_PIXBUF_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+const Babl * gimp_pixbuf_get_format (GdkPixbuf *pixbuf);
+GeglBuffer * gimp_pixbuf_create_buffer (GdkPixbuf *pixbuf);
+
+guint8 * gimp_pixbuf_get_icc_profile (GdkPixbuf *pixbuf,
+ gsize *length);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_PIXBUF_H__ */
diff --git a/libgimpcolor/gimprgb-parse.c b/libgimpcolor/gimprgb-parse.c
new file mode 100644
index 0000000..ba16432
--- /dev/null
+++ b/libgimpcolor/gimprgb-parse.c
@@ -0,0 +1,651 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * gimprgb-parse.c
+ * Copyright (C) 2004 Sven Neumann <sven@gimp.org>
+ *
+ * Some of the code in here was inspired and partly copied from pango
+ * and librsvg.
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <babl/babl.h>
+#include <glib-object.h>
+
+#include "gimpcolortypes.h"
+
+#include "gimpcolorspace.h"
+#include "gimprgb.h"
+
+
+static gchar * gimp_rgb_parse_strip (const gchar *str,
+ gint len);
+
+static gboolean gimp_rgb_parse_name_internal (GimpRGB *rgb,
+ const gchar *name);
+static gboolean gimp_rgb_parse_hex_internal (GimpRGB *rgb,
+ const gchar *hex);
+static gboolean gimp_rgb_parse_css_internal (GimpRGB *rgb,
+ const gchar *css);
+static gboolean gimp_rgba_parse_css_internal (GimpRGB *rgb,
+ const gchar *css);
+
+
+typedef struct
+{
+ const gchar *name;
+ const guchar red;
+ const guchar green;
+ const guchar blue;
+} ColorEntry;
+
+static const ColorEntry named_colors[] =
+{
+ { "aliceblue", 240, 248, 255 },
+ { "antiquewhite", 250, 235, 215 },
+ { "aqua", 0, 255, 255 },
+ { "aquamarine", 127, 255, 212 },
+ { "azure", 240, 255, 255 },
+ { "beige", 245, 245, 220 },
+ { "bisque", 255, 228, 196 },
+ { "black", 0, 0, 0 },
+ { "blanchedalmond", 255, 235, 205 },
+ { "blue", 0, 0, 255 },
+ { "blueviolet", 138, 43, 226 },
+ { "brown", 165, 42, 42 },
+ { "burlywood", 222, 184, 135 },
+ { "cadetblue", 95, 158, 160 },
+ { "chartreuse", 127, 255, 0 },
+ { "chocolate", 210, 105, 30 },
+ { "coral", 255, 127, 80 },
+ { "cornflowerblue", 100, 149, 237 },
+ { "cornsilk", 255, 248, 220 },
+ { "crimson", 220, 20, 60 },
+ { "cyan", 0, 255, 255 },
+ { "darkblue", 0, 0, 139 },
+ { "darkcyan", 0, 139, 139 },
+ { "darkgoldenrod", 184, 134, 11 },
+ { "darkgray", 169, 169, 169 },
+ { "darkgreen", 0, 100, 0 },
+ { "darkgrey", 169, 169, 169 },
+ { "darkkhaki", 189, 183, 107 },
+ { "darkmagenta", 139, 0, 139 },
+ { "darkolivegreen", 85, 107, 47 },
+ { "darkorange", 255, 140, 0 },
+ { "darkorchid", 153, 50, 204 },
+ { "darkred", 139, 0, 0 },
+ { "darksalmon", 233, 150, 122 },
+ { "darkseagreen", 143, 188, 143 },
+ { "darkslateblue", 72, 61, 139 },
+ { "darkslategray", 47, 79, 79 },
+ { "darkslategrey", 47, 79, 79 },
+ { "darkturquoise", 0, 206, 209 },
+ { "darkviolet", 148, 0, 211 },
+ { "deeppink", 255, 20, 147 },
+ { "deepskyblue", 0, 191, 255 },
+ { "dimgray", 105, 105, 105 },
+ { "dimgrey", 105, 105, 105 },
+ { "dodgerblue", 30, 144, 255 },
+ { "firebrick", 178, 34, 34 },
+ { "floralwhite" , 255, 250, 240 },
+ { "forestgreen", 34, 139, 34 },
+ { "fuchsia", 255, 0, 255 },
+ { "gainsboro", 220, 220, 220 },
+ { "ghostwhite", 248, 248, 255 },
+ { "gold", 255, 215, 0 },
+ { "goldenrod", 218, 165, 32 },
+ { "gray", 128, 128, 128 },
+ { "green", 0, 128, 0 },
+ { "greenyellow", 173, 255, 47 },
+ { "grey", 128, 128, 128 },
+ { "honeydew", 240, 255, 240 },
+ { "hotpink", 255, 105, 180 },
+ { "indianred", 205, 92, 92 },
+ { "indigo", 75, 0, 130 },
+ { "ivory", 255, 255, 240 },
+ { "khaki", 240, 230, 140 },
+ { "lavender", 230, 230, 250 },
+ { "lavenderblush", 255, 240, 245 },
+ { "lawngreen", 124, 252, 0 },
+ { "lemonchiffon", 255, 250, 205 },
+ { "lightblue", 173, 216, 230 },
+ { "lightcoral", 240, 128, 128 },
+ { "lightcyan", 224, 255, 255 },
+ { "lightgoldenrodyellow", 250, 250, 210 },
+ { "lightgray", 211, 211, 211 },
+ { "lightgreen", 144, 238, 144 },
+ { "lightgrey", 211, 211, 211 },
+ { "lightpink", 255, 182, 193 },
+ { "lightsalmon", 255, 160, 122 },
+ { "lightseagreen", 32, 178, 170 },
+ { "lightskyblue", 135, 206, 250 },
+ { "lightslategray", 119, 136, 153 },
+ { "lightslategrey", 119, 136, 153 },
+ { "lightsteelblue", 176, 196, 222 },
+ { "lightyellow", 255, 255, 224 },
+ { "lime", 0, 255, 0 },
+ { "limegreen", 50, 205, 50 },
+ { "linen", 250, 240, 230 },
+ { "magenta", 255, 0, 255 },
+ { "maroon", 128, 0, 0 },
+ { "mediumaquamarine", 102, 205, 170 },
+ { "mediumblue", 0, 0, 205 },
+ { "mediumorchid", 186, 85, 211 },
+ { "mediumpurple", 147, 112, 219 },
+ { "mediumseagreen", 60, 179, 113 },
+ { "mediumslateblue", 123, 104, 238 },
+ { "mediumspringgreen", 0, 250, 154 },
+ { "mediumturquoise", 72, 209, 204 },
+ { "mediumvioletred", 199, 21, 133 },
+ { "midnightblue", 25, 25, 112 },
+ { "mintcream", 245, 255, 250 },
+ { "mistyrose", 255, 228, 225 },
+ { "moccasin", 255, 228, 181 },
+ { "navajowhite", 255, 222, 173 },
+ { "navy", 0, 0, 128 },
+ { "oldlace", 253, 245, 230 },
+ { "olive", 128, 128, 0 },
+ { "olivedrab", 107, 142, 35 },
+ { "orange", 255, 165, 0 },
+ { "orangered", 255, 69, 0 },
+ { "orchid", 218, 112, 214 },
+ { "palegoldenrod", 238, 232, 170 },
+ { "palegreen", 152, 251, 152 },
+ { "paleturquoise", 175, 238, 238 },
+ { "palevioletred", 219, 112, 147 },
+ { "papayawhip", 255, 239, 213 },
+ { "peachpuff", 255, 218, 185 },
+ { "peru", 205, 133, 63 },
+ { "pink", 255, 192, 203 },
+ { "plum", 221, 160, 221 },
+ { "powderblue", 176, 224, 230 },
+ { "purple", 128, 0, 128 },
+ { "red", 255, 0, 0 },
+ { "rosybrown", 188, 143, 143 },
+ { "royalblue", 65, 105, 225 },
+ { "saddlebrown", 139, 69, 19 },
+ { "salmon", 250, 128, 114 },
+ { "sandybrown", 244, 164, 96 },
+ { "seagreen", 46, 139, 87 },
+ { "seashell", 255, 245, 238 },
+ { "sienna", 160, 82, 45 },
+ { "silver", 192, 192, 192 },
+ { "skyblue", 135, 206, 235 },
+ { "slateblue", 106, 90, 205 },
+ { "slategray", 112, 128, 144 },
+ { "slategrey", 112, 128, 144 },
+ { "snow", 255, 250, 250 },
+ { "springgreen", 0, 255, 127 },
+ { "steelblue", 70, 130, 180 },
+ { "tan", 210, 180, 140 },
+ { "teal", 0, 128, 128 },
+ { "thistle", 216, 191, 216 },
+ { "tomato", 255, 99, 71 },
+ { "turquoise", 64, 224, 208 },
+ { "violet", 238, 130, 238 },
+ { "wheat", 245, 222, 179 },
+ { "white", 255, 255, 255 },
+ { "whitesmoke", 245, 245, 245 },
+ { "yellow", 255, 255, 0 },
+ { "yellowgreen", 154, 205, 50 }
+};
+
+
+/**
+ * gimp_rgb_parse_name:
+ * @rgb: a #GimpRGB struct used to return the parsed color
+ * @name: a color name (in UTF-8 encoding)
+ * @len: the length of @name, in bytes. or -1 if @name is nul-terminated
+ *
+ * Attempts to parse a color name. This function accepts <ulink
+ * url="https://www.w3.org/TR/SVG/types.html#ColorKeywords">SVG 1.0
+ * color keywords</ulink>.
+ *
+ * This function does not touch the alpha component of @rgb.
+ *
+ * Return value: %TRUE if @name was parsed successfully and @rgb has
+ * been set, %FALSE otherwise
+ *
+ * Since: 2.2
+ **/
+gboolean
+gimp_rgb_parse_name (GimpRGB *rgb,
+ const gchar *name,
+ gint len)
+{
+ gchar *tmp;
+ gboolean result;
+
+ g_return_val_if_fail (rgb != NULL, FALSE);
+ g_return_val_if_fail (name != NULL, FALSE);
+
+ tmp = gimp_rgb_parse_strip (name, len);
+
+ result = gimp_rgb_parse_name_internal (rgb, tmp);
+
+ g_free (tmp);
+
+ return result;
+}
+
+/**
+ * gimp_rgb_parse_hex:
+ * @rgb: a #GimpRGB struct used to return the parsed color
+ * @hex: a string describing a color in hexadecimal notation
+ * @len: the length of @hex, in bytes. or -1 if @hex is nul-terminated
+ *
+ * Attempts to parse a string describing an RGB color in hexadecimal
+ * notation (optionally prefixed with a '#').
+ *
+ * This function does not touch the alpha component of @rgb.
+ *
+ * Return value: %TRUE if @hex was parsed successfully and @rgb has
+ * been set, %FALSE otherwise
+ *
+ * Since: 2.2
+ **/
+gboolean
+gimp_rgb_parse_hex (GimpRGB *rgb,
+ const gchar *hex,
+ gint len)
+{
+ gchar *tmp;
+ gboolean result;
+
+ g_return_val_if_fail (rgb != NULL, FALSE);
+ g_return_val_if_fail (hex != NULL, FALSE);
+
+ tmp = gimp_rgb_parse_strip (hex, len);
+
+ result = gimp_rgb_parse_hex_internal (rgb, tmp);
+
+ g_free (tmp);
+
+ return result;
+}
+
+/**
+ * gimp_rgb_parse_css:
+ * @rgb: a #GimpRGB struct used to return the parsed color
+ * @css: a string describing a color in CSS notation
+ * @len: the length of @hex, in bytes. or -1 if @hex is nul-terminated
+ *
+ * Attempts to parse a string describing an RGB color in CSS
+ * notation. This can be either a numerical representation
+ * (<code>rgb(255,0,0)</code> or <code>rgb(100%,0%,0%)</code>)
+ * or a hexadecimal notation as parsed by gimp_rgb_parse_hex()
+ * (<code>##ff0000</code>) or a color name as parsed by
+ * gimp_rgb_parse_name() (<code>red</code>).
+ *
+ * This function does not touch the alpha component of @rgb.
+ *
+ * Return value: %TRUE if @css was parsed successfully and @rgb has been
+ * set, %FALSE otherwise
+ *
+ * Since: 2.2
+ **/
+gboolean
+gimp_rgb_parse_css (GimpRGB *rgb,
+ const gchar *css,
+ gint len)
+{
+ gchar *tmp;
+ gboolean result;
+
+ g_return_val_if_fail (rgb != NULL, FALSE);
+ g_return_val_if_fail (css != NULL, FALSE);
+
+ tmp = gimp_rgb_parse_strip (css, len);
+
+ result = gimp_rgb_parse_css_internal (rgb, tmp);
+
+ g_free (tmp);
+
+ return result;
+}
+
+/**
+ * gimp_rgba_parse_css:
+ * @rgba: a #GimpRGB struct used to return the parsed color
+ * @css: a string describing a color in CSS notation
+ * @len: the length of @hex, in bytes. or -1 if @hex is nul-terminated
+ *
+ * Similar to gimp_rgb_parse_css() but handles RGB colors with alpha
+ * channel in the numerical CSS notation (<code>rgba(255,0,0,255)</code>
+ * or <code>rgba(100%,0%,0%,1000%)</code>).
+ *
+ * It doesn't handle the hexadecimal notation or color names because
+ * they leave the alpha channel unspecified.
+ *
+ * Return value: %TRUE if @css was parsed successfully and @rgb has been
+ * set, %FALSE otherwise
+ *
+ * Since: 2.2
+ **/
+gboolean
+gimp_rgba_parse_css (GimpRGB *rgba,
+ const gchar *css,
+ gint len)
+{
+ gchar *tmp;
+ gboolean result;
+
+ g_return_val_if_fail (rgba != NULL, FALSE);
+ g_return_val_if_fail (css != NULL, FALSE);
+
+ if (len < 0)
+ len = strlen (css);
+
+ tmp = gimp_rgb_parse_strip (css, len);
+
+ if (strcmp (tmp, "transparent") == 0)
+ {
+ gimp_rgba_set (rgba, 0.0, 0.0, 0.0, 0.0);
+ result = TRUE;
+ }
+ else
+ {
+ result = gimp_rgba_parse_css_internal (rgba, tmp);
+ }
+
+ g_free (tmp);
+
+ return result;
+}
+
+
+/**
+ * gimp_rgb_list_names:
+ * @names: return location for an array of color names
+ * @colors: return location for an array of GimpRGB structs
+ *
+ * Returns the list of <ulink
+ * url="https://www.w3.org/TR/SVG/types.html">SVG 1.0 color
+ * keywords</ulink> that is used by gimp_rgb_parse_name().
+ *
+ * The returned strings are const and must not be freed. Only the two
+ * arrays are allocated dynamically. You must call g_free() on the
+ * @names and @colors arrays when they are not any longer needed.
+ *
+ * Return value: the number of named colors
+ * (i.e. the length of the returned arrays)
+ *
+ * Since: 2.2
+ **/
+gint
+gimp_rgb_list_names (const gchar ***names,
+ GimpRGB **colors)
+{
+ gint i;
+
+ g_return_val_if_fail (names != NULL, 0);
+ g_return_val_if_fail (colors != NULL, 0);
+
+ *names = g_new (const gchar *, G_N_ELEMENTS (named_colors));
+ *colors = g_new (GimpRGB, G_N_ELEMENTS (named_colors));
+
+ for (i = 0; i < G_N_ELEMENTS (named_colors); i++)
+ {
+ (*names)[i] = named_colors[i].name;
+
+ gimp_rgba_set_uchar ((*colors) + i,
+ named_colors[i].red,
+ named_colors[i].green,
+ named_colors[i].blue,
+ 0xFF);
+ }
+
+ return G_N_ELEMENTS (named_colors);
+}
+
+
+static gchar *
+gimp_rgb_parse_strip (const gchar *str,
+ gint len)
+{
+ gchar *result;
+
+ while (len > 0 && g_ascii_isspace (*str))
+ {
+ str++;
+ len--;
+ }
+
+ if (len < 0)
+ {
+ while (g_ascii_isspace (*str))
+ str++;
+
+ len = strlen (str);
+ }
+
+ while (len > 0 && g_ascii_isspace (str[len - 1]))
+ len--;
+
+ result = g_malloc (len + 1);
+
+ memcpy (result, str, len);
+ result[len] = '\0';
+
+ return result;
+}
+
+static gint
+gimp_rgb_color_entry_compare (gconstpointer a,
+ gconstpointer b)
+{
+ const gchar *name = a;
+ const ColorEntry *entry = b;
+
+ return g_ascii_strcasecmp (name, entry->name);
+}
+
+static gboolean
+gimp_rgb_parse_name_internal (GimpRGB *rgb,
+ const gchar *name)
+{
+ ColorEntry *entry = bsearch (name, named_colors,
+ G_N_ELEMENTS (named_colors), sizeof (ColorEntry),
+ gimp_rgb_color_entry_compare);
+
+ if (entry)
+ {
+ gimp_rgb_set_uchar (rgb, entry->red, entry->green, entry->blue);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+static gboolean
+gimp_rgb_parse_hex_component (const gchar *hex,
+ gint len,
+ gdouble *value)
+{
+ gint i;
+ guint c = 0;
+
+ for (i = 0; i < len; i++, hex++)
+ {
+ if (!*hex || !g_ascii_isxdigit (*hex))
+ return FALSE;
+
+ c = (c << 4) | g_ascii_xdigit_value (*hex);
+ }
+
+ switch (len)
+ {
+ case 1: *value = (gdouble) c / 15.0; break;
+ case 2: *value = (gdouble) c / 255.0; break;
+ case 3: *value = (gdouble) c / 4095.0; break;
+ case 4: *value = (gdouble) c / 65535.0; break;
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gimp_rgb_parse_hex_internal (GimpRGB *rgb,
+ const gchar *hex)
+{
+ gint i;
+ gsize len;
+ gdouble val[3];
+
+ if (hex[0] == '#')
+ hex++;
+
+ len = strlen (hex);
+ if (len % 3 || len < 3 || len > 12)
+ return FALSE;
+
+ len /= 3;
+
+ for (i = 0; i < 3; i++, hex += len)
+ {
+ if (! gimp_rgb_parse_hex_component (hex, len, val + i))
+ return FALSE;
+ }
+
+ gimp_rgb_set (rgb, val[0], val[1], val[2]);
+
+ return TRUE;
+}
+
+
+static gboolean
+gimp_rgb_parse_css_numeric (GimpRGB *rgb,
+ const gchar *css)
+{
+ gdouble values[4];
+ gboolean alpha;
+ gboolean hsl;
+ gint i;
+
+ if (css[0] == 'r' && css[1] == 'g' && css[2] == 'b')
+ hsl = FALSE;
+ else if (css[0] == 'h' && css[1] == 's' && css[2] == 'l')
+ hsl = TRUE;
+ else
+ return FALSE;
+
+ if (css[3] == 'a' && css[4] == '(')
+ alpha = TRUE;
+else if (css[3] == '(')
+ alpha = FALSE;
+ else
+ return FALSE;
+
+ css += (alpha ? 5 : 4);
+
+ for (i = 0; i < (alpha ? 4 : 3); i++)
+ {
+ const gchar *end = css;
+
+ while (*end && *end != ',' && *end != '%' && *end != ')')
+ end++;
+
+ if (i == 3 || *end == '%')
+ {
+ values[i] = g_ascii_strtod (css, (gchar **) &end);
+
+ if (errno == ERANGE)
+ return FALSE;
+
+ if (*end == '%')
+ {
+ end++;
+ values[i] /= 100.0;
+ }
+ }
+ else
+ {
+ glong value = strtol (css, (gchar **) &end, 10);
+
+ if (errno == ERANGE)
+ return FALSE;
+
+ if (hsl)
+ values[i] = value / (i == 0 ? 360.0 : 100.0);
+ else
+ values[i] = value / 255.0;
+ }
+
+ while (*end == ',' || g_ascii_isspace (*end))
+ end++;
+
+ css = end;
+ }
+
+ if (*css != ')')
+ return FALSE;
+
+ if (alpha)
+ gimp_rgba_set (rgb, values[0], values[1], values[2], values[3]);
+ else
+ gimp_rgb_set (rgb, values[0], values[1], values[2]);
+
+ gimp_rgb_clamp (rgb);
+
+ if (hsl)
+ {
+ GimpHSL tmp = (*((GimpHSL *) rgb));
+
+ gimp_hsl_to_rgb (&tmp, rgb);
+ }
+
+ return TRUE;
+}
+
+static gboolean
+gimp_rgb_parse_css_internal (GimpRGB *rgb,
+ const gchar *css)
+{
+ if (css[0] == '#')
+ {
+ return gimp_rgb_parse_hex_internal (rgb, css);
+ }
+ else if (strncmp (css, "rgb(", 4) == 0 ||
+ strncmp (css, "hsl(", 4) == 0)
+ {
+ return gimp_rgb_parse_css_numeric (rgb, css);
+ }
+ else
+ {
+ return gimp_rgb_parse_name_internal (rgb, css);
+ }
+}
+
+static gboolean
+gimp_rgba_parse_css_internal (GimpRGB *rgba,
+ const gchar *css)
+{
+ if (strncmp (css, "rgba(", 5) != 0 &&
+ strncmp (css, "hsla(", 5) != 0)
+ return FALSE;
+
+ return gimp_rgb_parse_css_numeric (rgba, css);
+}
diff --git a/libgimpcolor/gimprgb.c b/libgimpcolor/gimprgb.c
new file mode 100644
index 0000000..b9ab4be
--- /dev/null
+++ b/libgimpcolor/gimprgb.c
@@ -0,0 +1,846 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <babl/babl.h>
+#include <glib-object.h>
+
+#define GIMP_DISABLE_DEPRECATION_WARNINGS /* for GIMP_RGB_INTENSITY() */
+#include "libgimpmath/gimpmath.h"
+
+#include "gimpcolortypes.h"
+
+#undef GIMP_DISABLE_DEPRECATED /* for GIMP_RGB_INTENSITY() */
+#include "gimprgb.h"
+
+
+/**
+ * SECTION: gimprgb
+ * @title: GimpRGB
+ * @short_description: Definitions and Functions relating to RGB colors.
+ *
+ * Definitions and Functions relating to RGB colors.
+ **/
+
+
+/*
+ * GIMP_TYPE_RGB
+ */
+
+static GimpRGB * gimp_rgb_copy (const GimpRGB *rgb);
+
+
+GType
+gimp_rgb_get_type (void)
+{
+ static GType rgb_type = 0;
+
+ if (!rgb_type)
+ rgb_type = g_boxed_type_register_static ("GimpRGB",
+ (GBoxedCopyFunc) gimp_rgb_copy,
+ (GBoxedFreeFunc) g_free);
+
+ return rgb_type;
+}
+
+void
+gimp_value_get_rgb (const GValue *value,
+ GimpRGB *rgb)
+{
+ g_return_if_fail (GIMP_VALUE_HOLDS_RGB (value));
+ g_return_if_fail (rgb != NULL);
+
+ if (value->data[0].v_pointer)
+ *rgb = *((GimpRGB *) value->data[0].v_pointer);
+ else
+ gimp_rgba_set (rgb, 0.0, 0.0, 0.0, 1.0);
+}
+
+void
+gimp_value_set_rgb (GValue *value,
+ const GimpRGB *rgb)
+{
+ g_return_if_fail (GIMP_VALUE_HOLDS_RGB (value));
+ g_return_if_fail (rgb != NULL);
+
+ g_value_set_boxed (value, rgb);
+}
+
+static GimpRGB *
+gimp_rgb_copy (const GimpRGB *rgb)
+{
+ return g_memdup (rgb, sizeof (GimpRGB));
+}
+
+
+/* RGB functions */
+
+/**
+ * gimp_rgb_set:
+ * @rgb: a #GimpRGB struct
+ * @red: the red component
+ * @green: the green component
+ * @blue: the blue component
+ *
+ * Sets the red, green and blue components of @rgb and leaves the
+ * alpha component unchanged. The color values should be between 0.0
+ * and 1.0 but there is no check to enforce this and the values are
+ * set exactly as they are passed in.
+ **/
+void
+gimp_rgb_set (GimpRGB *rgb,
+ gdouble r,
+ gdouble g,
+ gdouble b)
+{
+ g_return_if_fail (rgb != NULL);
+
+ rgb->r = r;
+ rgb->g = g;
+ rgb->b = b;
+}
+
+/**
+ * gimp_rgb_set_alpha:
+ * @rgb: a #GimpRGB struct
+ * @alpha: the alpha component
+ *
+ * Sets the alpha component of @rgb and leaves the RGB components unchanged.
+ **/
+void
+gimp_rgb_set_alpha (GimpRGB *rgb,
+ gdouble a)
+{
+ g_return_if_fail (rgb != NULL);
+
+ rgb->a = a;
+}
+
+/**
+ * gimp_rgb_set_pixel:
+ * @rgb: a #GimpRGB struct
+ * @format: a Babl format
+ * @pixel: pointer to the source pixel
+ *
+ * Sets the red, green and blue components of @rgb from the color
+ * stored in @pixel. The pixel format of @pixel is determined by
+ * @format.
+ *
+ * Since: 2.10
+ **/
+void
+gimp_rgb_set_pixel (GimpRGB *rgb,
+ const Babl *format,
+ gconstpointer pixel)
+{
+ g_return_if_fail (rgb != NULL);
+ g_return_if_fail (format != NULL);
+ g_return_if_fail (pixel != NULL);
+
+ babl_process (babl_fish (format,
+ babl_format ("R'G'B' double")),
+ pixel, rgb, 1);
+}
+
+/**
+ * gimp_rgb_get_pixel:
+ * @rgb: a #GimpRGB struct
+ * @format: a Babl format
+ * @pixel: pointer to the destination pixel
+ *
+ * Writes the red, green, blue and alpha components of @rgb to the
+ * color stored in @pixel. The pixel format of @pixel is determined by
+ * @format.
+ *
+ * Since: 2.10
+ **/
+void
+gimp_rgb_get_pixel (const GimpRGB *rgb,
+ const Babl *format,
+ gpointer pixel)
+{
+ g_return_if_fail (rgb != NULL);
+ g_return_if_fail (format != NULL);
+ g_return_if_fail (pixel != NULL);
+
+ babl_process (babl_fish (babl_format ("R'G'B' double"),
+ format),
+ rgb, pixel, 1);
+}
+
+/**
+ * gimp_rgb_set_uchar:
+ * @rgb: a #GimpRGB struct
+ * @red: the red component
+ * @green: the green component
+ * @blue: the blue component
+ *
+ * Sets the red, green and blue components of @rgb from 8bit values
+ * (0 to 255) and leaves the alpha component unchanged.
+ **/
+void
+gimp_rgb_set_uchar (GimpRGB *rgb,
+ guchar r,
+ guchar g,
+ guchar b)
+{
+ g_return_if_fail (rgb != NULL);
+
+ rgb->r = (gdouble) r / 255.0;
+ rgb->g = (gdouble) g / 255.0;
+ rgb->b = (gdouble) b / 255.0;
+}
+
+void
+gimp_rgb_get_uchar (const GimpRGB *rgb,
+ guchar *r,
+ guchar *g,
+ guchar *b)
+{
+ g_return_if_fail (rgb != NULL);
+
+ if (r) *r = ROUND (CLAMP (rgb->r, 0.0, 1.0) * 255.0);
+ if (g) *g = ROUND (CLAMP (rgb->g, 0.0, 1.0) * 255.0);
+ if (b) *b = ROUND (CLAMP (rgb->b, 0.0, 1.0) * 255.0);
+}
+
+void
+gimp_rgb_add (GimpRGB *rgb1,
+ const GimpRGB *rgb2)
+{
+ g_return_if_fail (rgb1 != NULL);
+ g_return_if_fail (rgb2 != NULL);
+
+ rgb1->r += rgb2->r;
+ rgb1->g += rgb2->g;
+ rgb1->b += rgb2->b;
+}
+
+void
+gimp_rgb_subtract (GimpRGB *rgb1,
+ const GimpRGB *rgb2)
+{
+ g_return_if_fail (rgb1 != NULL);
+ g_return_if_fail (rgb2 != NULL);
+
+ rgb1->r -= rgb2->r;
+ rgb1->g -= rgb2->g;
+ rgb1->b -= rgb2->b;
+}
+
+void
+gimp_rgb_multiply (GimpRGB *rgb,
+ gdouble factor)
+{
+ g_return_if_fail (rgb != NULL);
+
+ rgb->r *= factor;
+ rgb->g *= factor;
+ rgb->b *= factor;
+}
+
+gdouble
+gimp_rgb_distance (const GimpRGB *rgb1,
+ const GimpRGB *rgb2)
+{
+ g_return_val_if_fail (rgb1 != NULL, 0.0);
+ g_return_val_if_fail (rgb2 != NULL, 0.0);
+
+ return (fabs (rgb1->r - rgb2->r) +
+ fabs (rgb1->g - rgb2->g) +
+ fabs (rgb1->b - rgb2->b));
+}
+
+gdouble
+gimp_rgb_max (const GimpRGB *rgb)
+{
+ g_return_val_if_fail (rgb != NULL, 0.0);
+
+ if (rgb->r > rgb->g)
+ return (rgb->r > rgb->b) ? rgb->r : rgb->b;
+ else
+ return (rgb->g > rgb->b) ? rgb->g : rgb->b;
+}
+
+gdouble
+gimp_rgb_min (const GimpRGB *rgb)
+{
+ g_return_val_if_fail (rgb != NULL, 0.0);
+
+ if (rgb->r < rgb->g)
+ return (rgb->r < rgb->b) ? rgb->r : rgb->b;
+ else
+ return (rgb->g < rgb->b) ? rgb->g : rgb->b;
+}
+
+void
+gimp_rgb_clamp (GimpRGB *rgb)
+{
+ g_return_if_fail (rgb != NULL);
+
+ rgb->r = CLAMP (rgb->r, 0.0, 1.0);
+ rgb->g = CLAMP (rgb->g, 0.0, 1.0);
+ rgb->b = CLAMP (rgb->b, 0.0, 1.0);
+ rgb->a = CLAMP (rgb->a, 0.0, 1.0);
+}
+
+void
+gimp_rgb_gamma (GimpRGB *rgb,
+ gdouble gamma)
+{
+ gdouble ig;
+
+ g_return_if_fail (rgb != NULL);
+
+ if (gamma != 0.0)
+ ig = 1.0 / gamma;
+ else
+ ig = 0.0;
+
+ rgb->r = pow (rgb->r, ig);
+ rgb->g = pow (rgb->g, ig);
+ rgb->b = pow (rgb->b, ig);
+}
+
+/**
+ * gimp_rgb_luminance:
+ * @rgb: a #GimpRGB struct
+ *
+ * Return value: the luminous intensity of the range from 0.0 to 1.0.
+ *
+ * Since: 2.4
+ **/
+gdouble
+gimp_rgb_luminance (const GimpRGB *rgb)
+{
+ gdouble luminance;
+
+ g_return_val_if_fail (rgb != NULL, 0.0);
+
+ luminance = GIMP_RGB_LUMINANCE (rgb->r, rgb->g, rgb->b);
+
+ return CLAMP (luminance, 0.0, 1.0);
+}
+
+/**
+ * gimp_rgb_luminance_uchar:
+ * @rgb: a #GimpRGB struct
+ *
+ * Return value: the luminous intensity in the range from 0 to 255.
+ *
+ * Since: 2.4
+ **/
+guchar
+gimp_rgb_luminance_uchar (const GimpRGB *rgb)
+{
+ g_return_val_if_fail (rgb != NULL, 0);
+
+ return ROUND (gimp_rgb_luminance (rgb) * 255.0);
+}
+
+/**
+ * gimp_rgb_intensity:
+ * @rgb: a #GimpRGB struct
+ *
+ * This function is deprecated! Use gimp_rgb_luminance() instead.
+ *
+ * Return value: the intensity in the range from 0.0 to 1.0.
+ **/
+gdouble
+gimp_rgb_intensity (const GimpRGB *rgb)
+{
+ gdouble intensity;
+
+ g_return_val_if_fail (rgb != NULL, 0.0);
+
+ intensity = GIMP_RGB_INTENSITY (rgb->r, rgb->g, rgb->b);
+
+ return CLAMP (intensity, 0.0, 1.0);
+}
+
+/**
+ * gimp_rgb_intensity_uchar:
+ * @rgb: a #GimpRGB struct
+ *
+ * This function is deprecated! Use gimp_rgb_luminance_uchar() instead.
+ *
+ * Return value: the intensity in the range from 0 to 255.
+ **/
+guchar
+gimp_rgb_intensity_uchar (const GimpRGB *rgb)
+{
+ g_return_val_if_fail (rgb != NULL, 0);
+
+ return ROUND (gimp_rgb_intensity (rgb) * 255.0);
+}
+
+void
+gimp_rgb_composite (GimpRGB *color1,
+ const GimpRGB *color2,
+ GimpRGBCompositeMode mode)
+{
+ g_return_if_fail (color1 != NULL);
+ g_return_if_fail (color2 != NULL);
+
+ switch (mode)
+ {
+ case GIMP_RGB_COMPOSITE_NONE:
+ break;
+
+ case GIMP_RGB_COMPOSITE_NORMAL:
+ /* put color2 on top of color1 */
+ if (color2->a == 1.0)
+ {
+ *color1 = *color2;
+ }
+ else
+ {
+ gdouble factor = color1->a * (1.0 - color2->a);
+
+ color1->r = color1->r * factor + color2->r * color2->a;
+ color1->g = color1->g * factor + color2->g * color2->a;
+ color1->b = color1->b * factor + color2->b * color2->a;
+ color1->a = factor + color2->a;
+ }
+ break;
+
+ case GIMP_RGB_COMPOSITE_BEHIND:
+ /* put color2 below color1 */
+ if (color1->a < 1.0)
+ {
+ gdouble factor = color2->a * (1.0 - color1->a);
+
+ color1->r = color2->r * factor + color1->r * color1->a;
+ color1->g = color2->g * factor + color1->g * color1->a;
+ color1->b = color2->b * factor + color1->b * color1->a;
+ color1->a = factor + color1->a;
+ }
+ break;
+ }
+}
+
+/* RGBA functions */
+
+/**
+ * gimp_rgba_set_pixel:
+ * @rgba: a #GimpRGB struct
+ * @format: a Babl format
+ * @pixel: pointer to the source pixel
+ *
+ * Sets the red, green, blue and alpha components of @rgba from the
+ * color stored in @pixel. The pixel format of @pixel is determined
+ * by @format.
+ *
+ * Since: 2.10
+ **/
+void
+gimp_rgba_set_pixel (GimpRGB *rgba,
+ const Babl *format,
+ gconstpointer pixel)
+{
+ g_return_if_fail (rgba != NULL);
+ g_return_if_fail (format != NULL);
+ g_return_if_fail (pixel != NULL);
+
+ babl_process (babl_fish (format,
+ babl_format ("R'G'B'A double")),
+ pixel, rgba, 1);
+}
+
+/**
+ * gimp_rgba_get_pixel:
+ * @rgba: a #GimpRGB struct
+ * @format: a Babl format
+ * @pixel: pointer to the destination pixel
+ *
+ * Writes the red, green, blue and alpha components of @rgba to the
+ * color stored in @pixel. The pixel format of @pixel is determined by
+ * @format.
+ *
+ * Since: 2.10
+ **/
+void
+gimp_rgba_get_pixel (const GimpRGB *rgba,
+ const Babl *format,
+ gpointer pixel)
+{
+ g_return_if_fail (rgba != NULL);
+ g_return_if_fail (format != NULL);
+ g_return_if_fail (pixel != NULL);
+
+ babl_process (babl_fish (babl_format ("R'G'B'A double"),
+ format),
+ rgba, pixel, 1);
+}
+
+/**
+ * gimp_rgba_set:
+ * @rgba: a #GimpRGB struct
+ * @red: the red component
+ * @green: the green component
+ * @blue: the blue component
+ * @alpha: the alpha component
+ *
+ * Sets the red, green, blue and alpha components of @rgb. The values
+ * should be between 0.0 and 1.0 but there is no check to enforce this
+ * and the values are set exactly as they are passed in.
+ **/
+void
+gimp_rgba_set (GimpRGB *rgba,
+ gdouble r,
+ gdouble g,
+ gdouble b,
+ gdouble a)
+{
+ g_return_if_fail (rgba != NULL);
+
+ rgba->r = r;
+ rgba->g = g;
+ rgba->b = b;
+ rgba->a = a;
+}
+
+/**
+ * gimp_rgba_set_uchar:
+ * @rgba: a #GimpRGB struct
+ * @red: the red component
+ * @green: the green component
+ * @blue: the blue component
+ * @alpha: the alpha component
+ *
+ * Sets the red, green, blue and alpha components of @rgb from 8bit
+ * values (0 to 255).
+ **/
+void
+gimp_rgba_set_uchar (GimpRGB *rgba,
+ guchar r,
+ guchar g,
+ guchar b,
+ guchar a)
+{
+ g_return_if_fail (rgba != NULL);
+
+ rgba->r = (gdouble) r / 255.0;
+ rgba->g = (gdouble) g / 255.0;
+ rgba->b = (gdouble) b / 255.0;
+ rgba->a = (gdouble) a / 255.0;
+}
+
+void
+gimp_rgba_get_uchar (const GimpRGB *rgba,
+ guchar *r,
+ guchar *g,
+ guchar *b,
+ guchar *a)
+{
+ g_return_if_fail (rgba != NULL);
+
+ if (r) *r = ROUND (CLAMP (rgba->r, 0.0, 1.0) * 255.0);
+ if (g) *g = ROUND (CLAMP (rgba->g, 0.0, 1.0) * 255.0);
+ if (b) *b = ROUND (CLAMP (rgba->b, 0.0, 1.0) * 255.0);
+ if (a) *a = ROUND (CLAMP (rgba->a, 0.0, 1.0) * 255.0);
+}
+
+void
+gimp_rgba_add (GimpRGB *rgba1,
+ const GimpRGB *rgba2)
+{
+ g_return_if_fail (rgba1 != NULL);
+ g_return_if_fail (rgba2 != NULL);
+
+ rgba1->r += rgba2->r;
+ rgba1->g += rgba2->g;
+ rgba1->b += rgba2->b;
+ rgba1->a += rgba2->a;
+}
+
+void
+gimp_rgba_subtract (GimpRGB *rgba1,
+ const GimpRGB *rgba2)
+{
+ g_return_if_fail (rgba1 != NULL);
+ g_return_if_fail (rgba2 != NULL);
+
+ rgba1->r -= rgba2->r;
+ rgba1->g -= rgba2->g;
+ rgba1->b -= rgba2->b;
+ rgba1->a -= rgba2->a;
+}
+
+void
+gimp_rgba_multiply (GimpRGB *rgba,
+ gdouble factor)
+{
+ g_return_if_fail (rgba != NULL);
+
+ rgba->r *= factor;
+ rgba->g *= factor;
+ rgba->b *= factor;
+ rgba->a *= factor;
+}
+
+gdouble
+gimp_rgba_distance (const GimpRGB *rgba1,
+ const GimpRGB *rgba2)
+{
+ g_return_val_if_fail (rgba1 != NULL, 0.0);
+ g_return_val_if_fail (rgba2 != NULL, 0.0);
+
+ return (fabs (rgba1->r - rgba2->r) +
+ fabs (rgba1->g - rgba2->g) +
+ fabs (rgba1->b - rgba2->b) +
+ fabs (rgba1->a - rgba2->a));
+}
+
+
+/*
+ * GIMP_TYPE_PARAM_RGB
+ */
+
+#define GIMP_PARAM_SPEC_RGB(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_RGB, GimpParamSpecRGB))
+
+typedef struct _GimpParamSpecRGB GimpParamSpecRGB;
+
+struct _GimpParamSpecRGB
+{
+ GParamSpecBoxed parent_instance;
+
+ gboolean has_alpha;
+ gboolean validate; /* change this to enable [0.0...1.0] */
+ GimpRGB default_value;
+};
+
+static void gimp_param_rgb_class_init (GParamSpecClass *class);
+static void gimp_param_rgb_init (GParamSpec *pspec);
+static void gimp_param_rgb_set_default (GParamSpec *pspec,
+ GValue *value);
+static gboolean gimp_param_rgb_validate (GParamSpec *pspec,
+ GValue *value);
+static gint gimp_param_rgb_values_cmp (GParamSpec *pspec,
+ const GValue *value1,
+ const GValue *value2);
+
+/**
+ * gimp_param_rgb_get_type:
+ *
+ * Reveals the object type
+ *
+ * Returns: the #GType for a GimpParamRGB object
+ *
+ * Since: 2.4
+ **/
+GType
+gimp_param_rgb_get_type (void)
+{
+ static GType spec_type = 0;
+
+ if (! spec_type)
+ {
+ const GTypeInfo type_info =
+ {
+ sizeof (GParamSpecClass),
+ NULL, NULL,
+ (GClassInitFunc) gimp_param_rgb_class_init,
+ NULL, NULL,
+ sizeof (GimpParamSpecRGB),
+ 0,
+ (GInstanceInitFunc) gimp_param_rgb_init
+ };
+
+ spec_type = g_type_register_static (G_TYPE_PARAM_BOXED,
+ "GimpParamRGB",
+ &type_info, 0);
+ }
+
+ return spec_type;
+}
+
+static void
+gimp_param_rgb_class_init (GParamSpecClass *class)
+{
+ class->value_type = GIMP_TYPE_RGB;
+ class->value_set_default = gimp_param_rgb_set_default;
+ class->value_validate = gimp_param_rgb_validate;
+ class->values_cmp = gimp_param_rgb_values_cmp;
+}
+
+static void
+gimp_param_rgb_init (GParamSpec *pspec)
+{
+ GimpParamSpecRGB *cspec = GIMP_PARAM_SPEC_RGB (pspec);
+
+ gimp_rgba_set (&cspec->default_value, 0.0, 0.0, 0.0, 1.0);
+}
+
+static void
+gimp_param_rgb_set_default (GParamSpec *pspec,
+ GValue *value)
+{
+ GimpParamSpecRGB *cspec = GIMP_PARAM_SPEC_RGB (pspec);
+
+ g_value_set_static_boxed (value, &cspec->default_value);
+}
+
+static gboolean
+gimp_param_rgb_validate (GParamSpec *pspec,
+ GValue *value)
+{
+ GimpParamSpecRGB *rgb_spec = GIMP_PARAM_SPEC_RGB (pspec);
+ GimpRGB *rgb = value->data[0].v_pointer;
+
+ if (rgb_spec->validate && rgb)
+ {
+ GimpRGB oval = *rgb;
+
+ gimp_rgb_clamp (rgb);
+
+ return (oval.r != rgb->r ||
+ oval.g != rgb->g ||
+ oval.b != rgb->b ||
+ (rgb_spec->has_alpha && oval.a != rgb->a));
+ }
+
+ return FALSE;
+}
+
+static gint
+gimp_param_rgb_values_cmp (GParamSpec *pspec,
+ const GValue *value1,
+ const GValue *value2)
+{
+ GimpRGB *rgb1 = value1->data[0].v_pointer;
+ GimpRGB *rgb2 = value2->data[0].v_pointer;
+
+ /* try to return at least *something*, it's useless anyway... */
+
+ if (! rgb1)
+ {
+ return rgb2 != NULL ? -1 : 0;
+ }
+ else if (! rgb2)
+ {
+ return rgb1 != NULL;
+ }
+ else
+ {
+ guint32 int1 = 0;
+ guint32 int2 = 0;
+
+ if (GIMP_PARAM_SPEC_RGB (pspec)->has_alpha)
+ {
+ gimp_rgba_get_uchar (rgb1,
+ ((guchar *) &int1) + 0,
+ ((guchar *) &int1) + 1,
+ ((guchar *) &int1) + 2,
+ ((guchar *) &int1) + 3);
+ gimp_rgba_get_uchar (rgb2,
+ ((guchar *) &int2) + 0,
+ ((guchar *) &int2) + 1,
+ ((guchar *) &int2) + 2,
+ ((guchar *) &int2) + 3);
+ }
+ else
+ {
+ gimp_rgb_get_uchar (rgb1,
+ ((guchar *) &int1) + 0,
+ ((guchar *) &int1) + 1,
+ ((guchar *) &int1) + 2);
+ gimp_rgb_get_uchar (rgb2,
+ ((guchar *) &int2) + 0,
+ ((guchar *) &int2) + 1,
+ ((guchar *) &int2) + 2);
+ }
+
+ return int1 - int2;
+ }
+}
+
+/**
+ * gimp_param_spec_rgb:
+ * @name: Canonical name of the param
+ * @nick: Nickname of the param
+ * @blurb: Brief description of param.
+ * @has_alpha: %TRUE if the alpha channel has relevance.
+ * @default_value: Value to use if none is assigned.
+ * @flags: a combination of #GParamFlags
+ *
+ * Creates a param spec to hold an #GimpRGB value.
+ * See g_param_spec_internal() for more information.
+ *
+ * Returns: a newly allocated #GParamSpec instance
+ *
+ * Since: 2.4
+ **/
+GParamSpec *
+gimp_param_spec_rgb (const gchar *name,
+ const gchar *nick,
+ const gchar *blurb,
+ gboolean has_alpha,
+ const GimpRGB *default_value,
+ GParamFlags flags)
+{
+ GimpParamSpecRGB *cspec;
+
+ cspec = g_param_spec_internal (GIMP_TYPE_PARAM_RGB,
+ name, nick, blurb, flags);
+
+ cspec->has_alpha = has_alpha;
+
+ if (default_value)
+ cspec->default_value = *default_value;
+ else
+ gimp_rgba_set (&cspec->default_value, 0.0, 0.0, 0.0, 1.0);
+
+ return G_PARAM_SPEC (cspec);
+}
+
+/**
+ * gimp_param_spec_rgb_get_default:
+ * @pspec: a #GimpParamSpecRGB.
+ * @default_value: return location for @pspec's default value
+ *
+ * Returns the @pspec's default color value.
+ *
+ * Since: 2.10.14
+ **/
+void
+gimp_param_spec_rgb_get_default (GParamSpec *pspec,
+ GimpRGB *default_value)
+{
+ g_return_if_fail (GIMP_IS_PARAM_SPEC_RGB (pspec));
+ g_return_if_fail (default_value != NULL);
+
+ *default_value = GIMP_PARAM_SPEC_RGB (pspec)->default_value;
+}
+
+/**
+ * gimp_param_spec_rgb_has_alpha:
+ * @pspec: a #GParamSpec to hold an #GimpRGB value.
+ *
+ * Returns: %TRUE if the alpha channel is relevant.
+ *
+ * Since: 2.4
+ **/
+gboolean
+gimp_param_spec_rgb_has_alpha (GParamSpec *pspec)
+{
+ g_return_val_if_fail (GIMP_IS_PARAM_SPEC_RGB (pspec), FALSE);
+
+ return GIMP_PARAM_SPEC_RGB (pspec)->has_alpha;
+}
diff --git a/libgimpcolor/gimprgb.h b/libgimpcolor/gimprgb.h
new file mode 100644
index 0000000..089d97c
--- /dev/null
+++ b/libgimpcolor/gimprgb.h
@@ -0,0 +1,233 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
+ *
+ * This library 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.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_COLOR_H_INSIDE__) && !defined (GIMP_COLOR_COMPILATION)
+#error "Only <libgimpcolor/gimpcolor.h> can be included directly."
+#endif
+
+#ifndef __GIMP_RGB_H__
+#define __GIMP_RGB_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+/*
+ * GIMP_TYPE_RGB
+ */
+
+#define GIMP_TYPE_RGB (gimp_rgb_get_type ())
+#define GIMP_VALUE_HOLDS_RGB(value) (G_TYPE_CHECK_VALUE_TYPE ((value), GIMP_TYPE_RGB))
+
+GType gimp_rgb_get_type (void) G_GNUC_CONST;
+
+void gimp_value_get_rgb (const GValue *value,
+ GimpRGB *rgb);
+void gimp_value_set_rgb (GValue *value,
+ const GimpRGB *rgb);
+
+
+/*
+ * GIMP_TYPE_PARAM_RGB
+ */
+
+#define GIMP_TYPE_PARAM_RGB (gimp_param_rgb_get_type ())
+#define GIMP_IS_PARAM_SPEC_RGB(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), GIMP_TYPE_PARAM_RGB))
+
+
+GType gimp_param_rgb_get_type (void) G_GNUC_CONST;
+
+GParamSpec * gimp_param_spec_rgb (const gchar *name,
+ const gchar *nick,
+ const gchar *blurb,
+ gboolean has_alpha,
+ const GimpRGB *default_value,
+ GParamFlags flags);
+
+void gimp_param_spec_rgb_get_default (GParamSpec *pspec,
+ GimpRGB *default_value);
+gboolean gimp_param_spec_rgb_has_alpha (GParamSpec *pspec);
+
+
+/* RGB and RGBA color types and operations taken from LibGCK */
+
+/**
+ * GimpRGBCompositeMode:
+ * @GIMP_RGB_COMPOSITE_NONE: don't do compositing
+ * @GIMP_RGB_COMPOSITE_NORMAL: composite on top
+ * @GIMP_RGB_COMPOSITE_BEHIND: composite behind
+ **/
+typedef enum
+{
+ GIMP_RGB_COMPOSITE_NONE = 0,
+ GIMP_RGB_COMPOSITE_NORMAL,
+ GIMP_RGB_COMPOSITE_BEHIND
+} GimpRGBCompositeMode;
+
+
+void gimp_rgb_set (GimpRGB *rgb,
+ gdouble red,
+ gdouble green,
+ gdouble blue);
+void gimp_rgb_set_alpha (GimpRGB *rgb,
+ gdouble alpha);
+
+void gimp_rgb_set_pixel (GimpRGB *rgb,
+ const Babl *format,
+ gconstpointer pixel);
+void gimp_rgb_get_pixel (const GimpRGB *rgb,
+ const Babl *format,
+ gpointer pixel);
+
+void gimp_rgb_set_uchar (GimpRGB *rgb,
+ guchar red,
+ guchar green,
+ guchar blue);
+void gimp_rgb_get_uchar (const GimpRGB *rgb,
+ guchar *red,
+ guchar *green,
+ guchar *blue);
+
+gboolean gimp_rgb_parse_name (GimpRGB *rgb,
+ const gchar *name,
+ gint len);
+gboolean gimp_rgb_parse_hex (GimpRGB *rgb,
+ const gchar *hex,
+ gint len);
+gboolean gimp_rgb_parse_css (GimpRGB *rgb,
+ const gchar *css,
+ gint len);
+
+void gimp_rgb_add (GimpRGB *rgb1,
+ const GimpRGB *rgb2);
+void gimp_rgb_subtract (GimpRGB *rgb1,
+ const GimpRGB *rgb2);
+void gimp_rgb_multiply (GimpRGB *rgb1,
+ gdouble factor);
+gdouble gimp_rgb_distance (const GimpRGB *rgb1,
+ const GimpRGB *rgb2);
+
+gdouble gimp_rgb_max (const GimpRGB *rgb);
+gdouble gimp_rgb_min (const GimpRGB *rgb);
+void gimp_rgb_clamp (GimpRGB *rgb);
+
+void gimp_rgb_gamma (GimpRGB *rgb,
+ gdouble gamma);
+
+gdouble gimp_rgb_luminance (const GimpRGB *rgb);
+guchar gimp_rgb_luminance_uchar (const GimpRGB *rgb);
+
+GIMP_DEPRECATED_FOR(gimp_rgb_luminance)
+gdouble gimp_rgb_intensity (const GimpRGB *rgb);
+GIMP_DEPRECATED_FOR(gimp_rgb_luminance_uchar)
+guchar gimp_rgb_intensity_uchar (const GimpRGB *rgb);
+
+void gimp_rgb_composite (GimpRGB *color1,
+ const GimpRGB *color2,
+ GimpRGBCompositeMode mode);
+
+/* access to the list of color names */
+gint gimp_rgb_list_names (const gchar ***names,
+ GimpRGB **colors);
+
+
+void gimp_rgba_set (GimpRGB *rgba,
+ gdouble red,
+ gdouble green,
+ gdouble blue,
+ gdouble alpha);
+
+void gimp_rgba_set_pixel (GimpRGB *rgba,
+ const Babl *format,
+ gconstpointer pixel);
+void gimp_rgba_get_pixel (const GimpRGB *rgba,
+ const Babl *format,
+ gpointer pixel);
+
+void gimp_rgba_set_uchar (GimpRGB *rgba,
+ guchar red,
+ guchar green,
+ guchar blue,
+ guchar alpha);
+void gimp_rgba_get_uchar (const GimpRGB *rgba,
+ guchar *red,
+ guchar *green,
+ guchar *blue,
+ guchar *alpha);
+
+gboolean gimp_rgba_parse_css (GimpRGB *rgba,
+ const gchar *css,
+ gint len);
+
+void gimp_rgba_add (GimpRGB *rgba1,
+ const GimpRGB *rgba2);
+void gimp_rgba_subtract (GimpRGB *rgba1,
+ const GimpRGB *rgba2);
+void gimp_rgba_multiply (GimpRGB *rgba,
+ gdouble factor);
+
+gdouble gimp_rgba_distance (const GimpRGB *rgba1,
+ const GimpRGB *rgba2);
+
+
+
+/* Map D50-adapted sRGB to luminance */
+
+/*
+ * The weights to compute true CIE luminance from linear red, green
+ * and blue as defined by the sRGB color space specs in an ICC profile
+ * color managed application. The weights below have been chromatically
+ * adapted from D65 (as specified by the sRGB color space specs)
+ * to D50 (as specified by D50 illuminant values in the ICC V4 specs).
+ */
+
+#define GIMP_RGB_LUMINANCE_RED (0.22248840)
+#define GIMP_RGB_LUMINANCE_GREEN (0.71690369)
+#define GIMP_RGB_LUMINANCE_BLUE (0.06060791)
+
+#define GIMP_RGB_LUMINANCE(r,g,b) ((r) * GIMP_RGB_LUMINANCE_RED + \
+ (g) * GIMP_RGB_LUMINANCE_GREEN + \
+ (b) * GIMP_RGB_LUMINANCE_BLUE)
+
+
+#ifndef GIMP_DISABLE_DEPRECATED
+
+/*
+ * The coefficients below properly computed luminance for monitors
+ * having phosphors that were contemporary at the introduction of NTSC
+ * television in 1953. They are still appropriate for computing video
+ * luma. However, these coefficients do not accurately compute
+ * luminance for contemporary monitors. The use of these definitions
+ * is deprecated.
+ */
+
+#define GIMP_RGB_INTENSITY_RED (0.30)
+#define GIMP_RGB_INTENSITY_GREEN (0.59)
+#define GIMP_RGB_INTENSITY_BLUE (0.11)
+
+#define GIMP_RGB_INTENSITY(r,g,b) ((r) * GIMP_RGB_INTENSITY_RED + \
+ (g) * GIMP_RGB_INTENSITY_GREEN + \
+ (b) * GIMP_RGB_INTENSITY_BLUE)
+
+#endif
+
+
+G_END_DECLS
+
+#endif /* __GIMP_RGB_H__ */
diff --git a/libgimpcolor/test-color-parser.c b/libgimpcolor/test-color-parser.c
new file mode 100644
index 0000000..4ce7c50
--- /dev/null
+++ b/libgimpcolor/test-color-parser.c
@@ -0,0 +1,119 @@
+/* unit tests for the color parsing routines in gimprgb-parse.c
+ */
+
+#include "config.h"
+
+#include <stdlib.h>
+
+#include <babl/babl.h>
+#include <gegl.h>
+#include <gdk-pixbuf/gdk-pixbuf.h>
+
+#include <glib-object.h>
+#include <cairo.h>
+
+#include "gimpcolor.h"
+
+
+#define DBL(c) ((gdouble)(c) / 255.0)
+
+
+typedef struct
+{
+ const gchar *str;
+ gboolean alpha;
+ gboolean fail;
+ const gdouble r;
+ const gdouble g;
+ const gdouble b;
+ const gdouble a;
+} ColorSample;
+
+static const ColorSample samples[] =
+{
+ /* sample alpha fail red green blue alpha */
+
+ { "#000000", FALSE, FALSE, 0.0, 0.0, 0.0, 0.0 },
+ { "#FFff00", FALSE, FALSE, 1.0, 1.0, 0.0, 0.0 },
+ { "#6495ed", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 },
+ { "#fff", FALSE, FALSE, 1.0, 1.0, 1.0, 0.0 },
+ { "#64649595eded", FALSE, FALSE, 1.0, 1.0, 0.0, 0.0 },
+ { "rgb(0,0,0)", FALSE, FALSE, 0.0, 0.0, 0.0, 0.0 },
+ { "rgb(100,149,237)", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 },
+ { "rgba(100%,0,100%,0.5)", TRUE, FALSE, 255.0, 0.0, 255.0, 0.5 },
+ { "rgba(100%,0,100%,0.5)", FALSE, TRUE, 255.0, 0.0, 255.0, 0.5 },
+ { "rgb(100%,149,20%)", FALSE, FALSE, 1.0, DBL(149), 0.2, 0.0 },
+ { "rgb(100%,149,20%)", TRUE, TRUE, 1.0, DBL(149), 0.2, 0.0 },
+ { "rgb(foobar)", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
+ { "rgb(100,149,237", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
+ { "rED", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
+ { "cornflowerblue", FALSE, FALSE, DBL(100), DBL(149), DBL(237), 0.0 },
+ { " red", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
+ { "red ", FALSE, FALSE, 1.0, 0.0, 0.0, 0.0 },
+ { "red", TRUE, TRUE, 1.0, 0.0, 0.0, 0.0 },
+ { "red blue", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
+ { "transparent", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
+ { "transparent", TRUE, FALSE, 0.0, 0.0, 0.0, 0.0 },
+ { "23foobar", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 },
+ { "", FALSE, TRUE, 0.0, 0.0, 0.0, 0.0 }
+};
+
+
+static gint
+check_failure (const ColorSample *sample,
+ gboolean success,
+ GimpRGB *rgb)
+{
+ if (success && sample->fail)
+ {
+ g_print ("Parser succeeded for sample \"%s\" but should have failed!\n"
+ " parsed color: (%g, %g, %g, %g)\n",
+ sample->str, rgb->r, rgb->g, rgb->b, rgb->a);
+ return 1;
+ }
+
+ if (!success && !sample->fail)
+ {
+ g_print ("Parser failed for sample \"%s\" but should have succeeded!\n"
+ " parsed color: (%g, %g, %g, %g)\n",
+ sample->str, rgb->r, rgb->g, rgb->b, rgb->a);
+ return 1;
+ }
+
+ return 0;
+}
+
+int
+main (void)
+{
+ gint failures = 0;
+ gint i;
+
+ g_print ("\nTesting the GIMP color parser ...\n");
+
+ for (i = 0; i < G_N_ELEMENTS (samples); i++)
+ {
+ GimpRGB rgb = { 0.0, 0.0, 0.0, 0.0 };
+ gboolean success;
+
+ if (samples[i].alpha)
+ success = gimp_rgba_parse_css (&rgb, samples[i].str, -1);
+ else
+ success = gimp_rgb_parse_css (&rgb, samples[i].str, -1);
+
+ failures += check_failure (samples + i, success, &rgb);
+ }
+
+ if (failures)
+ {
+ g_print ("%d out of %d samples failed!\n\n",
+ failures, (int)G_N_ELEMENTS (samples));
+ return EXIT_FAILURE;
+ }
+ else
+ {
+ g_print ("All %d samples passed.\n\n", (int)G_N_ELEMENTS (samples));
+ return EXIT_SUCCESS;
+ }
+}
+