diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 18:30:19 +0000 |
commit | 5c1676dfe6d2f3c837a5e074117b45613fd29a72 (patch) | |
tree | cbffb45144febf451e54061db2b21395faf94bfe /libgimpcolor | |
parent | Initial commit. (diff) | |
download | gimp-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')
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='[0;31m'; \ + grn='[0;32m'; \ + lgn='[1;32m'; \ + blu='[1;34m'; \ + mgn='[0;35m'; \ + brg='[1m'; \ + std='[m'; \ + 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; + } +} + |