diff options
Diffstat (limited to 'app/operations')
152 files changed, 33831 insertions, 0 deletions
diff --git a/app/operations/Makefile.am b/app/operations/Makefile.am new file mode 100644 index 0000000..24bfe6d --- /dev/null +++ b/app/operations/Makefile.am @@ -0,0 +1,140 @@ +## Process this file with automake to produce Makefile.in + +SUBDIRS = \ + layer-modes \ + layer-modes-legacy \ + tests + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Operations\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = \ + libappoperations.a + +libappoperations_a_sources = \ + operations-types.h \ + operations-enums.h \ + gimp-operations.c \ + gimp-operations.h \ + \ + gimp-operation-config.c \ + gimp-operation-config.h \ + gimpoperationsettings.c \ + gimpoperationsettings.h \ + gimpbrightnesscontrastconfig.c \ + gimpbrightnesscontrastconfig.h \ + gimpcageconfig.c \ + gimpcageconfig.h \ + gimpcolorbalanceconfig.c \ + gimpcolorbalanceconfig.h \ + gimpcurvesconfig.c \ + gimpcurvesconfig.h \ + gimphuesaturationconfig.c \ + gimphuesaturationconfig.h \ + gimplevelsconfig.c \ + gimplevelsconfig.h \ + \ + gimpoperationborder.c \ + gimpoperationborder.h \ + gimpoperationbuffersourcevalidate.c \ + gimpoperationbuffersourcevalidate.h \ + gimpoperationcagecoefcalc.c \ + gimpoperationcagecoefcalc.h \ + gimpoperationcagetransform.c \ + gimpoperationcagetransform.h \ + gimpoperationcomposecrop.c \ + gimpoperationcomposecrop.h \ + gimpoperationequalize.c \ + gimpoperationequalize.h \ + gimpoperationfillsource.c \ + gimpoperationfillsource.h \ + gimpoperationflood.c \ + gimpoperationflood.h \ + gimpoperationgradient.c \ + gimpoperationgradient.h \ + gimpoperationgrow.c \ + gimpoperationgrow.h \ + gimpoperationhistogramsink.c \ + gimpoperationhistogramsink.h \ + gimpoperationmaskcomponents.cc \ + gimpoperationmaskcomponents.h \ + gimpoperationoffset.c \ + gimpoperationoffset.h \ + gimpoperationprofiletransform.c \ + gimpoperationprofiletransform.h \ + gimpoperationscalarmultiply.c \ + gimpoperationscalarmultiply.h \ + gimpoperationsemiflatten.c \ + gimpoperationsemiflatten.h \ + gimpoperationsetalpha.c \ + gimpoperationsetalpha.h \ + gimpoperationshrink.c \ + gimpoperationshrink.h \ + gimpoperationthresholdalpha.c \ + gimpoperationthresholdalpha.h \ + \ + gimpoperationpointfilter.c \ + gimpoperationpointfilter.h \ + gimpoperationbrightnesscontrast.c \ + gimpoperationbrightnesscontrast.h \ + gimpoperationcolorbalance.c \ + gimpoperationcolorbalance.h \ + gimpoperationcolorize.c \ + gimpoperationcolorize.h \ + gimpoperationcurves.c \ + gimpoperationcurves.h \ + gimpoperationdesaturate.c \ + gimpoperationdesaturate.h \ + gimpoperationhuesaturation.c \ + gimpoperationhuesaturation.h \ + gimpoperationlevels.c \ + gimpoperationlevels.h \ + gimpoperationposterize.c \ + gimpoperationposterize.h \ + gimpoperationthreshold.c \ + gimpoperationthreshold.h + +libappoperations_a_built_sources = operations-enums.c + +libappoperations_a_SOURCES = \ + $(libappoperations_a_built_sources) \ + $(libappoperations_a_sources) + +# +# rules to generate built sources +# +# setup autogeneration dependencies +gen_sources = xgen-oec +CLEANFILES = $(gen_sources) + +xgen-oec: $(srcdir)/operations-enums.h $(GIMP_MKENUMS) Makefile.am + $(AM_V_GEN) $(GIMP_MKENUMS) \ + --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"operations-enums.h\"\n#include \"gimp-intl.h\"" \ + --fprod "\n/* enumerations from \"@basename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n" \ + --dhead " static const Gimp@Type@Desc descs[] =\n {" \ + --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \ + --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \ + $< > $@ + +# copy the generated enum file back to the source directory only if it's +# changed; otherwise, only update its timestamp, so that the recipe isn't +# executed again on the next build, however, allow this to (harmlessly) fail, +# to support building from a read-only source tree. +$(srcdir)/operations-enums.c: xgen-oec + $(AM_V_GEN) if ! cmp -s $< $@; then \ + cp $< $@; \ + else \ + touch $@ 2> /dev/null \ + || true; \ + fi diff --git a/app/operations/Makefile.in b/app/operations/Makefile.in new file mode 100644 index 0000000..e960ea3 --- /dev/null +++ b/app/operations/Makefile.in @@ -0,0 +1,1376 @@ +# 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@ +subdir = app/operations +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 $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libappoperations_a_AR = $(AR) $(ARFLAGS) +libappoperations_a_LIBADD = +am__objects_1 = operations-enums.$(OBJEXT) +am__objects_2 = gimp-operations.$(OBJEXT) \ + gimp-operation-config.$(OBJEXT) \ + gimpoperationsettings.$(OBJEXT) \ + gimpbrightnesscontrastconfig.$(OBJEXT) \ + gimpcageconfig.$(OBJEXT) gimpcolorbalanceconfig.$(OBJEXT) \ + gimpcurvesconfig.$(OBJEXT) gimphuesaturationconfig.$(OBJEXT) \ + gimplevelsconfig.$(OBJEXT) gimpoperationborder.$(OBJEXT) \ + gimpoperationbuffersourcevalidate.$(OBJEXT) \ + gimpoperationcagecoefcalc.$(OBJEXT) \ + gimpoperationcagetransform.$(OBJEXT) \ + gimpoperationcomposecrop.$(OBJEXT) \ + gimpoperationequalize.$(OBJEXT) \ + gimpoperationfillsource.$(OBJEXT) gimpoperationflood.$(OBJEXT) \ + gimpoperationgradient.$(OBJEXT) gimpoperationgrow.$(OBJEXT) \ + gimpoperationhistogramsink.$(OBJEXT) \ + gimpoperationmaskcomponents.$(OBJEXT) \ + gimpoperationoffset.$(OBJEXT) \ + gimpoperationprofiletransform.$(OBJEXT) \ + gimpoperationscalarmultiply.$(OBJEXT) \ + gimpoperationsemiflatten.$(OBJEXT) \ + gimpoperationsetalpha.$(OBJEXT) gimpoperationshrink.$(OBJEXT) \ + gimpoperationthresholdalpha.$(OBJEXT) \ + gimpoperationpointfilter.$(OBJEXT) \ + gimpoperationbrightnesscontrast.$(OBJEXT) \ + gimpoperationcolorbalance.$(OBJEXT) \ + gimpoperationcolorize.$(OBJEXT) gimpoperationcurves.$(OBJEXT) \ + gimpoperationdesaturate.$(OBJEXT) \ + gimpoperationhuesaturation.$(OBJEXT) \ + gimpoperationlevels.$(OBJEXT) gimpoperationposterize.$(OBJEXT) \ + gimpoperationthreshold.$(OBJEXT) +am_libappoperations_a_OBJECTS = $(am__objects_1) $(am__objects_2) +libappoperations_a_OBJECTS = $(am_libappoperations_a_OBJECTS) +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)/gimp-operation-config.Po \ + ./$(DEPDIR)/gimp-operations.Po \ + ./$(DEPDIR)/gimpbrightnesscontrastconfig.Po \ + ./$(DEPDIR)/gimpcageconfig.Po \ + ./$(DEPDIR)/gimpcolorbalanceconfig.Po \ + ./$(DEPDIR)/gimpcurvesconfig.Po \ + ./$(DEPDIR)/gimphuesaturationconfig.Po \ + ./$(DEPDIR)/gimplevelsconfig.Po \ + ./$(DEPDIR)/gimpoperationborder.Po \ + ./$(DEPDIR)/gimpoperationbrightnesscontrast.Po \ + ./$(DEPDIR)/gimpoperationbuffersourcevalidate.Po \ + ./$(DEPDIR)/gimpoperationcagecoefcalc.Po \ + ./$(DEPDIR)/gimpoperationcagetransform.Po \ + ./$(DEPDIR)/gimpoperationcolorbalance.Po \ + ./$(DEPDIR)/gimpoperationcolorize.Po \ + ./$(DEPDIR)/gimpoperationcomposecrop.Po \ + ./$(DEPDIR)/gimpoperationcurves.Po \ + ./$(DEPDIR)/gimpoperationdesaturate.Po \ + ./$(DEPDIR)/gimpoperationequalize.Po \ + ./$(DEPDIR)/gimpoperationfillsource.Po \ + ./$(DEPDIR)/gimpoperationflood.Po \ + ./$(DEPDIR)/gimpoperationgradient.Po \ + ./$(DEPDIR)/gimpoperationgrow.Po \ + ./$(DEPDIR)/gimpoperationhistogramsink.Po \ + ./$(DEPDIR)/gimpoperationhuesaturation.Po \ + ./$(DEPDIR)/gimpoperationlevels.Po \ + ./$(DEPDIR)/gimpoperationmaskcomponents.Po \ + ./$(DEPDIR)/gimpoperationoffset.Po \ + ./$(DEPDIR)/gimpoperationpointfilter.Po \ + ./$(DEPDIR)/gimpoperationposterize.Po \ + ./$(DEPDIR)/gimpoperationprofiletransform.Po \ + ./$(DEPDIR)/gimpoperationscalarmultiply.Po \ + ./$(DEPDIR)/gimpoperationsemiflatten.Po \ + ./$(DEPDIR)/gimpoperationsetalpha.Po \ + ./$(DEPDIR)/gimpoperationsettings.Po \ + ./$(DEPDIR)/gimpoperationshrink.Po \ + ./$(DEPDIR)/gimpoperationthreshold.Po \ + ./$(DEPDIR)/gimpoperationthresholdalpha.Po \ + ./$(DEPDIR)/operations-enums.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +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 = +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 = +CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \ + $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) +LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CXXFLAGS) $(CXXFLAGS) +AM_V_CXX = $(am__v_CXX_@AM_V@) +am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@) +am__v_CXX_0 = @echo " CXX " $@; +am__v_CXX_1 = +CXXLD = $(CXX) +CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \ + $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CXXLD = $(am__v_CXXLD_@AM_V@) +am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@) +am__v_CXXLD_0 = @echo " CXXLD " $@; +am__v_CXXLD_1 = +SOURCES = $(libappoperations_a_SOURCES) +DIST_SOURCES = $(libappoperations_a_SOURCES) +RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ + ctags-recursive dvi-recursive html-recursive info-recursive \ + install-data-recursive install-dvi-recursive \ + install-exec-recursive install-html-recursive \ + install-info-recursive install-pdf-recursive \ + install-ps-recursive install-recursive installcheck-recursive \ + installdirs-recursive pdf-recursive ps-recursive \ + tags-recursive uninstall-recursive +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +am__recursive_targets = \ + $(RECURSIVE_TARGETS) \ + $(RECURSIVE_CLEAN_TARGETS) \ + $(am__extra_recursive_targets) +AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ + distdir distdir-am +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 +DIST_SUBDIRS = $(SUBDIRS) +am__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +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@ +SUBDIRS = \ + layer-modes \ + layer-modes-legacy \ + tests + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Operations\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = \ + libappoperations.a + +libappoperations_a_sources = \ + operations-types.h \ + operations-enums.h \ + gimp-operations.c \ + gimp-operations.h \ + \ + gimp-operation-config.c \ + gimp-operation-config.h \ + gimpoperationsettings.c \ + gimpoperationsettings.h \ + gimpbrightnesscontrastconfig.c \ + gimpbrightnesscontrastconfig.h \ + gimpcageconfig.c \ + gimpcageconfig.h \ + gimpcolorbalanceconfig.c \ + gimpcolorbalanceconfig.h \ + gimpcurvesconfig.c \ + gimpcurvesconfig.h \ + gimphuesaturationconfig.c \ + gimphuesaturationconfig.h \ + gimplevelsconfig.c \ + gimplevelsconfig.h \ + \ + gimpoperationborder.c \ + gimpoperationborder.h \ + gimpoperationbuffersourcevalidate.c \ + gimpoperationbuffersourcevalidate.h \ + gimpoperationcagecoefcalc.c \ + gimpoperationcagecoefcalc.h \ + gimpoperationcagetransform.c \ + gimpoperationcagetransform.h \ + gimpoperationcomposecrop.c \ + gimpoperationcomposecrop.h \ + gimpoperationequalize.c \ + gimpoperationequalize.h \ + gimpoperationfillsource.c \ + gimpoperationfillsource.h \ + gimpoperationflood.c \ + gimpoperationflood.h \ + gimpoperationgradient.c \ + gimpoperationgradient.h \ + gimpoperationgrow.c \ + gimpoperationgrow.h \ + gimpoperationhistogramsink.c \ + gimpoperationhistogramsink.h \ + gimpoperationmaskcomponents.cc \ + gimpoperationmaskcomponents.h \ + gimpoperationoffset.c \ + gimpoperationoffset.h \ + gimpoperationprofiletransform.c \ + gimpoperationprofiletransform.h \ + gimpoperationscalarmultiply.c \ + gimpoperationscalarmultiply.h \ + gimpoperationsemiflatten.c \ + gimpoperationsemiflatten.h \ + gimpoperationsetalpha.c \ + gimpoperationsetalpha.h \ + gimpoperationshrink.c \ + gimpoperationshrink.h \ + gimpoperationthresholdalpha.c \ + gimpoperationthresholdalpha.h \ + \ + gimpoperationpointfilter.c \ + gimpoperationpointfilter.h \ + gimpoperationbrightnesscontrast.c \ + gimpoperationbrightnesscontrast.h \ + gimpoperationcolorbalance.c \ + gimpoperationcolorbalance.h \ + gimpoperationcolorize.c \ + gimpoperationcolorize.h \ + gimpoperationcurves.c \ + gimpoperationcurves.h \ + gimpoperationdesaturate.c \ + gimpoperationdesaturate.h \ + gimpoperationhuesaturation.c \ + gimpoperationhuesaturation.h \ + gimpoperationlevels.c \ + gimpoperationlevels.h \ + gimpoperationposterize.c \ + gimpoperationposterize.h \ + gimpoperationthreshold.c \ + gimpoperationthreshold.h + +libappoperations_a_built_sources = operations-enums.c +libappoperations_a_SOURCES = \ + $(libappoperations_a_built_sources) \ + $(libappoperations_a_sources) + + +# +# rules to generate built sources +# +# setup autogeneration dependencies +gen_sources = xgen-oec +CLEANFILES = $(gen_sources) +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .cc .lo .o .obj +$(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 app/operations/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu app/operations/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): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libappoperations.a: $(libappoperations_a_OBJECTS) $(libappoperations_a_DEPENDENCIES) $(EXTRA_libappoperations_a_DEPENDENCIES) + $(AM_V_at)-rm -f libappoperations.a + $(AM_V_AR)$(libappoperations_a_AR) libappoperations.a $(libappoperations_a_OBJECTS) $(libappoperations_a_LIBADD) + $(AM_V_at)$(RANLIB) libappoperations.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-operation-config.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-operations.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpbrightnesscontrastconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpcageconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpcolorbalanceconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpcurvesconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimphuesaturationconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimplevelsconfig.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationborder.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationbrightnesscontrast.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationbuffersourcevalidate.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationcagecoefcalc.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationcagetransform.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationcolorbalance.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationcolorize.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationcomposecrop.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationcurves.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationdesaturate.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationequalize.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationfillsource.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationflood.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationgradient.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationgrow.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationhistogramsink.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationhuesaturation.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationlevels.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationmaskcomponents.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationoffset.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationpointfilter.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationposterize.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationprofiletransform.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationscalarmultiply.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationsemiflatten.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationsetalpha.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationsettings.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationshrink.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationthreshold.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationthresholdalpha.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/operations-enums.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 $@ $< + +.cc.o: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $< + +.cc.obj: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(CXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.cc.lo: +@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LTCXXCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run 'make' without going through this Makefile. +# To change the values of 'make' variables: instead of editing Makefiles, +# (1) if the variable is set in 'config.status', edit 'config.status' +# (which will cause the Makefiles to be regenerated when you run 'make'); +# (2) otherwise, pass the desired values on the 'make' command line. +$(am__recursive_targets): + @fail=; \ + if $(am__make_keepgoing); then \ + failcom='fail=yes'; \ + else \ + failcom='exit 1'; \ + fi; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-recursive +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + $(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-recursive + +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-recursive + +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 + +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 + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + $(am__make_dryrun) \ + || test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(LIBRARIES) +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +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: + +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-recursive + +clean-am: clean-generic clean-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-recursive + -rm -f ./$(DEPDIR)/gimp-operation-config.Po + -rm -f ./$(DEPDIR)/gimp-operations.Po + -rm -f ./$(DEPDIR)/gimpbrightnesscontrastconfig.Po + -rm -f ./$(DEPDIR)/gimpcageconfig.Po + -rm -f ./$(DEPDIR)/gimpcolorbalanceconfig.Po + -rm -f ./$(DEPDIR)/gimpcurvesconfig.Po + -rm -f ./$(DEPDIR)/gimphuesaturationconfig.Po + -rm -f ./$(DEPDIR)/gimplevelsconfig.Po + -rm -f ./$(DEPDIR)/gimpoperationborder.Po + -rm -f ./$(DEPDIR)/gimpoperationbrightnesscontrast.Po + -rm -f ./$(DEPDIR)/gimpoperationbuffersourcevalidate.Po + -rm -f ./$(DEPDIR)/gimpoperationcagecoefcalc.Po + -rm -f ./$(DEPDIR)/gimpoperationcagetransform.Po + -rm -f ./$(DEPDIR)/gimpoperationcolorbalance.Po + -rm -f ./$(DEPDIR)/gimpoperationcolorize.Po + -rm -f ./$(DEPDIR)/gimpoperationcomposecrop.Po + -rm -f ./$(DEPDIR)/gimpoperationcurves.Po + -rm -f ./$(DEPDIR)/gimpoperationdesaturate.Po + -rm -f ./$(DEPDIR)/gimpoperationequalize.Po + -rm -f ./$(DEPDIR)/gimpoperationfillsource.Po + -rm -f ./$(DEPDIR)/gimpoperationflood.Po + -rm -f ./$(DEPDIR)/gimpoperationgradient.Po + -rm -f ./$(DEPDIR)/gimpoperationgrow.Po + -rm -f ./$(DEPDIR)/gimpoperationhistogramsink.Po + -rm -f ./$(DEPDIR)/gimpoperationhuesaturation.Po + -rm -f ./$(DEPDIR)/gimpoperationlevels.Po + -rm -f ./$(DEPDIR)/gimpoperationmaskcomponents.Po + -rm -f ./$(DEPDIR)/gimpoperationoffset.Po + -rm -f ./$(DEPDIR)/gimpoperationpointfilter.Po + -rm -f ./$(DEPDIR)/gimpoperationposterize.Po + -rm -f ./$(DEPDIR)/gimpoperationprofiletransform.Po + -rm -f ./$(DEPDIR)/gimpoperationscalarmultiply.Po + -rm -f ./$(DEPDIR)/gimpoperationsemiflatten.Po + -rm -f ./$(DEPDIR)/gimpoperationsetalpha.Po + -rm -f ./$(DEPDIR)/gimpoperationsettings.Po + -rm -f ./$(DEPDIR)/gimpoperationshrink.Po + -rm -f ./$(DEPDIR)/gimpoperationthreshold.Po + -rm -f ./$(DEPDIR)/gimpoperationthresholdalpha.Po + -rm -f ./$(DEPDIR)/operations-enums.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f ./$(DEPDIR)/gimp-operation-config.Po + -rm -f ./$(DEPDIR)/gimp-operations.Po + -rm -f ./$(DEPDIR)/gimpbrightnesscontrastconfig.Po + -rm -f ./$(DEPDIR)/gimpcageconfig.Po + -rm -f ./$(DEPDIR)/gimpcolorbalanceconfig.Po + -rm -f ./$(DEPDIR)/gimpcurvesconfig.Po + -rm -f ./$(DEPDIR)/gimphuesaturationconfig.Po + -rm -f ./$(DEPDIR)/gimplevelsconfig.Po + -rm -f ./$(DEPDIR)/gimpoperationborder.Po + -rm -f ./$(DEPDIR)/gimpoperationbrightnesscontrast.Po + -rm -f ./$(DEPDIR)/gimpoperationbuffersourcevalidate.Po + -rm -f ./$(DEPDIR)/gimpoperationcagecoefcalc.Po + -rm -f ./$(DEPDIR)/gimpoperationcagetransform.Po + -rm -f ./$(DEPDIR)/gimpoperationcolorbalance.Po + -rm -f ./$(DEPDIR)/gimpoperationcolorize.Po + -rm -f ./$(DEPDIR)/gimpoperationcomposecrop.Po + -rm -f ./$(DEPDIR)/gimpoperationcurves.Po + -rm -f ./$(DEPDIR)/gimpoperationdesaturate.Po + -rm -f ./$(DEPDIR)/gimpoperationequalize.Po + -rm -f ./$(DEPDIR)/gimpoperationfillsource.Po + -rm -f ./$(DEPDIR)/gimpoperationflood.Po + -rm -f ./$(DEPDIR)/gimpoperationgradient.Po + -rm -f ./$(DEPDIR)/gimpoperationgrow.Po + -rm -f ./$(DEPDIR)/gimpoperationhistogramsink.Po + -rm -f ./$(DEPDIR)/gimpoperationhuesaturation.Po + -rm -f ./$(DEPDIR)/gimpoperationlevels.Po + -rm -f ./$(DEPDIR)/gimpoperationmaskcomponents.Po + -rm -f ./$(DEPDIR)/gimpoperationoffset.Po + -rm -f ./$(DEPDIR)/gimpoperationpointfilter.Po + -rm -f ./$(DEPDIR)/gimpoperationposterize.Po + -rm -f ./$(DEPDIR)/gimpoperationprofiletransform.Po + -rm -f ./$(DEPDIR)/gimpoperationscalarmultiply.Po + -rm -f ./$(DEPDIR)/gimpoperationsemiflatten.Po + -rm -f ./$(DEPDIR)/gimpoperationsetalpha.Po + -rm -f ./$(DEPDIR)/gimpoperationsettings.Po + -rm -f ./$(DEPDIR)/gimpoperationshrink.Po + -rm -f ./$(DEPDIR)/gimpoperationthreshold.Po + -rm -f ./$(DEPDIR)/gimpoperationthresholdalpha.Po + -rm -f ./$(DEPDIR)/operations-enums.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(am__recursive_targets) install-am install-strip + +.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \ + am--depfiles check check-am clean clean-generic clean-libtool \ + clean-noinstLIBRARIES 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-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + installdirs-am maintainer-clean maintainer-clean-generic \ + mostlyclean mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \ + uninstall-am + +.PRECIOUS: Makefile + + +xgen-oec: $(srcdir)/operations-enums.h $(GIMP_MKENUMS) Makefile.am + $(AM_V_GEN) $(GIMP_MKENUMS) \ + --fhead "#include \"config.h\"\n#include <gio/gio.h>\n#include \"libgimpbase/gimpbase.h\"\n#include \"operations-enums.h\"\n#include \"gimp-intl.h\"" \ + --fprod "\n/* enumerations from \"@basename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static const G@Type@Value values[] =\n {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@valuenick@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n" \ + --dhead " static const Gimp@Type@Desc descs[] =\n {" \ + --dprod " { @VALUENAME@, @valuedesc@, @valuehelp@ },@if ('@valueabbrev@' ne 'NULL')@\n /* Translators: this is an abbreviated version of @valueudesc@.\n Keep it short. */\n { @VALUENAME@, @valueabbrev@, NULL },@endif@" \ + --dtail " { 0, NULL, NULL }\n };\n\n static GType type = 0;\n\n if (G_UNLIKELY (! type))\n {\n type = g_@type@_register_static (\"@EnumName@\", values);\n gimp_type_set_translation_context (type, \"@enumnick@\");\n gimp_@type@_set_value_descriptions (type, descs);\n }\n\n return type;\n}\n" \ + $< > $@ + +# copy the generated enum file back to the source directory only if it's +# changed; otherwise, only update its timestamp, so that the recipe isn't +# executed again on the next build, however, allow this to (harmlessly) fail, +# to support building from a read-only source tree. +$(srcdir)/operations-enums.c: xgen-oec + $(AM_V_GEN) if ! cmp -s $< $@; then \ + cp $< $@; \ + else \ + touch $@ 2> /dev/null \ + || true; \ + fi + +# 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/app/operations/gimp-operation-config.c b/app/operations/gimp-operation-config.c new file mode 100644 index 0000000..492cefd --- /dev/null +++ b/app/operations/gimp-operation-config.c @@ -0,0 +1,827 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "core/gimp.h" + +#include "core/gimplist.h" +#include "core/gimpparamspecs-duplicate.h" +#include "core/gimpviewable.h" + +#include "gegl/gimp-gegl-utils.h" + +#include "gimp-operation-config.h" +#include "gimpoperationsettings.h" + + +/* local function prototypes */ + +static void gimp_operation_config_config_sync (GObject *config, + const GParamSpec *gimp_pspec, + GeglNode *node); +static void gimp_operation_config_config_notify (GObject *config, + const GParamSpec *gimp_pspec, + GeglNode *node); +static void gimp_operation_config_node_notify (GeglNode *node, + const GParamSpec *gegl_pspec, + GObject *config); + +static GFile * gimp_operation_config_get_file (GType config_type); +static void gimp_operation_config_add_sep (GimpContainer *container); +static void gimp_operation_config_remove_sep (GimpContainer *container); + + +/* public functions */ + +static GHashTable * +gimp_operation_config_get_type_table (Gimp *gimp) +{ + static GHashTable *config_types = NULL; + + if (! config_types) + config_types = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + NULL); + + return config_types; +} + +static GHashTable * +gimp_operation_config_get_container_table (Gimp *gimp) +{ + static GHashTable *config_containers = NULL; + + if (! config_containers) + config_containers = g_hash_table_new_full (g_direct_hash, + g_direct_equal, + NULL, + (GDestroyNotify) g_object_unref); + + return config_containers; +} + +static GValue * +gimp_operation_config_value_new (GParamSpec *pspec) +{ + GValue *value = g_slice_new0 (GValue); + + g_value_init (value, pspec->value_type); + g_param_value_set_default (pspec, value); + + return value; +} + +static void +gimp_operation_config_value_free (GValue *value) +{ + g_value_unset (value); + g_slice_free (GValue, value); +} + +static GHashTable * +gimp_operation_config_get_properties (GObject *object) +{ + GHashTable *properties = g_object_get_data (object, "properties"); + + if (! properties) + { + properties = g_hash_table_new_full (g_str_hash, + g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) gimp_operation_config_value_free); + + g_object_set_data_full (object, "properties", properties, + (GDestroyNotify) g_hash_table_unref); + } + + return properties; +} + +static GValue * +gimp_operation_config_value_get (GObject *object, + GParamSpec *pspec) +{ + GHashTable *properties = gimp_operation_config_get_properties (object); + GValue *value; + + value = g_hash_table_lookup (properties, pspec->name); + + if (! value) + { + value = gimp_operation_config_value_new (pspec); + g_hash_table_insert (properties, g_strdup (pspec->name), value); + } + + return value; +} + +static void +gimp_operation_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GValue *val = gimp_operation_config_value_get (object, pspec); + + g_value_copy (value, val); +} + +static void +gimp_operation_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GValue *val = gimp_operation_config_value_get (object, pspec); + + g_value_copy (val, value); +} + +static void +gimp_operation_config_class_init (GObjectClass *klass, + const gchar *operation) +{ + GParamSpec **pspecs; + guint n_pspecs; + gint i; + + klass->set_property = gimp_operation_config_set_property; + klass->get_property = gimp_operation_config_get_property; + + pspecs = gegl_operation_list_properties (operation, &n_pspecs); + + for (i = 0; i < n_pspecs; i++) + { + GParamSpec *pspec = pspecs[i]; + + if ((pspec->flags & G_PARAM_READABLE) && + (pspec->flags & G_PARAM_WRITABLE) && + strcmp (pspec->name, "input") && + strcmp (pspec->name, "output")) + { + GParamSpec *copy = gimp_param_spec_duplicate (pspec); + + if (copy) + { + g_object_class_install_property (klass, i + 1, copy); + } + } + } + + g_free (pspecs); +} + +static gboolean +gimp_operation_config_equal (GimpConfig *a, + GimpConfig *b) +{ + GList *diff; + gboolean equal = TRUE; + + diff = gimp_config_diff (G_OBJECT (a), G_OBJECT (b), + GIMP_CONFIG_PARAM_SERIALIZE); + + if (G_TYPE_FROM_INSTANCE (a) == G_TYPE_FROM_INSTANCE (b)) + { + GList *list; + + for (list = diff; list; list = g_list_next (list)) + { + GParamSpec *pspec = list->data; + + if (g_type_is_a (pspec->owner_type, GIMP_TYPE_OPERATION_SETTINGS)) + { + equal = FALSE; + break; + } + } + } + else if (diff) + { + equal = FALSE; + } + + g_list_free (diff); + + return equal; +} + +static void +gimp_operation_config_config_iface_init (GimpConfigInterface *iface) +{ + iface->equal = gimp_operation_config_equal; +} + + +/* public functions */ + +void +gimp_operation_config_register (Gimp *gimp, + const gchar *operation, + GType config_type) +{ + GHashTable *config_types; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + g_return_if_fail (operation != NULL); + g_return_if_fail (g_type_is_a (config_type, GIMP_TYPE_OBJECT)); + + config_types = gimp_operation_config_get_type_table (gimp); + + g_hash_table_insert (config_types, + g_strdup (operation), + (gpointer) config_type); + } + +GType +gimp_operation_config_get_type (Gimp *gimp, + const gchar *operation, + const gchar *icon_name, + GType parent_type) +{ + GHashTable *config_types; + GType config_type; + + g_return_val_if_fail (GIMP_IS_GIMP (gimp), G_TYPE_NONE); + g_return_val_if_fail (operation != NULL, G_TYPE_NONE); + + config_types = gimp_operation_config_get_type_table (gimp); + + config_type = (GType) g_hash_table_lookup (config_types, operation); + + if (! config_type) + { + GTypeQuery query; + + g_return_val_if_fail (g_type_is_a (parent_type, GIMP_TYPE_OBJECT), + G_TYPE_NONE); + + g_type_query (parent_type, &query); + + { + GTypeInfo info = + { + query.class_size, + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gimp_operation_config_class_init, + NULL, /* class_finalize */ + operation, + query.instance_size, + 0, /* n_preallocs */ + (GInstanceInitFunc) NULL, + }; + + const GInterfaceInfo config_info = + { + (GInterfaceInitFunc) gimp_operation_config_config_iface_init, + NULL, /* interface_finalize */ + NULL /* interface_data */ + }; + + gchar *type_name = g_strdup_printf ("GimpGegl-%s-config", + operation); + + g_strcanon (type_name, + G_CSET_DIGITS "-" G_CSET_a_2_z G_CSET_A_2_Z, '-'); + + config_type = g_type_register_static (parent_type, type_name, + &info, 0); + + g_free (type_name); + + g_type_add_interface_static (config_type, GIMP_TYPE_CONFIG, + &config_info); + + if (icon_name && g_type_is_a (config_type, GIMP_TYPE_VIEWABLE)) + { + GimpViewableClass *viewable_class = g_type_class_ref (config_type); + + viewable_class->default_icon_name = g_strdup (icon_name); + + g_type_class_unref (viewable_class); + } + + gimp_operation_config_register (gimp, operation, config_type); + } + } + + return config_type; +} + +GimpContainer * +gimp_operation_config_get_container (Gimp *gimp, + GType config_type, + GCompareFunc sort_func) +{ + GHashTable *config_containers; + GimpContainer *container; + + g_return_val_if_fail (GIMP_IS_GIMP (gimp), NULL); + g_return_val_if_fail (g_type_is_a (config_type, GIMP_TYPE_OBJECT), NULL); + + config_containers = gimp_operation_config_get_container_table (gimp); + + container = g_hash_table_lookup (config_containers, (gpointer) config_type); + + if (! container) + { + container = gimp_list_new (config_type, TRUE); + gimp_list_set_sort_func (GIMP_LIST (container), sort_func); + + g_hash_table_insert (config_containers, + (gpointer) config_type, container); + + gimp_operation_config_deserialize (gimp, container, NULL); + + if (gimp_container_get_n_children (container) == 0) + { + GFile *file = gimp_operation_config_get_file (config_type); + + if (! g_file_query_exists (file, NULL)) + { + GQuark quark = g_quark_from_static_string ("compat-file"); + GFile *compat_file; + + compat_file = g_type_get_qdata (config_type, quark); + + if (compat_file) + { + if (! g_file_move (compat_file, file, 0, + NULL, NULL, NULL, NULL)) + { + gimp_operation_config_deserialize (gimp, container, + compat_file); + } + else + { + gimp_operation_config_deserialize (gimp, container, NULL); + } + } + } + + g_object_unref (file); + } + + gimp_operation_config_add_sep (container); + } + + return container; +} + +void +gimp_operation_config_serialize (Gimp *gimp, + GimpContainer *container, + GFile *file) +{ + GError *error = NULL; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + g_return_if_fail (GIMP_IS_CONTAINER (container)); + g_return_if_fail (file == NULL || G_IS_FILE (file)); + + if (file) + { + g_object_ref (file); + } + else + { + GType config_type = gimp_container_get_children_type (container); + + file = gimp_operation_config_get_file (config_type); + } + + if (gimp->be_verbose) + g_print ("Writing '%s'\n", gimp_file_get_utf8_name (file)); + + gimp_operation_config_remove_sep (container); + + if (! gimp_config_serialize_to_gfile (GIMP_CONFIG (container), + file, + "settings", + "end of settings", + NULL, &error)) + { + gimp_message_literal (gimp, NULL, GIMP_MESSAGE_ERROR, + error->message); + g_clear_error (&error); + } + + gimp_operation_config_add_sep (container); + + g_object_unref (file); +} + +void +gimp_operation_config_deserialize (Gimp *gimp, + GimpContainer *container, + GFile *file) +{ + GError *error = NULL; + + g_return_if_fail (GIMP_IS_GIMP (gimp)); + g_return_if_fail (GIMP_IS_CONTAINER (container)); + g_return_if_fail (file == NULL || G_IS_FILE (file)); + + if (file) + { + g_object_ref (file); + } + else + { + GType config_type = gimp_container_get_children_type (container); + + file = gimp_operation_config_get_file (config_type); + } + + if (gimp->be_verbose) + g_print ("Parsing '%s'\n", gimp_file_get_utf8_name (file)); + + if (! gimp_config_deserialize_gfile (GIMP_CONFIG (container), + file, + NULL, &error)) + { + if (error->code != GIMP_CONFIG_ERROR_OPEN_ENOENT) + gimp_message_literal (gimp, NULL, GIMP_MESSAGE_ERROR, + error->message); + + g_clear_error (&error); + } + + g_object_unref (file); +} + +void +gimp_operation_config_sync_node (GObject *config, + GeglNode *node) +{ + GParamSpec **pspecs; + gchar *operation; + guint n_pspecs; + gint i; + + g_return_if_fail (G_IS_OBJECT (config)); + g_return_if_fail (GEGL_IS_NODE (node)); + + gegl_node_get (node, + "operation", &operation, + NULL); + + g_return_if_fail (operation != NULL); + + pspecs = gegl_operation_list_properties (operation, &n_pspecs); + g_free (operation); + + for (i = 0; i < n_pspecs; i++) + { + GParamSpec *gegl_pspec = pspecs[i]; + GParamSpec *gimp_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), + gegl_pspec->name); + + /* if the operation has an object property of the config's + * type, use the config object directly + */ + if (G_IS_PARAM_SPEC_OBJECT (gegl_pspec) && + gegl_pspec->value_type == G_TYPE_FROM_INSTANCE (config)) + { + gegl_node_set (node, + gegl_pspec->name, config, + NULL); + } + else if (gimp_pspec) + { + GValue value = G_VALUE_INIT; + + g_value_init (&value, gimp_pspec->value_type); + + g_object_get_property (G_OBJECT (config), gimp_pspec->name, + &value); + + if (GEGL_IS_PARAM_SPEC_COLOR (gegl_pspec)) + { + GimpRGB gimp_color; + GeglColor *gegl_color; + + gimp_value_get_rgb (&value, &gimp_color); + g_value_unset (&value); + + gegl_color = gimp_gegl_color_new (&gimp_color); + + g_value_init (&value, gegl_pspec->value_type); + g_value_take_object (&value, gegl_color); + } + + gegl_node_set_property (node, gegl_pspec->name, + &value); + + g_value_unset (&value); + } + } + + g_free (pspecs); +} + +void +gimp_operation_config_connect_node (GObject *config, + GeglNode *node) +{ + GParamSpec **pspecs; + gchar *operation; + guint n_pspecs; + gint i; + + g_return_if_fail (G_IS_OBJECT (config)); + g_return_if_fail (GEGL_IS_NODE (node)); + + gegl_node_get (node, + "operation", &operation, + NULL); + + g_return_if_fail (operation != NULL); + + pspecs = gegl_operation_list_properties (operation, &n_pspecs); + g_free (operation); + + for (i = 0; i < n_pspecs; i++) + { + GParamSpec *pspec = pspecs[i]; + + /* if the operation has an object property of the config's + * type, connect it to a special callback and done + */ + if (G_IS_PARAM_SPEC_OBJECT (pspec) && + pspec->value_type == G_TYPE_FROM_INSTANCE (config)) + { + g_signal_connect_object (config, "notify", + G_CALLBACK (gimp_operation_config_config_sync), + node, 0); + g_free (pspecs); + return; + } + } + + for (i = 0; i < n_pspecs; i++) + { + GParamSpec *gegl_pspec = pspecs[i]; + GParamSpec *gimp_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), + gegl_pspec->name); + + if (gimp_pspec) + { + gchar *notify_name = g_strconcat ("notify::", gimp_pspec->name, NULL); + + g_signal_connect_object (config, notify_name, + G_CALLBACK (gimp_operation_config_config_notify), + node, 0); + + g_signal_connect_object (node, notify_name, + G_CALLBACK (gimp_operation_config_node_notify), + config, 0); + + g_free (notify_name); + } + } + + g_free (pspecs); +} + +GParamSpec ** +gimp_operation_config_list_properties (GObject *config, + GType owner_type, + GParamFlags flags, + guint *n_pspecs) +{ + GParamSpec **param_specs; + guint n_param_specs; + gint i, j; + + g_return_val_if_fail (G_IS_OBJECT (config), NULL); + + param_specs = g_object_class_list_properties (G_OBJECT_GET_CLASS (config), + &n_param_specs); + + for (i = 0, j = 0; i < n_param_specs; i++) + { + GParamSpec *pspec = param_specs[i]; + + /* ignore properties of parent classes of owner_type */ + if (! g_type_is_a (pspec->owner_type, owner_type)) + continue; + + if (flags && ((pspec->flags & flags) != flags)) + continue; + + if (gimp_gegl_param_spec_has_key (pspec, "role", "output-extent")) + continue; + + param_specs[j] = param_specs[i]; + j++; + } + + if (n_pspecs) + *n_pspecs = j; + + if (j == 0) + { + g_free (param_specs); + param_specs = NULL; + } + + return param_specs; +} + + +/* private functions */ + +static void +gimp_operation_config_config_sync (GObject *config, + const GParamSpec *gimp_pspec, + GeglNode *node) +{ + gimp_operation_config_sync_node (config, node); +} + +static void +gimp_operation_config_config_notify (GObject *config, + const GParamSpec *gimp_pspec, + GeglNode *node) +{ + GParamSpec *gegl_pspec = gegl_node_find_property (node, gimp_pspec->name); + + if (gegl_pspec) + { + GValue value = G_VALUE_INIT; + gulong handler; + + g_value_init (&value, gimp_pspec->value_type); + g_object_get_property (config, gimp_pspec->name, &value); + + if (GEGL_IS_PARAM_SPEC_COLOR (gegl_pspec)) + { + GimpRGB gimp_color; + GeglColor *gegl_color; + + gimp_value_get_rgb (&value, &gimp_color); + g_value_unset (&value); + + gegl_color = gimp_gegl_color_new (&gimp_color); + + g_value_init (&value, gegl_pspec->value_type); + g_value_take_object (&value, gegl_color); + } + + handler = g_signal_handler_find (node, + G_SIGNAL_MATCH_DETAIL | + G_SIGNAL_MATCH_FUNC | + G_SIGNAL_MATCH_DATA, + 0, + g_quark_from_string (gegl_pspec->name), + NULL, + gimp_operation_config_node_notify, + config); + + if (handler) + g_signal_handler_block (node, handler); + + gegl_node_set_property (node, gegl_pspec->name, &value); + g_value_unset (&value); + + if (handler) + g_signal_handler_unblock (node, handler); + + } +} + +static void +gimp_operation_config_node_notify (GeglNode *node, + const GParamSpec *gegl_pspec, + GObject *config) +{ + GParamSpec *gimp_pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), + gegl_pspec->name); + + if (gimp_pspec) + { + GValue value = G_VALUE_INIT; + gulong handler; + + g_value_init (&value, gegl_pspec->value_type); + gegl_node_get_property (node, gegl_pspec->name, &value); + + if (GEGL_IS_PARAM_SPEC_COLOR (gegl_pspec)) + { + GeglColor *gegl_color; + GimpRGB gimp_color; + + gegl_color = g_value_dup_object (&value); + g_value_unset (&value); + + if (gegl_color) + { + gegl_color_get_rgba (gegl_color, + &gimp_color.r, + &gimp_color.g, + &gimp_color.b, + &gimp_color.a); + g_object_unref (gegl_color); + } + else + { + gimp_rgba_set (&gimp_color, 0.0, 0.0, 0.0, 1.0); + } + + g_value_init (&value, gimp_pspec->value_type); + gimp_value_set_rgb (&value, &gimp_color); + } + + handler = g_signal_handler_find (config, + G_SIGNAL_MATCH_DETAIL | + G_SIGNAL_MATCH_FUNC | + G_SIGNAL_MATCH_DATA, + 0, + g_quark_from_string (gimp_pspec->name), + NULL, + gimp_operation_config_config_notify, + node); + + if (handler) + g_signal_handler_block (config, handler); + + g_object_set_property (config, gimp_pspec->name, &value); + g_value_unset (&value); + + if (handler) + g_signal_handler_unblock (config, handler); + } +} + +static GFile * +gimp_operation_config_get_file (GType config_type) +{ + GFile *file; + gchar *basename; + + basename = g_strconcat (g_type_name (config_type), ".settings", NULL); + file = gimp_directory_file ("filters", basename, NULL); + g_free (basename); + + return file; +} + +static void +gimp_operation_config_add_sep (GimpContainer *container) +{ + GimpObject *sep = g_object_get_data (G_OBJECT (container), "separator"); + + if (! sep) + { + sep = g_object_new (gimp_container_get_children_type (container), + NULL); + + gimp_container_add (container, sep); + g_object_unref (sep); + + g_object_set_data (G_OBJECT (container), "separator", sep); + } +} + +static void +gimp_operation_config_remove_sep (GimpContainer *container) +{ + GimpObject *sep = g_object_get_data (G_OBJECT (container), "separator"); + + if (sep) + { + gimp_container_remove (container, sep); + + g_object_set_data (G_OBJECT (container), "separator", NULL); + } +} diff --git a/app/operations/gimp-operation-config.h b/app/operations/gimp-operation-config.h new file mode 100644 index 0000000..5f920e0 --- /dev/null +++ b/app/operations/gimp-operation-config.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_CONFIG_H__ +#define __GIMP_OPERATION_CONFIG_H__ + + +void gimp_operation_config_register (Gimp *gimp, + const gchar *operation, + GType config_type); + +GType gimp_operation_config_get_type (Gimp *gimp, + const gchar *operation, + const gchar *icon_name, + GType parent_type); + +GimpContainer * gimp_operation_config_get_container (Gimp *gimp, + GType config_type, + GCompareFunc sort_func); + +void gimp_operation_config_serialize (Gimp *gimp, + GimpContainer *container, + GFile *file); +void gimp_operation_config_deserialize (Gimp *gimp, + GimpContainer *container, + GFile *file); + +void gimp_operation_config_sync_node (GObject *config, + GeglNode *node); +void gimp_operation_config_connect_node (GObject *config, + GeglNode *node); + +GParamSpec ** gimp_operation_config_list_properties (GObject *config, + GType owner_type, + GParamFlags flags, + guint *n_pspecs); + + +#endif /* __GIMP_OPERATION_CONFIG_H__ */ diff --git a/app/operations/gimp-operations.c b/app/operations/gimp-operations.c new file mode 100644 index 0000000..7cb30fd --- /dev/null +++ b/app/operations/gimp-operations.c @@ -0,0 +1,225 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-operations.c + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpbase/gimpbase.h" + +#include "operations-types.h" + +#include "core/gimp.h" + +#include "gimp-operations.h" + +#include "gimpoperationborder.h" +#include "gimpoperationbuffersourcevalidate.h" +#include "gimpoperationcagecoefcalc.h" +#include "gimpoperationcagetransform.h" +#include "gimpoperationcomposecrop.h" +#include "gimpoperationequalize.h" +#include "gimpoperationfillsource.h" +#include "gimpoperationflood.h" +#include "gimpoperationgradient.h" +#include "gimpoperationgrow.h" +#include "gimpoperationhistogramsink.h" +#include "gimpoperationmaskcomponents.h" +#include "gimpoperationoffset.h" +#include "gimpoperationprofiletransform.h" +#include "gimpoperationscalarmultiply.h" +#include "gimpoperationsemiflatten.h" +#include "gimpoperationsetalpha.h" +#include "gimpoperationshrink.h" +#include "gimpoperationthresholdalpha.h" + +#include "gimpoperationbrightnesscontrast.h" +#include "gimpoperationcolorbalance.h" +#include "gimpoperationcolorize.h" +#include "gimpoperationcurves.h" +#include "gimpoperationdesaturate.h" +#include "gimpoperationhuesaturation.h" +#include "gimpoperationlevels.h" +#include "gimpoperationposterize.h" +#include "gimpoperationthreshold.h" + +#include "gimp-operation-config.h" +#include "gimpbrightnesscontrastconfig.h" +#include "gimpcolorbalanceconfig.h" +#include "gimpcurvesconfig.h" +#include "gimphuesaturationconfig.h" +#include "gimplevelsconfig.h" + +#include "layer-modes-legacy/gimpoperationadditionlegacy.h" +#include "layer-modes-legacy/gimpoperationburnlegacy.h" +#include "layer-modes-legacy/gimpoperationdarkenonlylegacy.h" +#include "layer-modes-legacy/gimpoperationdifferencelegacy.h" +#include "layer-modes-legacy/gimpoperationdividelegacy.h" +#include "layer-modes-legacy/gimpoperationdodgelegacy.h" +#include "layer-modes-legacy/gimpoperationgrainextractlegacy.h" +#include "layer-modes-legacy/gimpoperationgrainmergelegacy.h" +#include "layer-modes-legacy/gimpoperationhardlightlegacy.h" +#include "layer-modes-legacy/gimpoperationhslcolorlegacy.h" +#include "layer-modes-legacy/gimpoperationhsvhuelegacy.h" +#include "layer-modes-legacy/gimpoperationhsvsaturationlegacy.h" +#include "layer-modes-legacy/gimpoperationhsvvaluelegacy.h" +#include "layer-modes-legacy/gimpoperationlightenonlylegacy.h" +#include "layer-modes-legacy/gimpoperationmultiplylegacy.h" +#include "layer-modes-legacy/gimpoperationscreenlegacy.h" +#include "layer-modes-legacy/gimpoperationsoftlightlegacy.h" +#include "layer-modes-legacy/gimpoperationsubtractlegacy.h" + +#include "layer-modes/gimp-layer-modes.h" +#include "layer-modes/gimpoperationantierase.h" +#include "layer-modes/gimpoperationbehind.h" +#include "layer-modes/gimpoperationdissolve.h" +#include "layer-modes/gimpoperationerase.h" +#include "layer-modes/gimpoperationmerge.h" +#include "layer-modes/gimpoperationnormal.h" +#include "layer-modes/gimpoperationpassthrough.h" +#include "layer-modes/gimpoperationreplace.h" +#include "layer-modes/gimpoperationsplit.h" + + +static void +set_compat_file (GType type, + const gchar *basename) +{ + GFile *file = gimp_directory_file ("tool-options", basename, NULL); + GQuark quark = g_quark_from_static_string ("compat-file"); + + g_type_set_qdata (type, quark, file); +} + +static void +set_settings_folder (GType type, + const gchar *basename) +{ + GFile *file = gimp_directory_file (basename, NULL); + GQuark quark = g_quark_from_static_string ("settings-folder"); + + g_type_set_qdata (type, quark, file); +} + +void +gimp_operations_init (Gimp *gimp) +{ + g_return_if_fail (GIMP_IS_GIMP (gimp)); + + gimp_layer_modes_init (); + + g_type_class_ref (GIMP_TYPE_OPERATION_BORDER); + g_type_class_ref (GIMP_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE); + g_type_class_ref (GIMP_TYPE_OPERATION_CAGE_COEF_CALC); + g_type_class_ref (GIMP_TYPE_OPERATION_CAGE_TRANSFORM); + g_type_class_ref (GIMP_TYPE_OPERATION_COMPOSE_CROP); + g_type_class_ref (GIMP_TYPE_OPERATION_EQUALIZE); + g_type_class_ref (GIMP_TYPE_OPERATION_FILL_SOURCE); + g_type_class_ref (GIMP_TYPE_OPERATION_FLOOD); + g_type_class_ref (GIMP_TYPE_OPERATION_GRADIENT); + g_type_class_ref (GIMP_TYPE_OPERATION_GROW); + g_type_class_ref (GIMP_TYPE_OPERATION_HISTOGRAM_SINK); + g_type_class_ref (GIMP_TYPE_OPERATION_MASK_COMPONENTS); + g_type_class_ref (GIMP_TYPE_OPERATION_OFFSET); + g_type_class_ref (GIMP_TYPE_OPERATION_PROFILE_TRANSFORM); + g_type_class_ref (GIMP_TYPE_OPERATION_SCALAR_MULTIPLY); + g_type_class_ref (GIMP_TYPE_OPERATION_SEMI_FLATTEN); + g_type_class_ref (GIMP_TYPE_OPERATION_SET_ALPHA); + g_type_class_ref (GIMP_TYPE_OPERATION_SHRINK); + g_type_class_ref (GIMP_TYPE_OPERATION_THRESHOLD_ALPHA); + + g_type_class_ref (GIMP_TYPE_OPERATION_BRIGHTNESS_CONTRAST); + g_type_class_ref (GIMP_TYPE_OPERATION_COLOR_BALANCE); + g_type_class_ref (GIMP_TYPE_OPERATION_COLORIZE); + g_type_class_ref (GIMP_TYPE_OPERATION_CURVES); + g_type_class_ref (GIMP_TYPE_OPERATION_DESATURATE); + g_type_class_ref (GIMP_TYPE_OPERATION_HUE_SATURATION); + g_type_class_ref (GIMP_TYPE_OPERATION_LEVELS); + g_type_class_ref (GIMP_TYPE_OPERATION_POSTERIZE); + g_type_class_ref (GIMP_TYPE_OPERATION_THRESHOLD); + + g_type_class_ref (GIMP_TYPE_OPERATION_NORMAL); + g_type_class_ref (GIMP_TYPE_OPERATION_DISSOLVE); + g_type_class_ref (GIMP_TYPE_OPERATION_BEHIND); + g_type_class_ref (GIMP_TYPE_OPERATION_MULTIPLY_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_SCREEN_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_DIFFERENCE_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_ADDITION_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_SUBTRACT_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_DARKEN_ONLY_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_HSV_HUE_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_HSV_SATURATION_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_HSL_COLOR_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_HSV_VALUE_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_DIVIDE_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_DODGE_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_BURN_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_HARDLIGHT_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_SOFTLIGHT_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_GRAIN_MERGE_LEGACY); + g_type_class_ref (GIMP_TYPE_OPERATION_ERASE); + g_type_class_ref (GIMP_TYPE_OPERATION_MERGE); + g_type_class_ref (GIMP_TYPE_OPERATION_SPLIT); + g_type_class_ref (GIMP_TYPE_OPERATION_PASS_THROUGH); + g_type_class_ref (GIMP_TYPE_OPERATION_REPLACE); + g_type_class_ref (GIMP_TYPE_OPERATION_ANTI_ERASE); + + gimp_operation_config_register (gimp, + "gimp:brightness-contrast", + GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG); + set_compat_file (GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG, + "gimp-brightness-contrast-tool.settings"); + set_settings_folder (GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG, + "brightness-contrast"); + + gimp_operation_config_register (gimp, + "gimp:color-balance", + GIMP_TYPE_COLOR_BALANCE_CONFIG); + set_compat_file (GIMP_TYPE_COLOR_BALANCE_CONFIG, + "gimp-color-balance-tool.settings"); + set_settings_folder (GIMP_TYPE_COLOR_BALANCE_CONFIG, + "color-balance"); + + gimp_operation_config_register (gimp, + "gimp:curves", + GIMP_TYPE_CURVES_CONFIG); + set_compat_file (GIMP_TYPE_CURVES_CONFIG, + "gimp-curves-tool.settings"); + set_settings_folder (GIMP_TYPE_CURVES_CONFIG, + "curves"); + + gimp_operation_config_register (gimp, + "gimp:hue-saturation", + GIMP_TYPE_HUE_SATURATION_CONFIG); + set_compat_file (GIMP_TYPE_HUE_SATURATION_CONFIG, + "gimp-hue-saturation-tool.settings"); + set_settings_folder (GIMP_TYPE_HUE_SATURATION_CONFIG, + "hue-saturation"); + + gimp_operation_config_register (gimp, + "gimp:levels", + GIMP_TYPE_LEVELS_CONFIG); + set_compat_file (GIMP_TYPE_LEVELS_CONFIG, + "gimp-levels-tool.settings"); + set_settings_folder (GIMP_TYPE_LEVELS_CONFIG, + "levels"); +} diff --git a/app/operations/gimp-operations.h b/app/operations/gimp-operations.h new file mode 100644 index 0000000..6f2b222 --- /dev/null +++ b/app/operations/gimp-operations.h @@ -0,0 +1,27 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-operations.h + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATIONS_H__ +#define __GIMP_OPERATIONS_H__ + + +void gimp_operations_init (Gimp *gimp); + + +#endif /* __GIMP_OPERATIONS_H__ */ diff --git a/app/operations/gimpbrightnesscontrastconfig.c b/app/operations/gimpbrightnesscontrastconfig.c new file mode 100644 index 0000000..75ee36a --- /dev/null +++ b/app/operations/gimpbrightnesscontrastconfig.c @@ -0,0 +1,248 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpbrightnesscontrastconfig.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpmath/gimpmath.h" +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "gimpbrightnesscontrastconfig.h" +#include "gimplevelsconfig.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_BRIGHTNESS, + PROP_CONTRAST +}; + + +static void gimp_brightness_contrast_config_iface_init (GimpConfigInterface *iface); + +static void gimp_brightness_contrast_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_brightness_contrast_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gboolean gimp_brightness_contrast_config_equal (GimpConfig *a, + GimpConfig *b); + + +G_DEFINE_TYPE_WITH_CODE (GimpBrightnessContrastConfig, + gimp_brightness_contrast_config, + GIMP_TYPE_OPERATION_SETTINGS, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, + gimp_brightness_contrast_config_iface_init)) + +#define parent_class gimp_brightness_contrast_config_parent_class + + +static void +gimp_brightness_contrast_config_class_init (GimpBrightnessContrastConfigClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + + object_class->set_property = gimp_brightness_contrast_config_set_property; + object_class->get_property = gimp_brightness_contrast_config_get_property; + + viewable_class->default_icon_name = "gimp-tool-brightness-contrast"; + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_BRIGHTNESS, + "brightness", + _("Brightness"), + _("Brightness"), + -1.0, 1.0, 0.0, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_CONTRAST, + "contrast", + _("Contrast"), + _("Contrast"), + -1.0, 1.0, 0.0, 0); +} + +static void +gimp_brightness_contrast_config_iface_init (GimpConfigInterface *iface) +{ + iface->equal = gimp_brightness_contrast_config_equal; +} + +static void +gimp_brightness_contrast_config_init (GimpBrightnessContrastConfig *self) +{ +} + +static void +gimp_brightness_contrast_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpBrightnessContrastConfig *self = GIMP_BRIGHTNESS_CONTRAST_CONFIG (object); + + switch (property_id) + { + case PROP_BRIGHTNESS: + g_value_set_double (value, self->brightness); + break; + + case PROP_CONTRAST: + g_value_set_double (value, self->contrast); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_brightness_contrast_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpBrightnessContrastConfig *self = GIMP_BRIGHTNESS_CONTRAST_CONFIG (object); + + switch (property_id) + { + case PROP_BRIGHTNESS: + self->brightness = g_value_get_double (value); + break; + + case PROP_CONTRAST: + self->contrast = g_value_get_double (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gboolean +gimp_brightness_contrast_config_equal (GimpConfig *a, + GimpConfig *b) +{ + GimpBrightnessContrastConfig *config_a = GIMP_BRIGHTNESS_CONTRAST_CONFIG (a); + GimpBrightnessContrastConfig *config_b = GIMP_BRIGHTNESS_CONTRAST_CONFIG (b); + + if (! gimp_operation_settings_config_equal_base (a, b) || + config_a->brightness != config_b->brightness || + config_a->contrast != config_b->contrast) + { + return FALSE; + } + + return TRUE; +} + + +/* public functions */ + +GimpLevelsConfig * +gimp_brightness_contrast_config_to_levels_config (GimpBrightnessContrastConfig *config) +{ + GimpLevelsConfig *levels; + gdouble brightness; + gdouble slant; + gdouble value; + + g_return_val_if_fail (GIMP_IS_BRIGHTNESS_CONTRAST_CONFIG (config), NULL); + + levels = g_object_new (GIMP_TYPE_LEVELS_CONFIG, NULL); + + gimp_operation_settings_config_copy_base (GIMP_CONFIG (config), + GIMP_CONFIG (levels), + 0); + + brightness = config->brightness / 2.0; + slant = tan ((config->contrast + 1) * G_PI_4); + + if (config->brightness >= 0) + { + value = -0.5 * slant + brightness * slant + 0.5; + + if (value < 0.0) + { + value = 0.0; + + /* this slightly convoluted math follows by inverting the + * calculation of the brightness/contrast LUT in base/lut-funcs.h */ + + levels->low_input[GIMP_HISTOGRAM_VALUE] = + (- brightness * slant + 0.5 * slant - 0.5) / (slant - brightness * slant); + } + + levels->low_output[GIMP_HISTOGRAM_VALUE] = value; + + value = 0.5 * slant + 0.5; + + if (value > 1.0) + { + value = 1.0; + + levels->high_input[GIMP_HISTOGRAM_VALUE] = + (- brightness * slant + 0.5 * slant + 0.5) / (slant - brightness * slant); + } + + levels->high_output[GIMP_HISTOGRAM_VALUE] = value; + } + else + { + value = 0.5 - 0.5 * slant; + + if (value < 0.0) + { + value = 0.0; + + levels->low_input[GIMP_HISTOGRAM_VALUE] = + (0.5 * slant - 0.5) / (slant + brightness * slant); + } + + levels->low_output[GIMP_HISTOGRAM_VALUE] = value; + + value = slant * brightness + slant * 0.5 + 0.5; + + if (value > 1.0) + { + value = 1.0; + + levels->high_input[GIMP_HISTOGRAM_VALUE] = + (0.5 * slant + 0.5) / (slant + brightness * slant); + } + + levels->high_output[GIMP_HISTOGRAM_VALUE] = value; + } + + return levels; +} diff --git a/app/operations/gimpbrightnesscontrastconfig.h b/app/operations/gimpbrightnesscontrastconfig.h new file mode 100644 index 0000000..bab1a03 --- /dev/null +++ b/app/operations/gimpbrightnesscontrastconfig.h @@ -0,0 +1,58 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpbrightnesscontrastconfig.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_BRIGHTNESS_CONTRAST_CONFIG_H__ +#define __GIMP_BRIGHTNESS_CONTRAST_CONFIG_H__ + + +#include "gimpoperationsettings.h" + + +#define GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG (gimp_brightness_contrast_config_get_type ()) +#define GIMP_BRIGHTNESS_CONTRAST_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG, GimpBrightnessContrastConfig)) +#define GIMP_BRIGHTNESS_CONTRAST_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG, GimpBrightnessContrastConfigClass)) +#define GIMP_IS_BRIGHTNESS_CONTRAST_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG)) +#define GIMP_IS_BRIGHTNESS_CONTRAST_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG)) +#define GIMP_BRIGHTNESS_CONTRAST_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG, GimpBrightnessContrastConfigClass)) + + +typedef struct _GimpBrightnessContrastConfigClass GimpBrightnessContrastConfigClass; + +struct _GimpBrightnessContrastConfig +{ + GimpOperationSettings parent_instance; + + gdouble brightness; + gdouble contrast; +}; + +struct _GimpBrightnessContrastConfigClass +{ + GimpOperationSettingsClass parent_class; +}; + + +GType gimp_brightness_contrast_config_get_type (void) G_GNUC_CONST; + +GimpLevelsConfig * +gimp_brightness_contrast_config_to_levels_config (GimpBrightnessContrastConfig *config); + + +#endif /* __GIMP_BRIGHTNESS_CONTRAST_CONFIG_H__ */ diff --git a/app/operations/gimpcageconfig.c b/app/operations/gimpcageconfig.c new file mode 100644 index 0000000..17548cf --- /dev/null +++ b/app/operations/gimpcageconfig.c @@ -0,0 +1,832 @@ +/* GIMP - The GNU Image Manipulation Program + * + * gimpcageconfig.c + * Copyright (C) 2010 Michael Muré <batolettre@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpconfig/gimpconfig.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpbase/gimpbase.h" + +#include "operations-types.h" + +#include "gimpcageconfig.h" + + +/*#define DEBUG_CAGE */ + +/* This DELTA is aimed to not have handle on exact pixel during computation, + * to avoid particular case. It shouldn't be so useful, but it's a double + * safety. */ +#define DELTA 0.010309278351 + + +static void gimp_cage_config_finalize (GObject *object); +static void gimp_cage_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_cage_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_cage_config_compute_scaling_factor (GimpCageConfig *gcc); +static void gimp_cage_config_compute_edges_normal (GimpCageConfig *gcc); + + +G_DEFINE_TYPE_WITH_CODE (GimpCageConfig, gimp_cage_config, + GIMP_TYPE_OPERATION_SETTINGS, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, + NULL)) + +#define parent_class gimp_cage_config_parent_class + +#ifdef DEBUG_CAGE +static void +print_cage (GimpCageConfig *gcc) +{ + gint i; + GeglRectangle bounding_box; + GimpCagePoint *point; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + bounding_box = gimp_cage_config_get_bounding_box (gcc); + + for (i = 0; i < gcc->cage_points->len; i++) + { + point = &g_array_index (gcc->cage_points, GimpCagePoint, i); + g_printerr ("cgx: %.0f cgy: %.0f cvdx: %.0f cvdy: %.0f sf: %.2f normx: %.2f normy: %.2f %s\n", + point->src_point.x + ((gcc->cage_mode==GIMP_CAGE_MODE_CAGE_CHANGE)?gcc->displacement_x:0), + point->src_point.y + ((gcc->cage_mode==GIMP_CAGE_MODE_CAGE_CHANGE)?gcc->displacement_y:0), + point->dest_point.x + ((gcc->cage_mode==GIMP_CAGE_MODE_DEFORM)?gcc->displacement_x:0), + point->dest_point.y + ((gcc->cage_mode==GIMP_CAGE_MODE_DEFORM)?gcc->displacement_y:0), + point->edge_scaling_factor, + point->edge_normal.x, + point->edge_normal.y, + ((point->selected) ? "S" : "NS")); + } + + g_printerr ("bounding box: x: %d y: %d width: %d height: %d\n", bounding_box.x, bounding_box.y, bounding_box.width, bounding_box.height); + g_printerr ("disp x: %f disp y: %f\n", gcc->displacement_x, gcc->displacement_y); + g_printerr ("done\n"); +} +#endif + +static void +gimp_cage_config_class_init (GimpCageConfigClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gimp_cage_config_set_property; + object_class->get_property = gimp_cage_config_get_property; + + object_class->finalize = gimp_cage_config_finalize; +} + +static void +gimp_cage_config_init (GimpCageConfig *self) +{ + /*pre-allocation for 50 vertices for the cage.*/ + self->cage_points = g_array_sized_new (FALSE, FALSE, sizeof(GimpCagePoint), 50); +} + +static void +gimp_cage_config_finalize (GObject *object) +{ + GimpCageConfig *gcc = GIMP_CAGE_CONFIG (object); + + g_array_free (gcc->cage_points, TRUE); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_cage_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_cage_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (property_id) + { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +/** + * gimp_cage_config_get_n_points: + * @gcc: the cage config + * + * Returns: the number of points of the cage + */ +guint +gimp_cage_config_get_n_points (GimpCageConfig *gcc) +{ + return gcc->cage_points->len; +} + +/** + * gimp_cage_config_add_cage_point: + * @gcc: the cage config + * @x: x value of the new point + * @y: y value of the new point + * + * Add a new point in the last index of the polygon of the cage. + * Point is added in both source and destination cage + */ +void +gimp_cage_config_add_cage_point (GimpCageConfig *gcc, + gdouble x, + gdouble y) +{ + gimp_cage_config_insert_cage_point (gcc, gcc->cage_points->len, x, y); +} + +/** + * gimp_cage_config_insert_cage_point: + * @gcc: the cage config + * @point_number: index where the point will be inserted + * @x: x value of the new point + * @y: y value of the new point + * + * Insert a new point in the polygon of the cage at the given index. + * Point is added in both source and destination cage + */ +void +gimp_cage_config_insert_cage_point (GimpCageConfig *gcc, + gint point_number, + gdouble x, + gdouble y) +{ + GimpCagePoint point; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + g_return_if_fail (point_number <= gcc->cage_points->len); + g_return_if_fail (point_number >= 0); + + point.src_point.x = x + DELTA; + point.src_point.y = y + DELTA; + + point.dest_point.x = x + DELTA; + point.dest_point.y = y + DELTA; + + g_array_insert_val (gcc->cage_points, point_number, point); + + gimp_cage_config_compute_scaling_factor (gcc); + gimp_cage_config_compute_edges_normal (gcc); +} + +/** + * gimp_cage_config_remove_last_cage_point: + * @gcc: the cage config + * + * Remove the last point of the cage, in both source and destination cage + */ +void +gimp_cage_config_remove_last_cage_point (GimpCageConfig *gcc) +{ + gimp_cage_config_remove_cage_point (gcc, gcc->cage_points->len - 1); +} + +/** + * gimp_cage_config_remove_cage_point: + * @gcc: the cage config + * @point_number: the index of the point to remove + * + * Remove the given point from the cage + */ +void +gimp_cage_config_remove_cage_point (GimpCageConfig *gcc, + gint point_number) +{ + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + g_return_if_fail (point_number < gcc->cage_points->len); + g_return_if_fail (point_number >= 0); + + if (gcc->cage_points->len > 0) + g_array_remove_index (gcc->cage_points, gcc->cage_points->len - 1); + + gimp_cage_config_compute_scaling_factor (gcc); + gimp_cage_config_compute_edges_normal (gcc); +} + +/** + * gimp_cage_config_remove_selected_points: + * @gcc: the cage config + * + * Remove all the selected points from the cage + */ +void +gimp_cage_config_remove_selected_points (GimpCageConfig *gcc) +{ + gint i; + GimpCagePoint *point; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + for (i = 0; i < gcc->cage_points->len; i++) + { + point = &g_array_index (gcc->cage_points, GimpCagePoint, i); + + if (point->selected) + { + g_array_remove_index (gcc->cage_points, i); + i--; + } + } + + gimp_cage_config_compute_scaling_factor (gcc); + gimp_cage_config_compute_edges_normal (gcc); +} + +/** + * gimp_cage_config_get_point_coordinate: + * @gcc: the cage config + * @mode: the actual mode of the cage, GIMP_CAGE_MODE_CAGE_CHANGE or GIMP_CAGE_MODE_DEFORM + * @point_number: the index of the point to return + * + * Returns: the real position of the given point, as a GimpVector2 + */ +GimpVector2 +gimp_cage_config_get_point_coordinate (GimpCageConfig *gcc, + GimpCageMode mode, + gint point_number) +{ + GimpVector2 result = { 0.0, 0.0 }; + GimpCagePoint *point; + + g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), result); + g_return_val_if_fail (point_number < gcc->cage_points->len, result); + g_return_val_if_fail (point_number >= 0, result); + + point = &g_array_index (gcc->cage_points, GimpCagePoint, point_number); + + if (point->selected) + { + if (mode == GIMP_CAGE_MODE_CAGE_CHANGE) + { + result.x = point->src_point.x + gcc->displacement_x; + result.y = point->src_point.y + gcc->displacement_y; + } + else + { + result.x = point->dest_point.x + gcc->displacement_x; + result.y = point->dest_point.y + gcc->displacement_y; + } + } + else + { + if (mode == GIMP_CAGE_MODE_CAGE_CHANGE) + { + result.x = point->src_point.x; + result.y = point->src_point.y; + } + else + { + result.x = point->dest_point.x; + result.y = point->dest_point.y; + } + } + + return result; +} + +/** + * gimp_cage_config_add_displacement: + * @gcc: the cage config + * @mode: the actual mode of the cage, GIMP_CAGE_MODE_CAGE_CHANGE or GIMP_CAGE_MODE_DEFORM + * @point_number: the point of the cage to move + * @x: x displacement value + * @y: y displacement value + * + * Add a displacement for all selected points of the cage. + * This displacement need to be committed to become effective. + */ +void +gimp_cage_config_add_displacement (GimpCageConfig *gcc, + GimpCageMode mode, + gdouble x, + gdouble y) +{ + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + gcc->cage_mode = mode; + gcc->displacement_x = x; + gcc->displacement_y = y; + + #ifdef DEBUG_CAGE + print_cage (gcc); + #endif +} + +/** + * gimp_cage_config_commit_displacement: + * @gcc: the cage config + * + * Apply the displacement to the cage + */ +void +gimp_cage_config_commit_displacement (GimpCageConfig *gcc) +{ + gint i; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + for (i = 0; i < gcc->cage_points->len; i++) + { + GimpCagePoint *point; + point = &g_array_index (gcc->cage_points, GimpCagePoint, i); + + if (point->selected) + { + if (gcc->cage_mode == GIMP_CAGE_MODE_CAGE_CHANGE) + { + point->src_point.x += gcc->displacement_x; + point->src_point.y += gcc->displacement_y; + point->dest_point.x += gcc->displacement_x; + point->dest_point.y += gcc->displacement_y; + } + else + { + point->dest_point.x += gcc->displacement_x; + point->dest_point.y += gcc->displacement_y; + } + } + } + + gimp_cage_config_compute_scaling_factor (gcc); + gimp_cage_config_compute_edges_normal (gcc); + gimp_cage_config_reset_displacement (gcc); +} + +/** + * gimp_cage_config_reset_displacement: + * @gcc: the cage config + * + * Set the displacement to zero. + */ +void +gimp_cage_config_reset_displacement (GimpCageConfig *gcc) +{ + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + gcc->displacement_x = 0.0; + gcc->displacement_y = 0.0; +} + +/** + * gimp_cage_config_get_bounding_box: + * @gcc: the cage config + * + * Compute the bounding box of the source cage + * + * Returns: the bounding box of the source cage, as a GeglRectangle + */ +GeglRectangle +gimp_cage_config_get_bounding_box (GimpCageConfig *gcc) +{ + GeglRectangle bounding_box = { 0, 0, 0, 0}; + gint i; + GimpCagePoint *point; + + g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), bounding_box); + + if (gcc->cage_points->len == 0) + return bounding_box; + + point = &g_array_index (gcc->cage_points, GimpCagePoint, 0); + + if (point->selected) + { + bounding_box.x = point->src_point.x + gcc->displacement_x; + bounding_box.y = point->src_point.y + gcc->displacement_y; + } + else + { + bounding_box.x = point->src_point.x; + bounding_box.y = point->src_point.y; + } + + for (i = 1; i < gcc->cage_points->len; i++) + { + gdouble x,y; + point = &g_array_index (gcc->cage_points, GimpCagePoint, i); + + if (point->selected) + { + x = point->src_point.x + gcc->displacement_x; + y = point->src_point.y + gcc->displacement_y; + } + else + { + x = point->src_point.x; + y = point->src_point.y; + } + + if (x < bounding_box.x) + { + bounding_box.width += bounding_box.x - x; + bounding_box.x = x; + } + + if (y < bounding_box.y) + { + bounding_box.height += bounding_box.y - y; + bounding_box.y = y; + } + + if (x > bounding_box.x + bounding_box.width) + { + bounding_box.width = x - bounding_box.x; + } + + if (y > bounding_box.y + bounding_box.height) + { + bounding_box.height = y - bounding_box.y; + } + } + + return bounding_box; +} + +/** + * gimp_cage_config_reverse_cage: + * @gcc: the cage config + * + * When using non-simple cage (like a cage in 8), user may want to + * manually inverse inside and outside of the cage. This function + * reverse the cage + */ +void +gimp_cage_config_reverse_cage (GimpCageConfig *gcc) +{ + GimpCagePoint temp; + gint i; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + for (i = 0; i < gcc->cage_points->len / 2; i++) + { + temp = g_array_index (gcc->cage_points, GimpCagePoint, i); + + g_array_index (gcc->cage_points, GimpCagePoint, i) = + g_array_index (gcc->cage_points, GimpCagePoint, gcc->cage_points->len - i - 1); + + g_array_index (gcc->cage_points, GimpCagePoint, gcc->cage_points->len - i - 1) = temp; + } + + gimp_cage_config_compute_scaling_factor (gcc); + gimp_cage_config_compute_edges_normal (gcc); +} + +/** + * gimp_cage_config_reverse_cage_if_needed: + * @gcc: the cage config + * + * Since the cage need to be defined counter-clockwise to have the + * topological inside in the actual 'physical' inside of the cage, + * this function compute if the cage is clockwise or not, and reverse + * the cage if needed. + * + * This function does not take into account an eventual displacement + */ +void +gimp_cage_config_reverse_cage_if_needed (GimpCageConfig *gcc) +{ + gint i; + gdouble sum; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + sum = 0.0; + + /* this is a bit crappy, but should works most of the case */ + /* we do the sum of the projection of each point to the previous + segment, and see the final sign */ + for (i = 0; i < gcc->cage_points->len ; i++) + { + GimpVector2 P1, P2, P3; + gdouble z; + + P1 = (g_array_index (gcc->cage_points, GimpCagePoint, i)).src_point; + P2 = (g_array_index (gcc->cage_points, GimpCagePoint, (i+1) % gcc->cage_points->len)).src_point; + P3 = (g_array_index (gcc->cage_points, GimpCagePoint, (i+2) % gcc->cage_points->len)).src_point; + + z = P1.x * (P2.y - P3.y) + P2.x * (P3.y - P1.y) + P3.x * (P1.y - P2.y); + + sum += z; + } + + /* sum > 0 mean a cage defined counter-clockwise, so we reverse it */ + if (sum > 0) + { + gimp_cage_config_reverse_cage (gcc); + } +} + +/** + * gimp_cage_config_compute_scaling_factor: + * @gcc: the cage config + * + * Update Green Coordinate scaling factor for the destination cage. + * This function does not take into account an eventual displacement. + */ +static void +gimp_cage_config_compute_scaling_factor (GimpCageConfig *gcc) +{ + GimpVector2 edge; + gdouble length, length_d; + gint i; + GimpCagePoint *current, *last; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + if (gcc->cage_points->len < 2) + return; + + last = &g_array_index (gcc->cage_points, GimpCagePoint, 0); + + for (i = 1; i <= gcc->cage_points->len; i++) + { + current = &g_array_index (gcc->cage_points, GimpCagePoint, i % gcc->cage_points->len); + + gimp_vector2_sub (&edge, + &(last->src_point), + &(current->src_point)); + length = gimp_vector2_length (&edge); + + gimp_vector2_sub (&edge, + &(last->dest_point), + &(current->dest_point)); + length_d = gimp_vector2_length (&edge); + + last->edge_scaling_factor = length_d / length; + last = current; + } +} + +/** + * gimp_cage_config_compute_edges_normal: + * @gcc: the cage config + * + * Update edges normal for the destination cage. + * This function does not take into account an eventual displacement. + */ +static void +gimp_cage_config_compute_edges_normal (GimpCageConfig *gcc) +{ + GimpVector2 normal; + gint i; + GimpCagePoint *current, *last; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + last = &g_array_index (gcc->cage_points, GimpCagePoint, 0); + + for (i = 1; i <= gcc->cage_points->len; i++) + { + current = &g_array_index (gcc->cage_points, GimpCagePoint, i % gcc->cage_points->len); + + gimp_vector2_sub (&normal, + &(current->dest_point), + &(last->dest_point)); + + last->edge_normal = gimp_vector2_normal (&normal); + last = current; + } +} + +/** + * gimp_cage_config_point_inside: + * @gcc: the cage config + * @x: x coordinate of the point to test + * @y: y coordinate of the point to test + * + * Check if the given point is inside the cage. This test is done in + * the regard of the topological inside of the source cage. + * + * Returns: TRUE if the point is inside, FALSE if not. + * This function does not take into account an eventual displacement. + */ +gboolean +gimp_cage_config_point_inside (GimpCageConfig *gcc, + gfloat x, + gfloat y) +{ + GimpVector2 *last, *current; + gboolean inside = FALSE; + gint i; + + g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), FALSE); + + last = &((g_array_index (gcc->cage_points, GimpCagePoint, gcc->cage_points->len - 1)).src_point); + + for (i = 0; i < gcc->cage_points->len; i++) + { + current = &((g_array_index (gcc->cage_points, GimpCagePoint, i)).src_point); + + if ((((current->y <= y) && (y < last->y)) + || ((last->y <= y) && (y < current->y))) + && (x < (last->x - current->x) * (y - current->y) / (last->y - current->y) + current->x)) + { + inside = !inside; + } + + last = current; + } + + return inside; +} + +/** + * gimp_cage_config_select_point: + * @gcc: the cage config + * @point_number: the index of the point to select + * + * Select the given point of the cage, and deselect the others. + */ +void +gimp_cage_config_select_point (GimpCageConfig *gcc, + gint point_number) +{ + gint i; + GimpCagePoint *point; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + g_return_if_fail (point_number < gcc->cage_points->len); + g_return_if_fail (point_number >= 0); + + for (i = 0; i < gcc->cage_points->len; i++) + { + point = &g_array_index (gcc->cage_points, GimpCagePoint, i); + + if (i == point_number) + { + point->selected = TRUE; + } + else + { + point->selected = FALSE; + } + } +} + +/** + * gimp_cage_config_select_area: + * @gcc: the cage config + * @mode: the actual mode of the cage, GIMP_CAGE_MODE_CAGE_CHANGE or GIMP_CAGE_MODE_DEFORM + * @area: the area to select + * + * Select cage's point inside the given area and deselect others + */ +void +gimp_cage_config_select_area (GimpCageConfig *gcc, + GimpCageMode mode, + GeglRectangle area) +{ + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + gimp_cage_config_deselect_points (gcc); + gimp_cage_config_select_add_area (gcc, mode, area); +} + +/** + * gimp_cage_config_select_add_area: + * @gcc: the cage config + * @mode: the actual mode of the cage, GIMP_CAGE_MODE_CAGE_CHANGE or GIMP_CAGE_MODE_DEFORM + * @area: the area to select + * + * Select cage's point inside the given area. Already selected point stay selected. + */ +void +gimp_cage_config_select_add_area (GimpCageConfig *gcc, + GimpCageMode mode, + GeglRectangle area) +{ + gint i; + GimpCagePoint *point; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + for (i = 0; i < gcc->cage_points->len; i++) + { + point = &g_array_index (gcc->cage_points, GimpCagePoint, i); + + if (mode == GIMP_CAGE_MODE_CAGE_CHANGE) + { + if (point->src_point.x >= area.x && + point->src_point.x <= area.x + area.width && + point->src_point.y >= area.y && + point->src_point.y <= area.y + area.height) + { + point->selected = TRUE; + } + } + else + { + if (point->dest_point.x >= area.x && + point->dest_point.x <= area.x + area.width && + point->dest_point.y >= area.y && + point->dest_point.y <= area.y + area.height) + { + point->selected = TRUE; + } + } + } +} + +/** + * gimp_cage_config_toggle_point_selection: + * @gcc: the cage config + * @point_number: the index of the point to toggle selection + * + * Toggle the selection of the given cage point + */ +void +gimp_cage_config_toggle_point_selection (GimpCageConfig *gcc, + gint point_number) +{ + GimpCagePoint *point; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + g_return_if_fail (point_number < gcc->cage_points->len); + g_return_if_fail (point_number >= 0); + + point = &g_array_index (gcc->cage_points, GimpCagePoint, point_number); + point->selected = ! point->selected; +} + +/** + * gimp_cage_deselect_points: + * @gcc: the cage config + * + * Deselect all cage points. + */ +void +gimp_cage_config_deselect_points (GimpCageConfig *gcc) +{ + gint i; + + g_return_if_fail (GIMP_IS_CAGE_CONFIG (gcc)); + + for (i = 0; i < gcc->cage_points->len; i++) + { + (g_array_index (gcc->cage_points, GimpCagePoint, i)).selected = FALSE; + } +} + +/** + * gimp_cage_config_point_is_selected: + * @gcc: the cage config + * @point_number: the index of the point to test + * + * Returns: TRUE if the point is selected, FALSE otherwise. + */ +gboolean +gimp_cage_config_point_is_selected (GimpCageConfig *gcc, + gint point_number) +{ + GimpCagePoint *point; + + g_return_val_if_fail (GIMP_IS_CAGE_CONFIG (gcc), FALSE); + g_return_val_if_fail (point_number < gcc->cage_points->len, FALSE); + g_return_val_if_fail (point_number >= 0, FALSE); + + point = &(g_array_index (gcc->cage_points, GimpCagePoint, point_number)); + + return point->selected; +} diff --git a/app/operations/gimpcageconfig.h b/app/operations/gimpcageconfig.h new file mode 100644 index 0000000..8106d52 --- /dev/null +++ b/app/operations/gimpcageconfig.h @@ -0,0 +1,108 @@ +/* GIMP - The GNU Image Manipulation Program + * + * gimpcageconfig.h + * Copyright (C) 2010 Michael Muré <batolettre@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_CAGE_CONFIG_H__ +#define __GIMP_CAGE_CONFIG_H__ + + +#include "gimpoperationsettings.h" + + +struct _GimpCagePoint +{ + GimpVector2 src_point; + GimpVector2 dest_point; + GimpVector2 edge_normal; + gdouble edge_scaling_factor; + gboolean selected; +}; + + +#define GIMP_TYPE_CAGE_CONFIG (gimp_cage_config_get_type ()) +#define GIMP_CAGE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CAGE_CONFIG, GimpCageConfig)) +#define GIMP_CAGE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CAGE_CONFIG, GimpCageConfigClass)) +#define GIMP_IS_CAGE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CAGE_CONFIG)) +#define GIMP_IS_CAGE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CAGE_CONFIG)) +#define GIMP_CAGE_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CAGE_CONFIG, GimpCageConfigClass)) + + +typedef struct _GimpCageConfigClass GimpCageConfigClass; + +struct _GimpCageConfig +{ + GimpOperationSettings parent_instance; + + GArray *cage_points; + + gdouble displacement_x; + gdouble displacement_y; + GimpCageMode cage_mode; /* Cage mode, used to commit displacement */ +}; + +struct _GimpCageConfigClass +{ + GimpOperationSettingsClass parent_class; +}; + + +GType gimp_cage_config_get_type (void) G_GNUC_CONST; + +guint gimp_cage_config_get_n_points (GimpCageConfig *gcc); +void gimp_cage_config_add_cage_point (GimpCageConfig *gcc, + gdouble x, + gdouble y); +void gimp_cage_config_insert_cage_point (GimpCageConfig *gcc, + gint point_number, + gdouble x, + gdouble y); +void gimp_cage_config_remove_last_cage_point (GimpCageConfig *gcc); +void gimp_cage_config_remove_cage_point (GimpCageConfig *gcc, + gint point_number); +void gimp_cage_config_remove_selected_points (GimpCageConfig *gcc); +GimpVector2 gimp_cage_config_get_point_coordinate (GimpCageConfig *gcc, + GimpCageMode mode, + gint point_number); +void gimp_cage_config_add_displacement (GimpCageConfig *gcc, + GimpCageMode mode, + gdouble x, + gdouble y); +void gimp_cage_config_commit_displacement (GimpCageConfig *gcc); +void gimp_cage_config_reset_displacement (GimpCageConfig *gcc); +GeglRectangle gimp_cage_config_get_bounding_box (GimpCageConfig *gcc); +void gimp_cage_config_reverse_cage_if_needed (GimpCageConfig *gcc); +void gimp_cage_config_reverse_cage (GimpCageConfig *gcc); +gboolean gimp_cage_config_point_inside (GimpCageConfig *gcc, + gfloat x, + gfloat y); +void gimp_cage_config_select_point (GimpCageConfig *gcc, + gint point_number); +void gimp_cage_config_select_area (GimpCageConfig *gcc, + GimpCageMode mode, + GeglRectangle area); +void gimp_cage_config_select_add_area (GimpCageConfig *gcc, + GimpCageMode mode, + GeglRectangle area); +void gimp_cage_config_toggle_point_selection (GimpCageConfig *gcc, + gint point_number); +void gimp_cage_config_deselect_points (GimpCageConfig *gcc); +gboolean gimp_cage_config_point_is_selected (GimpCageConfig *gcc, + gint point_number); + + +#endif /* __GIMP_CAGE_CONFIG_H__ */ diff --git a/app/operations/gimpcolorbalanceconfig.c b/app/operations/gimpcolorbalanceconfig.c new file mode 100644 index 0000000..7011a86 --- /dev/null +++ b/app/operations/gimpcolorbalanceconfig.c @@ -0,0 +1,382 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpcolorbalanceconfig.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "gimpcolorbalanceconfig.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_RANGE, + PROP_CYAN_RED, + PROP_MAGENTA_GREEN, + PROP_YELLOW_BLUE, + PROP_PRESERVE_LUMINOSITY +}; + + +static void gimp_color_balance_config_iface_init (GimpConfigInterface *iface); + +static void gimp_color_balance_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_color_balance_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gboolean gimp_color_balance_config_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data); +static gboolean gimp_color_balance_config_deserialize (GimpConfig *config, + GScanner *scanner, + gint nest_level, + gpointer data); +static gboolean gimp_color_balance_config_equal (GimpConfig *a, + GimpConfig *b); +static void gimp_color_balance_config_reset (GimpConfig *config); +static gboolean gimp_color_balance_config_copy (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags); + + +G_DEFINE_TYPE_WITH_CODE (GimpColorBalanceConfig, gimp_color_balance_config, + GIMP_TYPE_OPERATION_SETTINGS, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, + gimp_color_balance_config_iface_init)) + +#define parent_class gimp_color_balance_config_parent_class + + +static void +gimp_color_balance_config_class_init (GimpColorBalanceConfigClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + + object_class->set_property = gimp_color_balance_config_set_property; + object_class->get_property = gimp_color_balance_config_get_property; + + viewable_class->default_icon_name = "gimp-tool-color-balance"; + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_RANGE, + "range", + _("Range"), + _("The affected range"), + GIMP_TYPE_TRANSFER_MODE, + GIMP_TRANSFER_MIDTONES, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_CYAN_RED, + "cyan-red", + _("Cyan-Red"), + _("Cyan-Red"), + -1.0, 1.0, 0.0, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_MAGENTA_GREEN, + "magenta-green", + _("Magenta-Green"), + _("Magenta-Green"), + -1.0, 1.0, 0.0, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_YELLOW_BLUE, + "yellow-blue", + _("Yellow-Blue"), + _("Yellow-Blue"), + -1.0, 1.0, 0.0, 0); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_PRESERVE_LUMINOSITY, + "preserve-luminosity", + _("Preserve Luminosity"), + _("Preserve Luminosity"), + TRUE, 0); +} + +static void +gimp_color_balance_config_iface_init (GimpConfigInterface *iface) +{ + iface->serialize = gimp_color_balance_config_serialize; + iface->deserialize = gimp_color_balance_config_deserialize; + iface->equal = gimp_color_balance_config_equal; + iface->reset = gimp_color_balance_config_reset; + iface->copy = gimp_color_balance_config_copy; +} + +static void +gimp_color_balance_config_init (GimpColorBalanceConfig *self) +{ + gimp_config_reset (GIMP_CONFIG (self)); +} + +static void +gimp_color_balance_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpColorBalanceConfig *self = GIMP_COLOR_BALANCE_CONFIG (object); + + switch (property_id) + { + case PROP_RANGE: + g_value_set_enum (value, self->range); + break; + + case PROP_CYAN_RED: + g_value_set_double (value, self->cyan_red[self->range]); + break; + + case PROP_MAGENTA_GREEN: + g_value_set_double (value, self->magenta_green[self->range]); + break; + + case PROP_YELLOW_BLUE: + g_value_set_double (value, self->yellow_blue[self->range]); + break; + + case PROP_PRESERVE_LUMINOSITY: + g_value_set_boolean (value, self->preserve_luminosity); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_color_balance_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpColorBalanceConfig *self = GIMP_COLOR_BALANCE_CONFIG (object); + + switch (property_id) + { + case PROP_RANGE: + self->range = g_value_get_enum (value); + g_object_notify (object, "cyan-red"); + g_object_notify (object, "magenta-green"); + g_object_notify (object, "yellow-blue"); + break; + + case PROP_CYAN_RED: + self->cyan_red[self->range] = g_value_get_double (value); + break; + + case PROP_MAGENTA_GREEN: + self->magenta_green[self->range] = g_value_get_double (value); + break; + + case PROP_YELLOW_BLUE: + self->yellow_blue[self->range] = g_value_get_double (value); + break; + + case PROP_PRESERVE_LUMINOSITY: + self->preserve_luminosity = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gboolean +gimp_color_balance_config_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data) +{ + GimpColorBalanceConfig *bc_config = GIMP_COLOR_BALANCE_CONFIG (config); + GimpTransferMode range; + GimpTransferMode old_range; + gboolean success = TRUE; + + if (! gimp_operation_settings_config_serialize_base (config, writer, data)) + return FALSE; + + old_range = bc_config->range; + + for (range = GIMP_TRANSFER_SHADOWS; + range <= GIMP_TRANSFER_HIGHLIGHTS; + range++) + { + bc_config->range = range; + + success = (gimp_config_serialize_property_by_name (config, + "range", + writer) && + gimp_config_serialize_property_by_name (config, + "cyan-red", + writer) && + gimp_config_serialize_property_by_name (config, + "magenta-green", + writer) && + gimp_config_serialize_property_by_name (config, + "yellow-blue", + writer)); + + if (! success) + break; + } + + if (success) + success = gimp_config_serialize_property_by_name (config, + "preserve-luminosity", + writer); + + bc_config->range = old_range; + + return success; +} + +static gboolean +gimp_color_balance_config_deserialize (GimpConfig *config, + GScanner *scanner, + gint nest_level, + gpointer data) +{ + GimpColorBalanceConfig *cb_config = GIMP_COLOR_BALANCE_CONFIG (config); + GimpTransferMode old_range; + gboolean success = TRUE; + + old_range = cb_config->range; + + success = gimp_config_deserialize_properties (config, scanner, nest_level); + + g_object_set (config, "range", old_range, NULL); + + return success; +} + +static gboolean +gimp_color_balance_config_equal (GimpConfig *a, + GimpConfig *b) +{ + GimpColorBalanceConfig *config_a = GIMP_COLOR_BALANCE_CONFIG (a); + GimpColorBalanceConfig *config_b = GIMP_COLOR_BALANCE_CONFIG (b); + GimpTransferMode range; + + if (! gimp_operation_settings_config_equal_base (a, b)) + return FALSE; + + for (range = GIMP_TRANSFER_SHADOWS; + range <= GIMP_TRANSFER_HIGHLIGHTS; + range++) + { + if (config_a->cyan_red[range] != config_b->cyan_red[range] || + config_a->magenta_green[range] != config_b->magenta_green[range] || + config_a->yellow_blue[range] != config_b->yellow_blue[range]) + return FALSE; + } + + /* don't compare "range" */ + + if (config_a->preserve_luminosity != config_b->preserve_luminosity) + return FALSE; + + return TRUE; +} + +static void +gimp_color_balance_config_reset (GimpConfig *config) +{ + GimpColorBalanceConfig *cb_config = GIMP_COLOR_BALANCE_CONFIG (config); + GimpTransferMode range; + + gimp_operation_settings_config_reset_base (config); + + for (range = GIMP_TRANSFER_SHADOWS; + range <= GIMP_TRANSFER_HIGHLIGHTS; + range++) + { + cb_config->range = range; + gimp_color_balance_config_reset_range (cb_config); + } + + gimp_config_reset_property (G_OBJECT (config), "range"); + gimp_config_reset_property (G_OBJECT (config), "preserve-luminosity"); +} + +static gboolean +gimp_color_balance_config_copy (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags) +{ + GimpColorBalanceConfig *src_config = GIMP_COLOR_BALANCE_CONFIG (src); + GimpColorBalanceConfig *dest_config = GIMP_COLOR_BALANCE_CONFIG (dest); + GimpTransferMode range; + + if (! gimp_operation_settings_config_copy_base (src, dest, flags)) + return FALSE; + + for (range = GIMP_TRANSFER_SHADOWS; + range <= GIMP_TRANSFER_HIGHLIGHTS; + range++) + { + dest_config->cyan_red[range] = src_config->cyan_red[range]; + dest_config->magenta_green[range] = src_config->magenta_green[range]; + dest_config->yellow_blue[range] = src_config->yellow_blue[range]; + } + + g_object_notify (G_OBJECT (dest), "cyan-red"); + g_object_notify (G_OBJECT (dest), "magenta-green"); + g_object_notify (G_OBJECT (dest), "yellow-blue"); + + dest_config->range = src_config->range; + dest_config->preserve_luminosity = src_config->preserve_luminosity; + + g_object_notify (G_OBJECT (dest), "range"); + g_object_notify (G_OBJECT (dest), "preserve-luminosity"); + + return TRUE; +} + + +/* public functions */ + +void +gimp_color_balance_config_reset_range (GimpColorBalanceConfig *config) +{ + g_return_if_fail (GIMP_IS_COLOR_BALANCE_CONFIG (config)); + + g_object_freeze_notify (G_OBJECT (config)); + + gimp_config_reset_property (G_OBJECT (config), "cyan-red"); + gimp_config_reset_property (G_OBJECT (config), "magenta-green"); + gimp_config_reset_property (G_OBJECT (config), "yellow-blue"); + + g_object_thaw_notify (G_OBJECT (config)); +} diff --git a/app/operations/gimpcolorbalanceconfig.h b/app/operations/gimpcolorbalanceconfig.h new file mode 100644 index 0000000..4c58cea --- /dev/null +++ b/app/operations/gimpcolorbalanceconfig.h @@ -0,0 +1,62 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpcolorbalanceconfig.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_COLOR_BALANCE_CONFIG_H__ +#define __GIMP_COLOR_BALANCE_CONFIG_H__ + + +#include "gimpoperationsettings.h" + + +#define GIMP_TYPE_COLOR_BALANCE_CONFIG (gimp_color_balance_config_get_type ()) +#define GIMP_COLOR_BALANCE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_COLOR_BALANCE_CONFIG, GimpColorBalanceConfig)) +#define GIMP_COLOR_BALANCE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_COLOR_BALANCE_CONFIG, GimpColorBalanceConfigClass)) +#define GIMP_IS_COLOR_BALANCE_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_COLOR_BALANCE_CONFIG)) +#define GIMP_IS_COLOR_BALANCE_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_COLOR_BALANCE_CONFIG)) +#define GIMP_COLOR_BALANCE_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_COLOR_BALANCE_CONFIG, GimpColorBalanceConfigClass)) + + +typedef struct _GimpColorBalanceConfigClass GimpColorBalanceConfigClass; + +struct _GimpColorBalanceConfig +{ + GimpOperationSettings parent_instance; + + GimpTransferMode range; + + gdouble cyan_red[3]; + gdouble magenta_green[3]; + gdouble yellow_blue[3]; + + gboolean preserve_luminosity; +}; + +struct _GimpColorBalanceConfigClass +{ + GimpOperationSettingsClass parent_class; +}; + + +GType gimp_color_balance_config_get_type (void) G_GNUC_CONST; + +void gimp_color_balance_config_reset_range (GimpColorBalanceConfig *config); + + +#endif /* __GIMP_COLOR_BALANCE_CONFIG_H__ */ diff --git a/app/operations/gimpcurvesconfig.c b/app/operations/gimpcurvesconfig.c new file mode 100644 index 0000000..b63bcf3 --- /dev/null +++ b/app/operations/gimpcurvesconfig.c @@ -0,0 +1,695 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpcurvesconfig.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "core/gimp-utils.h" +#include "core/gimpcurve.h" +#include "core/gimphistogram.h" + +#include "gimpcurvesconfig.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_LINEAR, + PROP_CHANNEL, + PROP_CURVE +}; + + +static void gimp_curves_config_iface_init (GimpConfigInterface *iface); + +static void gimp_curves_config_finalize (GObject *object); +static void gimp_curves_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_curves_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gboolean gimp_curves_config_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data); +static gboolean gimp_curves_config_deserialize (GimpConfig *config, + GScanner *scanner, + gint nest_level, + gpointer data); +static gboolean gimp_curves_config_equal (GimpConfig *a, + GimpConfig *b); +static void gimp_curves_config_reset (GimpConfig *config); +static gboolean gimp_curves_config_copy (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags); + +static void gimp_curves_config_curve_dirty (GimpCurve *curve, + GimpCurvesConfig *config); + + +G_DEFINE_TYPE_WITH_CODE (GimpCurvesConfig, gimp_curves_config, + GIMP_TYPE_OPERATION_SETTINGS, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, + gimp_curves_config_iface_init)) + +#define parent_class gimp_curves_config_parent_class + + +static void +gimp_curves_config_class_init (GimpCurvesConfigClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + + object_class->finalize = gimp_curves_config_finalize; + object_class->set_property = gimp_curves_config_set_property; + object_class->get_property = gimp_curves_config_get_property; + + viewable_class->default_icon_name = "gimp-tool-curves"; + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_LINEAR, + "linear", + _("Linear"), + _("Work on linear RGB"), + FALSE, 0); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_CHANNEL, + "channel", + _("Channel"), + _("The affected channel"), + GIMP_TYPE_HISTOGRAM_CHANNEL, + GIMP_HISTOGRAM_VALUE, 0); + + GIMP_CONFIG_PROP_OBJECT (object_class, PROP_CURVE, + "curve", + _("Curve"), + _("Curve"), + GIMP_TYPE_CURVE, + GIMP_CONFIG_PARAM_AGGREGATE); +} + +static void +gimp_curves_config_iface_init (GimpConfigInterface *iface) +{ + iface->serialize = gimp_curves_config_serialize; + iface->deserialize = gimp_curves_config_deserialize; + iface->equal = gimp_curves_config_equal; + iface->reset = gimp_curves_config_reset; + iface->copy = gimp_curves_config_copy; +} + +static void +gimp_curves_config_init (GimpCurvesConfig *self) +{ + GimpHistogramChannel channel; + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + self->curve[channel] = GIMP_CURVE (gimp_curve_new ("curves config")); + + g_signal_connect_object (self->curve[channel], "dirty", + G_CALLBACK (gimp_curves_config_curve_dirty), + self, 0); + } + + gimp_config_reset (GIMP_CONFIG (self)); +} + +static void +gimp_curves_config_finalize (GObject *object) +{ + GimpCurvesConfig *self = GIMP_CURVES_CONFIG (object); + GimpHistogramChannel channel; + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + g_object_unref (self->curve[channel]); + self->curve[channel] = NULL; + } + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_curves_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpCurvesConfig *self = GIMP_CURVES_CONFIG (object); + + switch (property_id) + { + case PROP_LINEAR: + g_value_set_boolean (value, self->linear); + break; + + case PROP_CHANNEL: + g_value_set_enum (value, self->channel); + break; + + case PROP_CURVE: + g_value_set_object (value, self->curve[self->channel]); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_curves_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpCurvesConfig *self = GIMP_CURVES_CONFIG (object); + + switch (property_id) + { + case PROP_LINEAR: + self->linear = g_value_get_boolean (value); + break; + + case PROP_CHANNEL: + self->channel = g_value_get_enum (value); + g_object_notify (object, "curve"); + break; + + case PROP_CURVE: + { + GimpCurve *src_curve = g_value_get_object (value); + GimpCurve *dest_curve = self->curve[self->channel]; + + if (src_curve && dest_curve) + { + gimp_config_copy (GIMP_CONFIG (src_curve), + GIMP_CONFIG (dest_curve), 0); + } + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gboolean +gimp_curves_config_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data) +{ + GimpCurvesConfig *c_config = GIMP_CURVES_CONFIG (config); + GimpHistogramChannel channel; + GimpHistogramChannel old_channel; + gboolean success = TRUE; + + if (! gimp_operation_settings_config_serialize_base (config, writer, data) || + ! gimp_config_serialize_property_by_name (config, "linear", writer)) + return FALSE; + + old_channel = c_config->channel; + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + c_config->channel = channel; + + /* serialize the channel properties manually (not using + * gimp_config_serialize_properties()), so the parent class' + * properties don't end up in the config file one per channel. + * See bug #700653. + */ + success = + (gimp_config_serialize_property_by_name (config, "channel", writer) && + gimp_config_serialize_property_by_name (config, "curve", writer)); + + if (! success) + break; + } + + c_config->channel = old_channel; + + return success; +} + +static gboolean +gimp_curves_config_deserialize (GimpConfig *config, + GScanner *scanner, + gint nest_level, + gpointer data) +{ + GimpCurvesConfig *c_config = GIMP_CURVES_CONFIG (config); + GimpHistogramChannel old_channel; + gboolean success = TRUE; + + old_channel = c_config->channel; + + success = gimp_config_deserialize_properties (config, scanner, nest_level); + + g_object_set (config, "channel", old_channel, NULL); + + return success; +} + +static gboolean +gimp_curves_config_equal (GimpConfig *a, + GimpConfig *b) +{ + GimpCurvesConfig *config_a = GIMP_CURVES_CONFIG (a); + GimpCurvesConfig *config_b = GIMP_CURVES_CONFIG (b); + GimpHistogramChannel channel; + + if (! gimp_operation_settings_config_equal_base (a, b) || + config_a->linear != config_b->linear) + return FALSE; + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + GimpCurve *curve_a = config_a->curve[channel]; + GimpCurve *curve_b = config_b->curve[channel]; + + if (curve_a && curve_b) + { + if (! gimp_config_is_equal_to (GIMP_CONFIG (curve_a), + GIMP_CONFIG (curve_b))) + return FALSE; + } + else if (curve_a || curve_b) + { + return FALSE; + } + } + + /* don't compare "channel" */ + + return TRUE; +} + +static void +gimp_curves_config_reset (GimpConfig *config) +{ + GimpCurvesConfig *c_config = GIMP_CURVES_CONFIG (config); + GimpHistogramChannel channel; + + gimp_operation_settings_config_reset_base (config); + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + c_config->channel = channel; + gimp_curves_config_reset_channel (c_config); + } + + gimp_config_reset_property (G_OBJECT (config), "linear"); + gimp_config_reset_property (G_OBJECT (config), "channel"); +} + +static gboolean +gimp_curves_config_copy (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags) +{ + GimpCurvesConfig *src_config = GIMP_CURVES_CONFIG (src); + GimpCurvesConfig *dest_config = GIMP_CURVES_CONFIG (dest); + GimpHistogramChannel channel; + + if (! gimp_operation_settings_config_copy_base (src, dest, flags)) + return FALSE; + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + gimp_config_copy (GIMP_CONFIG (src_config->curve[channel]), + GIMP_CONFIG (dest_config->curve[channel]), + flags); + } + + dest_config->linear = src_config->linear; + dest_config->channel = src_config->channel; + + g_object_notify (G_OBJECT (dest), "linear"); + g_object_notify (G_OBJECT (dest), "channel"); + + return TRUE; +} + +static void +gimp_curves_config_curve_dirty (GimpCurve *curve, + GimpCurvesConfig *config) +{ + g_object_notify (G_OBJECT (config), "curve"); +} + + +/* public functions */ + +GObject * +gimp_curves_config_new_spline (gint32 channel, + const gdouble *points, + gint n_points) +{ + GimpCurvesConfig *config; + GimpCurve *curve; + gint i; + + g_return_val_if_fail (channel >= GIMP_HISTOGRAM_VALUE && + channel <= GIMP_HISTOGRAM_ALPHA, NULL); + g_return_val_if_fail (points != NULL, NULL); + g_return_val_if_fail (n_points >= 2 && n_points <= 1024, NULL); + + config = g_object_new (GIMP_TYPE_CURVES_CONFIG, NULL); + + curve = config->curve[channel]; + + gimp_data_freeze (GIMP_DATA (curve)); + + gimp_curve_set_curve_type (curve, GIMP_CURVE_SMOOTH); + gimp_curve_clear_points (curve); + + for (i = 0; i < n_points; i++) + gimp_curve_add_point (curve, + (gdouble) points[i * 2], + (gdouble) points[i * 2 + 1]); + + gimp_data_thaw (GIMP_DATA (curve)); + + return G_OBJECT (config); +} + +GObject * +gimp_curves_config_new_explicit (gint32 channel, + const gdouble *samples, + gint n_samples) +{ + GimpCurvesConfig *config; + GimpCurve *curve; + gint i; + + g_return_val_if_fail (channel >= GIMP_HISTOGRAM_VALUE && + channel <= GIMP_HISTOGRAM_ALPHA, NULL); + g_return_val_if_fail (samples != NULL, NULL); + g_return_val_if_fail (n_samples >= 2 && n_samples <= 4096, NULL); + + config = g_object_new (GIMP_TYPE_CURVES_CONFIG, NULL); + + curve = config->curve[channel]; + + gimp_data_freeze (GIMP_DATA (curve)); + + gimp_curve_set_curve_type (curve, GIMP_CURVE_FREE); + gimp_curve_set_n_samples (curve, n_samples); + + for (i = 0; i < n_samples; i++) + gimp_curve_set_curve (curve, + (gdouble) i / (gdouble) (n_samples - 1), + (gdouble) samples[i]); + + gimp_data_thaw (GIMP_DATA (curve)); + + return G_OBJECT (config); +} + +GObject * +gimp_curves_config_new_spline_cruft (gint32 channel, + const guint8 *points, + gint n_points) +{ + GObject *config; + gdouble *d_points; + gint i; + + g_return_val_if_fail (channel >= GIMP_HISTOGRAM_VALUE && + channel <= GIMP_HISTOGRAM_ALPHA, NULL); + g_return_val_if_fail (points != NULL, NULL); + g_return_val_if_fail (n_points >= 2 && n_points <= 1024, NULL); + + d_points = g_new (gdouble, 2 * n_points); + + for (i = 0; i < n_points; i++) + { + d_points[i * 2] = (gdouble) points[i * 2] / 255.0; + d_points[i * 2 + 1] = (gdouble) points[i * 2 + 1] / 255.0; + } + + config = gimp_curves_config_new_spline (channel, d_points, n_points); + + g_free (d_points); + + return config; +} + +GObject * +gimp_curves_config_new_explicit_cruft (gint32 channel, + const guint8 *samples, + gint n_samples) +{ + GObject *config; + gdouble *d_samples; + gint i; + + g_return_val_if_fail (channel >= GIMP_HISTOGRAM_VALUE && + channel <= GIMP_HISTOGRAM_ALPHA, NULL); + g_return_val_if_fail (samples != NULL, NULL); + g_return_val_if_fail (n_samples >= 2 && n_samples <= 4096, NULL); + + d_samples = g_new (gdouble, n_samples); + + for (i = 0; i < n_samples; i++) + { + d_samples[i] = (gdouble) samples[i] / 255.0; + } + + config = gimp_curves_config_new_explicit (channel, d_samples, n_samples); + + g_free (d_samples); + + return config; +} + +void +gimp_curves_config_reset_channel (GimpCurvesConfig *config) +{ + g_return_if_fail (GIMP_IS_CURVES_CONFIG (config)); + + gimp_config_reset (GIMP_CONFIG (config->curve[config->channel])); +} + +#define GIMP_CURVE_N_CRUFT_POINTS 17 + +gboolean +gimp_curves_config_load_cruft (GimpCurvesConfig *config, + GInputStream *input, + GError **error) +{ + GDataInputStream *data_input; + gint index[5][GIMP_CURVE_N_CRUFT_POINTS]; + gint value[5][GIMP_CURVE_N_CRUFT_POINTS]; + gchar *line; + gsize line_len; + gint i, j; + + g_return_val_if_fail (GIMP_IS_CURVES_CONFIG (config), FALSE); + g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + data_input = g_data_input_stream_new (input); + + line_len = 64; + line = gimp_data_input_stream_read_line_always (data_input, &line_len, + NULL, error); + if (! line) + return FALSE; + + if (strcmp (line, "# GIMP Curves File") != 0) + { + g_set_error_literal (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE, + _("not a GIMP Curves file")); + g_object_unref (data_input); + g_free (line); + return FALSE; + } + + for (i = 0; i < 5; i++) + { + for (j = 0; j < GIMP_CURVE_N_CRUFT_POINTS; j++) + { + gchar *x_str = NULL; + gchar *y_str = NULL; + + if (! (x_str = g_data_input_stream_read_upto (data_input, " ", -1, + NULL, NULL, error)) || + ! g_data_input_stream_read_byte (data_input, NULL, error) || + ! (y_str = g_data_input_stream_read_upto (data_input, " ", -1, + NULL, NULL, error)) || + ! g_data_input_stream_read_byte (data_input, NULL, error)) + { + g_free (x_str); + g_free (y_str); + g_object_unref (data_input); + return FALSE; + } + + if (sscanf (x_str, "%d", &index[i][j]) != 1 || + sscanf (y_str, "%d", &value[i][j]) != 1) + { + g_set_error_literal (error, + GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE, + _("Parse error, didn't find 2 integers")); + g_free (x_str); + g_free (y_str); + g_object_unref (data_input); + return FALSE; + } + + g_free (x_str); + g_free (y_str); + } + } + + g_object_unref (data_input); + + g_object_freeze_notify (G_OBJECT (config)); + + for (i = 0; i < 5; i++) + { + GimpCurve *curve = config->curve[i]; + + gimp_data_freeze (GIMP_DATA (curve)); + + gimp_curve_set_curve_type (curve, GIMP_CURVE_SMOOTH); + gimp_curve_clear_points (curve); + + for (j = 0; j < GIMP_CURVE_N_CRUFT_POINTS; j++) + { + gdouble x; + gdouble y; + + x = (gdouble) index[i][j] / 255.0; + y = (gdouble) value[i][j] / 255.0; + + if (x >= 0.0) + gimp_curve_add_point (curve, x, y); + } + + gimp_data_thaw (GIMP_DATA (curve)); + } + + config->linear = FALSE; + + g_object_notify (G_OBJECT (config), "linear"); + + g_object_thaw_notify (G_OBJECT (config)); + + return TRUE; +} + +gboolean +gimp_curves_config_save_cruft (GimpCurvesConfig *config, + GOutputStream *output, + GError **error) +{ + GString *string; + gint i; + + g_return_val_if_fail (GIMP_IS_CURVES_CONFIG (config), FALSE); + g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + string = g_string_new ("# GIMP Curves File\n"); + + for (i = 0; i < 5; i++) + { + GimpCurve *curve = config->curve[i]; + gint j; + + if (curve->curve_type == GIMP_CURVE_SMOOTH) + { + g_object_ref (curve); + } + else + { + curve = GIMP_CURVE (gimp_data_duplicate (GIMP_DATA (curve))); + + gimp_curve_set_curve_type (curve, GIMP_CURVE_SMOOTH); + } + + for (j = 0; j < GIMP_CURVE_N_CRUFT_POINTS; j++) + { + gint x = -1; + gint y = -1; + + if (j < gimp_curve_get_n_points (curve)) + { + gdouble point_x; + gdouble point_y; + + gimp_curve_get_point (curve, j, &point_x, &point_y); + + x = floor (point_x * 255.999); + y = floor (point_y * 255.999); + } + + g_string_append_printf (string, "%d %d ", x, y); + } + + g_string_append_printf (string, "\n"); + + g_object_unref (curve); + } + + if (! g_output_stream_write_all (output, string->str, string->len, + NULL, NULL, error)) + { + g_prefix_error (error, _("Writing curves file failed: ")); + g_string_free (string, TRUE); + return FALSE; + } + + g_string_free (string, TRUE); + + return TRUE; +} diff --git a/app/operations/gimpcurvesconfig.h b/app/operations/gimpcurvesconfig.h new file mode 100644 index 0000000..c6241fe --- /dev/null +++ b/app/operations/gimpcurvesconfig.h @@ -0,0 +1,81 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpcurvesconfig.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_CURVES_CONFIG_H__ +#define __GIMP_CURVES_CONFIG_H__ + + +#include "gimpoperationsettings.h" + + +#define GIMP_TYPE_CURVES_CONFIG (gimp_curves_config_get_type ()) +#define GIMP_CURVES_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_CURVES_CONFIG, GimpCurvesConfig)) +#define GIMP_CURVES_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_CURVES_CONFIG, GimpCurvesConfigClass)) +#define GIMP_IS_CURVES_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_CURVES_CONFIG)) +#define GIMP_IS_CURVES_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_CURVES_CONFIG)) +#define GIMP_CURVES_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_CURVES_CONFIG, GimpCurvesConfigClass)) + + +typedef struct _GimpCurvesConfigClass GimpCurvesConfigClass; + +struct _GimpCurvesConfig +{ + GimpOperationSettings parent_instance; + + gboolean linear; + + GimpHistogramChannel channel; + + GimpCurve *curve[5]; +}; + +struct _GimpCurvesConfigClass +{ + GimpOperationSettingsClass parent_class; +}; + + +GType gimp_curves_config_get_type (void) G_GNUC_CONST; + +GObject * gimp_curves_config_new_spline (gint32 channel, + const gdouble *points, + gint n_points); +GObject * gimp_curves_config_new_explicit (gint32 channel, + const gdouble *samples, + gint n_samples); + +GObject * gimp_curves_config_new_spline_cruft (gint32 channel, + const guint8 *points, + gint n_points); +GObject * gimp_curves_config_new_explicit_cruft (gint32 channel, + const guint8 *samples, + gint n_samples); + +void gimp_curves_config_reset_channel (GimpCurvesConfig *config); + +gboolean gimp_curves_config_load_cruft (GimpCurvesConfig *config, + GInputStream *input, + GError **error); +gboolean gimp_curves_config_save_cruft (GimpCurvesConfig *config, + GOutputStream *output, + GError **error); + + +#endif /* __GIMP_CURVES_CONFIG_H__ */ diff --git a/app/operations/gimphuesaturationconfig.c b/app/operations/gimphuesaturationconfig.c new file mode 100644 index 0000000..4f0a397 --- /dev/null +++ b/app/operations/gimphuesaturationconfig.c @@ -0,0 +1,367 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimphuesaturationconfig.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "gimphuesaturationconfig.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_RANGE, + PROP_HUE, + PROP_SATURATION, + PROP_LIGHTNESS, + PROP_OVERLAP +}; + + +static void gimp_hue_saturation_config_iface_init (GimpConfigInterface *iface); + +static void gimp_hue_saturation_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_hue_saturation_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gboolean gimp_hue_saturation_config_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data); +static gboolean gimp_hue_saturation_config_deserialize (GimpConfig *config, + GScanner *scanner, + gint nest_level, + gpointer data); +static gboolean gimp_hue_saturation_config_equal (GimpConfig *a, + GimpConfig *b); +static void gimp_hue_saturation_config_reset (GimpConfig *config); +static gboolean gimp_hue_saturation_config_copy (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags); + + +G_DEFINE_TYPE_WITH_CODE (GimpHueSaturationConfig, gimp_hue_saturation_config, + GIMP_TYPE_OPERATION_SETTINGS, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, + gimp_hue_saturation_config_iface_init)) + +#define parent_class gimp_hue_saturation_config_parent_class + + +static void +gimp_hue_saturation_config_class_init (GimpHueSaturationConfigClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + + object_class->set_property = gimp_hue_saturation_config_set_property; + object_class->get_property = gimp_hue_saturation_config_get_property; + + viewable_class->default_icon_name = "gimp-tool-hue-saturation"; + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_RANGE, + "range", + _("Range"), + _("The affected range"), + GIMP_TYPE_HUE_RANGE, + GIMP_HUE_RANGE_ALL, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_HUE, + "hue", + _("Hue"), + _("Hue"), + -1.0, 1.0, 0.0, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_SATURATION, + "saturation", + _("Saturation"), + _("Saturation"), + -1.0, 1.0, 0.0, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LIGHTNESS, + "lightness", + _("Lightness"), + _("Lightness"), + -1.0, 1.0, 0.0, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_OVERLAP, + "overlap", + _("Overlap"), + _("Overlap"), + 0.0, 1.0, 0.0, 0); +} + +static void +gimp_hue_saturation_config_iface_init (GimpConfigInterface *iface) +{ + iface->serialize = gimp_hue_saturation_config_serialize; + iface->deserialize = gimp_hue_saturation_config_deserialize; + iface->equal = gimp_hue_saturation_config_equal; + iface->reset = gimp_hue_saturation_config_reset; + iface->copy = gimp_hue_saturation_config_copy; +} + +static void +gimp_hue_saturation_config_init (GimpHueSaturationConfig *self) +{ + gimp_config_reset (GIMP_CONFIG (self)); +} + +static void +gimp_hue_saturation_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpHueSaturationConfig *self = GIMP_HUE_SATURATION_CONFIG (object); + + switch (property_id) + { + case PROP_RANGE: + g_value_set_enum (value, self->range); + break; + + case PROP_HUE: + g_value_set_double (value, self->hue[self->range]); + break; + + case PROP_SATURATION: + g_value_set_double (value, self->saturation[self->range]); + break; + + case PROP_LIGHTNESS: + g_value_set_double (value, self->lightness[self->range]); + break; + + case PROP_OVERLAP: + g_value_set_double (value, self->overlap); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_hue_saturation_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpHueSaturationConfig *self = GIMP_HUE_SATURATION_CONFIG (object); + + switch (property_id) + { + case PROP_RANGE: + self->range = g_value_get_enum (value); + g_object_notify (object, "hue"); + g_object_notify (object, "saturation"); + g_object_notify (object, "lightness"); + break; + + case PROP_HUE: + self->hue[self->range] = g_value_get_double (value); + break; + + case PROP_SATURATION: + self->saturation[self->range] = g_value_get_double (value); + break; + + case PROP_LIGHTNESS: + self->lightness[self->range] = g_value_get_double (value); + break; + + case PROP_OVERLAP: + self->overlap = g_value_get_double (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gboolean +gimp_hue_saturation_config_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data) +{ + GimpHueSaturationConfig *hs_config = GIMP_HUE_SATURATION_CONFIG (config); + GimpHueRange range; + GimpHueRange old_range; + gboolean success = TRUE; + + if (! gimp_operation_settings_config_serialize_base (config, writer, data)) + return FALSE; + + old_range = hs_config->range; + + for (range = GIMP_HUE_RANGE_ALL; range <= GIMP_HUE_RANGE_MAGENTA; range++) + { + hs_config->range = range; + + success = (gimp_config_serialize_property_by_name (config, "range", + writer) && + gimp_config_serialize_property_by_name (config, "hue", + writer) && + gimp_config_serialize_property_by_name (config, "saturation", + writer) && + gimp_config_serialize_property_by_name (config, "lightness", + writer)); + + if (! success) + break; + } + + if (success) + success = gimp_config_serialize_property_by_name (config, "overlap", + writer); + + hs_config->range = old_range; + + return success; +} + +static gboolean +gimp_hue_saturation_config_deserialize (GimpConfig *config, + GScanner *scanner, + gint nest_level, + gpointer data) +{ + GimpHueSaturationConfig *hs_config = GIMP_HUE_SATURATION_CONFIG (config); + GimpHueRange old_range; + gboolean success = TRUE; + + old_range = hs_config->range; + + success = gimp_config_deserialize_properties (config, scanner, nest_level); + + g_object_set (config, "range", old_range, NULL); + + return success; +} + +static gboolean +gimp_hue_saturation_config_equal (GimpConfig *a, + GimpConfig *b) +{ + GimpHueSaturationConfig *config_a = GIMP_HUE_SATURATION_CONFIG (a); + GimpHueSaturationConfig *config_b = GIMP_HUE_SATURATION_CONFIG (b); + GimpHueRange range; + + if (! gimp_operation_settings_config_equal_base (a, b)) + return FALSE; + + for (range = GIMP_HUE_RANGE_ALL; range <= GIMP_HUE_RANGE_MAGENTA; range++) + { + if (config_a->hue[range] != config_b->hue[range] || + config_a->saturation[range] != config_b->saturation[range] || + config_a->lightness[range] != config_b->lightness[range]) + return FALSE; + } + + /* don't compare "range" */ + + if (config_a->overlap != config_b->overlap) + return FALSE; + + return TRUE; +} + +static void +gimp_hue_saturation_config_reset (GimpConfig *config) +{ + GimpHueSaturationConfig *hs_config = GIMP_HUE_SATURATION_CONFIG (config); + GimpHueRange range; + + gimp_operation_settings_config_reset_base (config); + + for (range = GIMP_HUE_RANGE_ALL; range <= GIMP_HUE_RANGE_MAGENTA; range++) + { + hs_config->range = range; + gimp_hue_saturation_config_reset_range (hs_config); + } + + gimp_config_reset_property (G_OBJECT (config), "range"); + gimp_config_reset_property (G_OBJECT (config), "overlap"); +} + +static gboolean +gimp_hue_saturation_config_copy (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags) +{ + GimpHueSaturationConfig *src_config = GIMP_HUE_SATURATION_CONFIG (src); + GimpHueSaturationConfig *dest_config = GIMP_HUE_SATURATION_CONFIG (dest); + GimpHueRange range; + + if (! gimp_operation_settings_config_copy_base (src, dest, flags)) + return FALSE; + + for (range = GIMP_HUE_RANGE_ALL; range <= GIMP_HUE_RANGE_MAGENTA; range++) + { + dest_config->hue[range] = src_config->hue[range]; + dest_config->saturation[range] = src_config->saturation[range]; + dest_config->lightness[range] = src_config->lightness[range]; + } + + g_object_notify (G_OBJECT (dest), "hue"); + g_object_notify (G_OBJECT (dest), "saturation"); + g_object_notify (G_OBJECT (dest), "lightness"); + + dest_config->range = src_config->range; + dest_config->overlap = src_config->overlap; + + g_object_notify (G_OBJECT (dest), "range"); + g_object_notify (G_OBJECT (dest), "overlap"); + + return TRUE; +} + + +/* public functions */ + +void +gimp_hue_saturation_config_reset_range (GimpHueSaturationConfig *config) +{ + g_return_if_fail (GIMP_IS_HUE_SATURATION_CONFIG (config)); + + g_object_freeze_notify (G_OBJECT (config)); + + gimp_config_reset_property (G_OBJECT (config), "hue"); + gimp_config_reset_property (G_OBJECT (config), "saturation"); + gimp_config_reset_property (G_OBJECT (config), "lightness"); + + g_object_thaw_notify (G_OBJECT (config)); +} diff --git a/app/operations/gimphuesaturationconfig.h b/app/operations/gimphuesaturationconfig.h new file mode 100644 index 0000000..151ac05 --- /dev/null +++ b/app/operations/gimphuesaturationconfig.h @@ -0,0 +1,62 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimphuesaturationconfig.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_HUE_SATURATION_CONFIG_H__ +#define __GIMP_HUE_SATURATION_CONFIG_H__ + + +#include "gimpoperationsettings.h" + + +#define GIMP_TYPE_HUE_SATURATION_CONFIG (gimp_hue_saturation_config_get_type ()) +#define GIMP_HUE_SATURATION_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_HUE_SATURATION_CONFIG, GimpHueSaturationConfig)) +#define GIMP_HUE_SATURATION_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_HUE_SATURATION_CONFIG, GimpHueSaturationConfigClass)) +#define GIMP_IS_HUE_SATURATION_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_HUE_SATURATION_CONFIG)) +#define GIMP_IS_HUE_SATURATION_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_HUE_SATURATION_CONFIG)) +#define GIMP_HUE_SATURATION_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_HUE_SATURATION_CONFIG, GimpHueSaturationConfigClass)) + + +typedef struct _GimpHueSaturationConfigClass GimpHueSaturationConfigClass; + +struct _GimpHueSaturationConfig +{ + GimpOperationSettings parent_instance; + + GimpHueRange range; + + gdouble hue[7]; + gdouble saturation[7]; + gdouble lightness[7]; + + gdouble overlap; +}; + +struct _GimpHueSaturationConfigClass +{ + GimpOperationSettingsClass parent_class; +}; + + +GType gimp_hue_saturation_config_get_type (void) G_GNUC_CONST; + +void gimp_hue_saturation_config_reset_range (GimpHueSaturationConfig *config); + + +#endif /* __GIMP_HUE_SATURATION_CONFIG_H__ */ diff --git a/app/operations/gimplevelsconfig.c b/app/operations/gimplevelsconfig.c new file mode 100644 index 0000000..df5d349 --- /dev/null +++ b/app/operations/gimplevelsconfig.c @@ -0,0 +1,964 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimplevelsconfig.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <errno.h> + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpbase/gimpbase.h" +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "core/gimp-utils.h" +#include "core/gimpcurve.h" +#include "core/gimphistogram.h" + +#include "gimpcurvesconfig.h" +#include "gimplevelsconfig.h" +#include "gimpoperationlevels.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_LINEAR, + PROP_CHANNEL, + PROP_LOW_INPUT, + PROP_HIGH_INPUT, + PROP_CLAMP_INPUT, + PROP_GAMMA, + PROP_LOW_OUTPUT, + PROP_HIGH_OUTPUT, + PROP_CLAMP_OUTPUT +}; + + +static void gimp_levels_config_iface_init (GimpConfigInterface *iface); + +static void gimp_levels_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_levels_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gboolean gimp_levels_config_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data); +static gboolean gimp_levels_config_deserialize (GimpConfig *config, + GScanner *scanner, + gint nest_level, + gpointer data); +static gboolean gimp_levels_config_equal (GimpConfig *a, + GimpConfig *b); +static void gimp_levels_config_reset (GimpConfig *config); +static gboolean gimp_levels_config_copy (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags); + + +G_DEFINE_TYPE_WITH_CODE (GimpLevelsConfig, gimp_levels_config, + GIMP_TYPE_OPERATION_SETTINGS, + G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG, + gimp_levels_config_iface_init)) + +#define parent_class gimp_levels_config_parent_class + + +static void +gimp_levels_config_class_init (GimpLevelsConfigClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GimpViewableClass *viewable_class = GIMP_VIEWABLE_CLASS (klass); + + object_class->set_property = gimp_levels_config_set_property; + object_class->get_property = gimp_levels_config_get_property; + + viewable_class->default_icon_name = "gimp-tool-levels"; + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_LINEAR, + "linear", + _("Linear"), + _("Work on linear RGB"), + FALSE, 0); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_CHANNEL, + "channel", + _("Channel"), + _("The affected channel"), + GIMP_TYPE_HISTOGRAM_CHANNEL, + GIMP_HISTOGRAM_VALUE, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LOW_INPUT, + "low-input", + _("Low Input"), + _("Low Input"), + 0.0, 1.0, 0.0, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_HIGH_INPUT, + "high-input", + _("High Input"), + _("High Input"), + 0.0, 1.0, 1.0, 0); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_CLAMP_INPUT, + "clamp-input", + _("Clamp Input"), + _("Clamp input values before applying output mapping."), + FALSE, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_GAMMA, + "gamma", + _("Gamma"), + _("Gamma"), + 0.1, 10.0, 1.0, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LOW_OUTPUT, + "low-output", + _("Low Output"), + _("Low Output"), + 0.0, 1.0, 0.0, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_HIGH_OUTPUT, + "high-output", + _("High Output"), + _("High Output"), + 0.0, 1.0, 1.0, 0); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_CLAMP_OUTPUT, + "clamp-output", + _("Clamp Output"), + _("Clamp final output values."), + FALSE, 0); +} + +static void +gimp_levels_config_iface_init (GimpConfigInterface *iface) +{ + iface->serialize = gimp_levels_config_serialize; + iface->deserialize = gimp_levels_config_deserialize; + iface->equal = gimp_levels_config_equal; + iface->reset = gimp_levels_config_reset; + iface->copy = gimp_levels_config_copy; +} + +static void +gimp_levels_config_init (GimpLevelsConfig *self) +{ + gimp_config_reset (GIMP_CONFIG (self)); +} + +static void +gimp_levels_config_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpLevelsConfig *self = GIMP_LEVELS_CONFIG (object); + + switch (property_id) + { + case PROP_LINEAR: + g_value_set_boolean (value, self->linear); + break; + + case PROP_CHANNEL: + g_value_set_enum (value, self->channel); + break; + + case PROP_LOW_INPUT: + g_value_set_double (value, self->low_input[self->channel]); + break; + + case PROP_HIGH_INPUT: + g_value_set_double (value, self->high_input[self->channel]); + break; + + case PROP_CLAMP_INPUT: + g_value_set_boolean (value, self->clamp_input); + break; + + case PROP_GAMMA: + g_value_set_double (value, self->gamma[self->channel]); + break; + + case PROP_LOW_OUTPUT: + g_value_set_double (value, self->low_output[self->channel]); + break; + + case PROP_HIGH_OUTPUT: + g_value_set_double (value, self->high_output[self->channel]); + break; + + case PROP_CLAMP_OUTPUT: + g_value_set_boolean (value, self->clamp_output); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_levels_config_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpLevelsConfig *self = GIMP_LEVELS_CONFIG (object); + + switch (property_id) + { + case PROP_LINEAR: + self->linear = g_value_get_boolean (value); + break; + + case PROP_CHANNEL: + self->channel = g_value_get_enum (value); + g_object_notify (object, "low-input"); + g_object_notify (object, "high-input"); + g_object_notify (object, "gamma"); + g_object_notify (object, "low-output"); + g_object_notify (object, "high-output"); + break; + + case PROP_LOW_INPUT: + self->low_input[self->channel] = g_value_get_double (value); + break; + + case PROP_HIGH_INPUT: + self->high_input[self->channel] = g_value_get_double (value); + break; + + case PROP_CLAMP_INPUT: + self->clamp_input = g_value_get_boolean (value); + break; + + case PROP_GAMMA: + self->gamma[self->channel] = g_value_get_double (value); + break; + + case PROP_LOW_OUTPUT: + self->low_output[self->channel] = g_value_get_double (value); + break; + + case PROP_HIGH_OUTPUT: + self->high_output[self->channel] = g_value_get_double (value); + break; + + case PROP_CLAMP_OUTPUT: + self->clamp_output = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gboolean +gimp_levels_config_serialize (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data) +{ + GimpLevelsConfig *l_config = GIMP_LEVELS_CONFIG (config); + GimpHistogramChannel channel; + GimpHistogramChannel old_channel; + gboolean success = TRUE; + + if (! gimp_operation_settings_config_serialize_base (config, writer, data) || + ! gimp_config_serialize_property_by_name (config, "linear", writer) || + ! gimp_config_serialize_property_by_name (config, "clamp-input", writer) || + ! gimp_config_serialize_property_by_name (config, "clamp-output", writer)) + return FALSE; + + old_channel = l_config->channel; + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + l_config->channel = channel; + + /* serialize the channel properties manually (not using + * gimp_config_serialize_properties()), so the parent class' + * properties don't end up in the config file one per channel. + * See bug #700653. + */ + success = + (gimp_config_serialize_property_by_name (config, "channel", writer) && + gimp_config_serialize_property_by_name (config, "low-input", writer) && + gimp_config_serialize_property_by_name (config, "high-input", writer) && + gimp_config_serialize_property_by_name (config, "gamma", writer) && + gimp_config_serialize_property_by_name (config, "low-output", writer) && + gimp_config_serialize_property_by_name (config, "high-output", writer)); + + if (! success) + break; + } + + l_config->channel = old_channel; + + return success; +} + +static gboolean +gimp_levels_config_deserialize (GimpConfig *config, + GScanner *scanner, + gint nest_level, + gpointer data) +{ + GimpLevelsConfig *l_config = GIMP_LEVELS_CONFIG (config); + GimpHistogramChannel old_channel; + gboolean success = TRUE; + + old_channel = l_config->channel; + + success = gimp_config_deserialize_properties (config, scanner, nest_level); + + g_object_set (config, "channel", old_channel, NULL); + + return success; +} + +static gboolean +gimp_levels_config_equal (GimpConfig *a, + GimpConfig *b) +{ + GimpLevelsConfig *config_a = GIMP_LEVELS_CONFIG (a); + GimpLevelsConfig *config_b = GIMP_LEVELS_CONFIG (b); + GimpHistogramChannel channel; + + if (! gimp_operation_settings_config_equal_base (a, b) || + config_a->linear != config_b->linear || + config_a->clamp_input != config_b->clamp_input || + config_a->clamp_output != config_b->clamp_output) + return FALSE; + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + if (config_a->gamma[channel] != config_b->gamma[channel] || + config_a->low_input[channel] != config_b->low_input[channel] || + config_a->high_input[channel] != config_b->high_input[channel] || + config_a->low_output[channel] != config_b->low_output[channel] || + config_a->high_output[channel] != config_b->high_output[channel]) + return FALSE; + } + + /* don't compare "channel" */ + + return TRUE; +} + +static void +gimp_levels_config_reset (GimpConfig *config) +{ + GimpLevelsConfig *l_config = GIMP_LEVELS_CONFIG (config); + GimpHistogramChannel channel; + + gimp_operation_settings_config_reset_base (config); + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + l_config->channel = channel; + gimp_levels_config_reset_channel (l_config); + } + + gimp_config_reset_property (G_OBJECT (config), "linear"); + gimp_config_reset_property (G_OBJECT (config), "channel"); + gimp_config_reset_property (G_OBJECT (config), "clamp-input"); + gimp_config_reset_property (G_OBJECT (config), "clamp_output"); +} + +static gboolean +gimp_levels_config_copy (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags) +{ + GimpLevelsConfig *src_config = GIMP_LEVELS_CONFIG (src); + GimpLevelsConfig *dest_config = GIMP_LEVELS_CONFIG (dest); + GimpHistogramChannel channel; + + if (! gimp_operation_settings_config_copy_base (src, dest, flags)) + return FALSE; + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + dest_config->gamma[channel] = src_config->gamma[channel]; + dest_config->low_input[channel] = src_config->low_input[channel]; + dest_config->high_input[channel] = src_config->high_input[channel]; + dest_config->low_output[channel] = src_config->low_output[channel]; + dest_config->high_output[channel] = src_config->high_output[channel]; + } + + g_object_notify (G_OBJECT (dest), "gamma"); + g_object_notify (G_OBJECT (dest), "low-input"); + g_object_notify (G_OBJECT (dest), "high-input"); + g_object_notify (G_OBJECT (dest), "low-output"); + g_object_notify (G_OBJECT (dest), "high-output"); + + dest_config->linear = src_config->linear; + dest_config->channel = src_config->channel; + dest_config->clamp_input = src_config->clamp_input; + dest_config->clamp_output = src_config->clamp_output; + + g_object_notify (G_OBJECT (dest), "linear"); + g_object_notify (G_OBJECT (dest), "channel"); + g_object_notify (G_OBJECT (dest), "clamp-input"); + g_object_notify (G_OBJECT (dest), "clamp-output"); + + return TRUE; +} + + +/* public functions */ + +void +gimp_levels_config_reset_channel (GimpLevelsConfig *config) +{ + g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); + + g_object_freeze_notify (G_OBJECT (config)); + + gimp_config_reset_property (G_OBJECT (config), "gamma"); + gimp_config_reset_property (G_OBJECT (config), "low-input"); + gimp_config_reset_property (G_OBJECT (config), "high-input"); + gimp_config_reset_property (G_OBJECT (config), "low-output"); + gimp_config_reset_property (G_OBJECT (config), "high-output"); + + g_object_thaw_notify (G_OBJECT (config)); +} + +void +gimp_levels_config_stretch (GimpLevelsConfig *config, + GimpHistogram *histogram, + gboolean is_color) +{ + g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); + g_return_if_fail (histogram != NULL); + + g_object_freeze_notify (G_OBJECT (config)); + + if (is_color) + { + GimpHistogramChannel channel; + + /* Set the overall value to defaults */ + channel = config->channel; + config->channel = GIMP_HISTOGRAM_VALUE; + gimp_levels_config_reset_channel (config); + config->channel = channel; + + for (channel = GIMP_HISTOGRAM_RED; + channel <= GIMP_HISTOGRAM_BLUE; + channel++) + { + gimp_levels_config_stretch_channel (config, histogram, channel); + } + } + else + { + gimp_levels_config_stretch_channel (config, histogram, + GIMP_HISTOGRAM_VALUE); + } + + g_object_thaw_notify (G_OBJECT (config)); +} + +void +gimp_levels_config_stretch_channel (GimpLevelsConfig *config, + GimpHistogram *histogram, + GimpHistogramChannel channel) +{ + gdouble count; + gdouble bias = 0.006; + gint n_bins; + gint i; + + g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); + g_return_if_fail (histogram != NULL); + + g_object_freeze_notify (G_OBJECT (config)); + + config->gamma[channel] = 1.0; + config->low_output[channel] = 0.0; + config->high_output[channel] = 1.0; + + n_bins = gimp_histogram_n_bins (histogram); + count = gimp_histogram_get_count (histogram, channel, 0, n_bins - 1); + + if (count == 0.0) + { + config->low_input[channel] = 0.0; + config->high_input[channel] = 0.0; + } + else + { + gdouble new_count; + gdouble percentage; + gdouble next_percentage; + + /* Set the low input */ + new_count = 0.0; + + for (i = 0; i < (n_bins - 1); i++) + { + new_count += gimp_histogram_get_value (histogram, channel, i); + percentage = new_count / count; + next_percentage = (new_count + + gimp_histogram_get_value (histogram, + channel, + i + 1)) / count; + + if (fabs (percentage - bias) < fabs (next_percentage - bias)) + { + config->low_input[channel] = (gdouble) (i + 1) / (n_bins - 1); + break; + } + } + + /* Set the high input */ + new_count = 0.0; + + for (i = (n_bins - 1); i > 0; i--) + { + new_count += gimp_histogram_get_value (histogram, channel, i); + percentage = new_count / count; + next_percentage = (new_count + + gimp_histogram_get_value (histogram, + channel, + i - 1)) / count; + + if (fabs (percentage - bias) < fabs (next_percentage - bias)) + { + config->high_input[channel] = (gdouble) (i - 1) / (n_bins - 1); + break; + } + } + } + + g_object_notify (G_OBJECT (config), "gamma"); + g_object_notify (G_OBJECT (config), "low-input"); + g_object_notify (G_OBJECT (config), "high-input"); + g_object_notify (G_OBJECT (config), "low-output"); + g_object_notify (G_OBJECT (config), "high-output"); + + g_object_thaw_notify (G_OBJECT (config)); +} + +static gdouble +gimp_levels_config_input_from_color (GimpHistogramChannel channel, + const GimpRGB *color) +{ + switch (channel) + { + case GIMP_HISTOGRAM_VALUE: + return MAX (MAX (color->r, color->g), color->b); + + case GIMP_HISTOGRAM_RED: + return color->r; + + case GIMP_HISTOGRAM_GREEN: + return color->g; + + case GIMP_HISTOGRAM_BLUE: + return color->b; + + case GIMP_HISTOGRAM_ALPHA: + return color->a; + + case GIMP_HISTOGRAM_RGB: + return MIN (MIN (color->r, color->g), color->b); + + case GIMP_HISTOGRAM_LUMINANCE: + return GIMP_RGB_LUMINANCE (color->r, color->g, color->b); + } + + return 0.0; +} + +void +gimp_levels_config_adjust_by_colors (GimpLevelsConfig *config, + GimpHistogramChannel channel, + const GimpRGB *black, + const GimpRGB *gray, + const GimpRGB *white) +{ + g_return_if_fail (GIMP_IS_LEVELS_CONFIG (config)); + + g_object_freeze_notify (G_OBJECT (config)); + + if (black) + { + config->low_input[channel] = gimp_levels_config_input_from_color (channel, + black); + g_object_notify (G_OBJECT (config), "low-input"); + } + + + if (white) + { + config->high_input[channel] = gimp_levels_config_input_from_color (channel, + white); + g_object_notify (G_OBJECT (config), "high-input"); + } + + if (gray) + { + gdouble input; + gdouble range; + gdouble inten; + gdouble out_light; + gdouble lightness; + + /* Calculate lightness value */ + lightness = GIMP_RGB_LUMINANCE (gray->r, gray->g, gray->b); + + input = gimp_levels_config_input_from_color (channel, gray); + + range = config->high_input[channel] - config->low_input[channel]; + if (range <= 0) + goto out; + + input -= config->low_input[channel]; + if (input < 0) + goto out; + + /* Normalize input and lightness */ + inten = input / range; + out_light = lightness / range; + + /* See bug 622054: picking pure black or white as gamma doesn't + * work. But we cannot compare to 0.0 or 1.0 because cpus and + * compilers are shit. If you try to check out_light using + * printf() it will give exact 0.0 or 1.0 anyway, probably + * because the generated code is different and out_light doesn't + * live in a register. That must be why the cpu/compiler mafia + * invented epsilon and defined this shit to be the programmer's + * responsibility. + */ + if (out_light <= 0.0001 || out_light >= 0.9999) + goto out; + + /* Map selected color to corresponding lightness */ + config->gamma[channel] = log (inten) / log (out_light); + config->gamma[channel] = CLAMP (config->gamma[channel], 0.1, 10.0); + g_object_notify (G_OBJECT (config), "gamma"); + } + + out: + g_object_thaw_notify (G_OBJECT (config)); +} + +GimpCurvesConfig * +gimp_levels_config_to_curves_config (GimpLevelsConfig *config) +{ + GimpCurvesConfig *curves; + GimpHistogramChannel channel; + + g_return_val_if_fail (GIMP_IS_LEVELS_CONFIG (config), NULL); + + curves = g_object_new (GIMP_TYPE_CURVES_CONFIG, NULL); + + gimp_operation_settings_config_copy_base (GIMP_CONFIG (config), + GIMP_CONFIG (curves), + 0); + + curves->linear = config->linear; + + for (channel = GIMP_HISTOGRAM_VALUE; + channel <= GIMP_HISTOGRAM_ALPHA; + channel++) + { + GimpCurve *curve = curves->curve[channel]; + static const gint n = 8; + gdouble gamma = config->gamma[channel]; + gdouble delta_in; + gdouble delta_out; + gdouble x, y; + + /* clear the points set by default */ + gimp_curve_clear_points (curve); + + delta_in = config->high_input[channel] - config->low_input[channel]; + delta_out = config->high_output[channel] - config->low_output[channel]; + + x = config->low_input[channel]; + y = config->low_output[channel]; + + gimp_curve_add_point (curve, x, y); + + if (delta_out != 0 && gamma != 1.0) + { + /* The Levels tool performs gamma adjustment, which is a + * power law, while the Curves tool uses cubic Bézier + * curves. Here we try to approximate this gamma adjustment + * with a Bézier curve with 5 control points. Two of them + * must be (low_input, low_output) and (high_input, + * high_output), so we need to add 3 more control points in + * the middle. + */ + gint i; + + if (gamma > 1) + { + /* Case no. 1: γ > 1 + * + * The curve should look like a horizontal + * parabola. Since its curvature is greatest when x is + * small, we add more control points there, so the + * approximation is more accurate. I decided to set the + * length of the consecutive segments to x₀, γ⋅x₀, γ²⋅x₀ + * and γ³⋅x₀ and I saw that the curves looked + * good. Still, this is completely arbitrary. + */ + gdouble dx = 0; + gdouble x0; + + for (i = 0; i < n; ++i) + dx = dx * gamma + 1; + x0 = delta_in / dx; + + dx = 0; + for (i = 1; i < n; ++i) + { + dx = dx * gamma + x0; + x = config->low_input[channel] + dx; + y = config->low_output[channel] + delta_out * + gimp_operation_levels_map_input (config, channel, x); + gimp_curve_add_point (curve, x, y); + } + } + else + { + /* Case no. 2: γ < 1 + * + * The curve is the same as the one in case no. 1, + * observed through a reflexion along the y = x axis. So + * if we invert γ and swap the x and y axes we can use + * the same method as in case no. 1. + */ + GimpLevelsConfig *config_inv; + gdouble dy = 0; + gdouble y0; + const gdouble gamma_inv = 1 / gamma; + + config_inv = gimp_config_duplicate (GIMP_CONFIG (config)); + + config_inv->gamma[channel] = gamma_inv; + config_inv->low_input[channel] = config->low_output[channel]; + config_inv->low_output[channel] = config->low_input[channel]; + config_inv->high_input[channel] = config->high_output[channel]; + config_inv->high_output[channel] = config->high_input[channel]; + + for (i = 0; i < n; ++i) + dy = dy * gamma_inv + 1; + y0 = delta_out / dy; + + dy = 0; + for (i = 1; i < n; ++i) + { + dy = dy * gamma_inv + y0; + y = config->low_output[channel] + dy; + x = config->low_input[channel] + delta_in * + gimp_operation_levels_map_input (config_inv, channel, y); + gimp_curve_add_point (curve, x, y); + } + + g_object_unref (config_inv); + } + } + + x = config->high_input[channel]; + y = config->high_output[channel]; + + gimp_curve_add_point (curve, x, y); + } + + return curves; +} + +gboolean +gimp_levels_config_load_cruft (GimpLevelsConfig *config, + GInputStream *input, + GError **error) +{ + GDataInputStream *data_input; + gint low_input[5]; + gint high_input[5]; + gint low_output[5]; + gint high_output[5]; + gdouble gamma[5]; + gchar *line; + gsize line_len; + gint i; + + g_return_val_if_fail (GIMP_IS_LEVELS_CONFIG (config), FALSE); + g_return_val_if_fail (G_IS_INPUT_STREAM (input), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + data_input = g_data_input_stream_new (input); + + line_len = 64; + line = gimp_data_input_stream_read_line_always (data_input, &line_len, + NULL, error); + if (! line) + return FALSE; + + if (strcmp (line, "# GIMP Levels File") != 0) + { + g_set_error_literal (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE, + _("not a GIMP Levels file")); + g_object_unref (data_input); + g_free (line); + return FALSE; + } + + g_free (line); + + for (i = 0; i < 5; i++) + { + gchar float_buf[32]; + gchar *endp; + gint fields; + + line_len = 64; + line = gimp_data_input_stream_read_line_always (data_input, &line_len, + NULL, error); + if (! line) + { + g_object_unref (data_input); + return FALSE; + } + + fields = sscanf (line, "%d %d %d %d %31s", + &low_input[i], + &high_input[i], + &low_output[i], + &high_output[i], + float_buf); + + g_free (line); + + if (fields != 5) + goto error; + + gamma[i] = g_ascii_strtod (float_buf, &endp); + + if (endp == float_buf || errno == ERANGE) + goto error; + } + + g_object_unref (data_input); + + g_object_freeze_notify (G_OBJECT (config)); + + for (i = 0; i < 5; i++) + { + config->low_input[i] = low_input[i] / 255.0; + config->high_input[i] = high_input[i] / 255.0; + config->gamma[i] = gamma[i]; + config->low_output[i] = low_output[i] / 255.0; + config->high_output[i] = high_output[i] / 255.0; + } + + config->linear = FALSE; + config->clamp_input = TRUE; + config->clamp_output = TRUE; + + g_object_notify (G_OBJECT (config), "linear"); + g_object_notify (G_OBJECT (config), "low-input"); + g_object_notify (G_OBJECT (config), "high-input"); + g_object_notify (G_OBJECT (config), "clamp-input"); + g_object_notify (G_OBJECT (config), "gamma"); + g_object_notify (G_OBJECT (config), "low-output"); + g_object_notify (G_OBJECT (config), "high-output"); + g_object_notify (G_OBJECT (config), "clamp-output"); + + g_object_thaw_notify (G_OBJECT (config)); + + return TRUE; + + error: + g_object_unref (data_input); + + g_set_error_literal (error, GIMP_CONFIG_ERROR, GIMP_CONFIG_ERROR_PARSE, + _("parse error")); + return FALSE; +} + +gboolean +gimp_levels_config_save_cruft (GimpLevelsConfig *config, + GOutputStream *output, + GError **error) +{ + GString *string; + gint i; + + g_return_val_if_fail (GIMP_IS_LEVELS_CONFIG (config), FALSE); + g_return_val_if_fail (G_IS_OUTPUT_STREAM (output), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + string = g_string_new ("# GIMP Levels File\n"); + + for (i = 0; i < 5; i++) + { + gchar buf[G_ASCII_DTOSTR_BUF_SIZE]; + + g_string_append_printf (string, + "%d %d %d %d %s\n", + (gint) (config->low_input[i] * 255.999), + (gint) (config->high_input[i] * 255.999), + (gint) (config->low_output[i] * 255.999), + (gint) (config->high_output[i] * 255.999), + g_ascii_dtostr (buf, G_ASCII_DTOSTR_BUF_SIZE, + config->gamma[i])); + } + + if (! g_output_stream_write_all (output, string->str, string->len, + NULL, NULL, error)) + { + g_prefix_error (error, _("Writing levels file failed: ")); + g_string_free (string, TRUE); + return FALSE; + } + + g_string_free (string, TRUE); + + return TRUE; +} diff --git a/app/operations/gimplevelsconfig.h b/app/operations/gimplevelsconfig.h new file mode 100644 index 0000000..2e7569c --- /dev/null +++ b/app/operations/gimplevelsconfig.h @@ -0,0 +1,92 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimplevelsconfig.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_LEVELS_CONFIG_H__ +#define __GIMP_LEVELS_CONFIG_H__ + + +#include "gimpoperationsettings.h" + + +#define GIMP_TYPE_LEVELS_CONFIG (gimp_levels_config_get_type ()) +#define GIMP_LEVELS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_LEVELS_CONFIG, GimpLevelsConfig)) +#define GIMP_LEVELS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_LEVELS_CONFIG, GimpLevelsConfigClass)) +#define GIMP_IS_LEVELS_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_LEVELS_CONFIG)) +#define GIMP_IS_LEVELS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_LEVELS_CONFIG)) +#define GIMP_LEVELS_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_LEVELS_CONFIG, GimpLevelsConfigClass)) + + +typedef struct _GimpLevelsConfigClass GimpLevelsConfigClass; + +struct _GimpLevelsConfig +{ + GimpOperationSettings parent_instance; + + gboolean linear; + + GimpHistogramChannel channel; + + gdouble low_input[5]; + gdouble high_input[5]; + + gboolean clamp_input; + + gdouble gamma[5]; + + gdouble low_output[5]; + gdouble high_output[5]; + + gboolean clamp_output; +}; + +struct _GimpLevelsConfigClass +{ + GimpOperationSettingsClass parent_class; +}; + + +GType gimp_levels_config_get_type (void) G_GNUC_CONST; + +void gimp_levels_config_reset_channel (GimpLevelsConfig *config); + +void gimp_levels_config_stretch (GimpLevelsConfig *config, + GimpHistogram *histogram, + gboolean is_color); +void gimp_levels_config_stretch_channel (GimpLevelsConfig *config, + GimpHistogram *histogram, + GimpHistogramChannel channel); +void gimp_levels_config_adjust_by_colors (GimpLevelsConfig *config, + GimpHistogramChannel channel, + const GimpRGB *black, + const GimpRGB *gray, + const GimpRGB *white); + +GimpCurvesConfig * + gimp_levels_config_to_curves_config (GimpLevelsConfig *config); + +gboolean gimp_levels_config_load_cruft (GimpLevelsConfig *config, + GInputStream *input, + GError **error); +gboolean gimp_levels_config_save_cruft (GimpLevelsConfig *config, + GOutputStream *output, + GError **error); + + +#endif /* __GIMP_LEVELS_CONFIG_H__ */ diff --git a/app/operations/gimpoperationborder.c b/app/operations/gimpoperationborder.c new file mode 100644 index 0000000..e08481c --- /dev/null +++ b/app/operations/gimpoperationborder.c @@ -0,0 +1,748 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationborder.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimpoperationborder.h" + + +enum +{ + PROP_0, + PROP_RADIUS_X, + PROP_RADIUS_Y, + PROP_FEATHER, + PROP_EDGE_LOCK +}; + + +static void gimp_operation_border_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_border_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static GeglRectangle +gimp_operation_border_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi); +static GeglRectangle + gimp_operation_border_get_cached_region (GeglOperation *self, + const GeglRectangle *roi); +static void gimp_operation_border_prepare (GeglOperation *operation); +static gboolean gimp_operation_border_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationBorder, gimp_operation_border, + GEGL_TYPE_OPERATION_FILTER) + +#define parent_class gimp_operation_border_parent_class + + +static void +gimp_operation_border_class_init (GimpOperationBorderClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_border_set_property; + object_class->get_property = gimp_operation_border_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:border", + "categories", "gimp", + "description", "GIMP Border operation", + NULL); + + operation_class->prepare = gimp_operation_border_prepare; + operation_class->get_required_for_output = gimp_operation_border_get_required_for_output; + operation_class->get_cached_region = gimp_operation_border_get_cached_region; + operation_class->threaded = FALSE; + + filter_class->process = gimp_operation_border_process; + + g_object_class_install_property (object_class, PROP_RADIUS_X, + g_param_spec_int ("radius-x", + "Radius X", + "Border radius in X diection", + 1, 2342, 1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_RADIUS_Y, + g_param_spec_int ("radius-y", + "Radius Y", + "Border radius in Y diection", + 1, 2342, 1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_FEATHER, + g_param_spec_boolean ("feather", + "Feather", + "Feather the border", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_EDGE_LOCK, + g_param_spec_boolean ("edge-lock", + "Edge Lock", + "Shrink from border", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_border_init (GimpOperationBorder *self) +{ +} + +static void +gimp_operation_border_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationBorder *self = GIMP_OPERATION_BORDER (object); + + switch (property_id) + { + case PROP_RADIUS_X: + g_value_set_int (value, self->radius_x); + break; + + case PROP_RADIUS_Y: + g_value_set_int (value, self->radius_y); + break; + + case PROP_FEATHER: + g_value_set_boolean (value, self->feather); + break; + + case PROP_EDGE_LOCK: + g_value_set_boolean (value, self->edge_lock); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_border_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationBorder *self = GIMP_OPERATION_BORDER (object); + + switch (property_id) + { + case PROP_RADIUS_X: + self->radius_x = g_value_get_int (value); + break; + + case PROP_RADIUS_Y: + self->radius_y = g_value_get_int (value); + break; + + case PROP_FEATHER: + self->feather = g_value_get_boolean (value); + break; + + case PROP_EDGE_LOCK: + self->edge_lock = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_border_prepare (GeglOperation *operation) +{ + const Babl *space = gegl_operation_get_source_space (operation, "input"); + gegl_operation_set_format (operation, "input", babl_format_with_space ("Y float", space)); + gegl_operation_set_format (operation, "output", babl_format_with_space ("Y float", space)); +} + +static GeglRectangle +gimp_operation_border_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi) +{ + return *gegl_operation_source_get_bounding_box (self, "input"); +} + +static GeglRectangle +gimp_operation_border_get_cached_region (GeglOperation *self, + const GeglRectangle *roi) +{ + return *gegl_operation_source_get_bounding_box (self, "input"); +} + +static inline void +rotate_pointers (gfloat **p, + guint32 n) +{ + guint32 i; + gfloat *tmp; + + tmp = p[0]; + + for (i = 0; i < n - 1; i++) + p[i] = p[i + 1]; + + p[i] = tmp; +} + +/* Computes whether pixels in `buf[1]', if they are selected, have neighbouring + pixels that are unselected. Put result in `transition'. */ +static void +compute_transition (gfloat *transition, + gfloat **buf, + gint32 width, + gboolean edge_lock) +{ + register gint32 x = 0; + + if (width == 1) + { + if (buf[1][0] >= 0.5 && (buf[0][0] < 0.5 || buf[2][0] < 0.5)) + transition[0] = 1.0; + else + transition[0] = 0.0; + return; + } + + if (buf[1][0] >= 0.5 && edge_lock) + { + /* The pixel to the left (outside of the canvas) is considered selected, + so we check if there are any unselected pixels in neighbouring pixels + _on_ the canvas. */ + if (buf[0][x] < 0.5 || buf[0][x + 1] < 0.5 || + buf[1][x + 1] < 0.5 || + buf[2][x] < 0.5 || buf[2][x + 1] < 0.5 ) + { + transition[x] = 1.0; + } + else + { + transition[x] = 0.0; + } + } + else if (buf[1][0] >= 0.5 && !edge_lock) + { + /* We must not care about neighbouring pixels on the image canvas since + there always are unselected pixels to the left (which is outside of + the image canvas). */ + transition[x] = 1.0; + } + else + { + transition[x] = 0.0; + } + + for (x = 1; x < width - 1; x++) + { + if (buf[1][x] >= 0.5) + { + if (buf[0][x - 1] < 0.5 || buf[0][x] < 0.5 || buf[0][x + 1] < 0.5 || + buf[1][x - 1] < 0.5 || buf[1][x + 1] < 0.5 || + buf[2][x - 1] < 0.5 || buf[2][x] < 0.5 || buf[2][x + 1] < 0.5) + transition[x] = 1.0; + else + transition[x] = 0.0; + } + else + { + transition[x] = 0.0; + } + } + + if (buf[1][width - 1] >= 0.5 && edge_lock) + { + /* The pixel to the right (outside of the canvas) is considered selected, + so we check if there are any unselected pixels in neighbouring pixels + _on_ the canvas. */ + if ( buf[0][x - 1] < 0.5 || buf[0][x] < 0.5 || + buf[1][x - 1] < 0.5 || + buf[2][x - 1] < 0.5 || buf[2][x] < 0.5) + { + transition[width - 1] = 1.0; + } + else + { + transition[width - 1] = 0.0; + } + } + else if (buf[1][width - 1] >= 0.5 && !edge_lock) + { + /* We must not care about neighbouring pixels on the image canvas since + there always are unselected pixels to the right (which is outside of + the image canvas). */ + transition[width - 1] = 1.0; + } + else + { + transition[width - 1] = 0.0; + } +} + +static gboolean +gimp_operation_border_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level) +{ + /* This function has no bugs, but if you imagine some you can blame + * them on jaycox@gimp.org + */ + GimpOperationBorder *self = GIMP_OPERATION_BORDER (operation); + const Babl *input_format = gegl_operation_get_format (operation, "input"); + const Babl *output_format = gegl_operation_get_format (operation, "output"); + + gint32 i, j, x, y; + + /* A cache used in the algorithm as it works its way down. `buf[1]' is the + current row. Thus, at algorithm initialization, `buf[0]' represents the + row 'above' the first row of the region. */ + gfloat *buf[3]; + + /* The resulting selection is calculated row by row, and this buffer holds the + output for each individual row, on each iteration. */ + gfloat *out; + + /* Keeps track of transitional pixels (pixels that are selected and have + unselected neighbouring pixels). */ + gfloat **transition; + + /* TODO: Figure out role clearly in algorithm. */ + gint16 *max; + + /* TODO: Figure out role clearly in algorithm. */ + gfloat **density; + + gint16 last_index; + + /* optimize this case specifically */ + if (self->radius_x == 1 && self->radius_y == 1) + { + gfloat *transition; + gfloat *source[3]; + + for (i = 0; i < 3; i++) + source[i] = g_new (gfloat, roi->width); + + transition = g_new (gfloat, roi->width); + + /* With `self->edge_lock', initialize row above image as + * selected, otherwise, initialize as unselected. + */ + if (self->edge_lock) + { + for (i = 0; i < roi->width; i++) + source[0][i] = 1.0; + } + else + { + memset (source[0], 0, roi->width * sizeof (gfloat)); + } + + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + 0, + roi->width, 1), + 1.0, input_format, source[1], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + + if (roi->height > 1) + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + 1, + roi->width, 1), + 1.0, input_format, source[2], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + else + memcpy (source[2], source[1], roi->width * sizeof (gfloat)); + + compute_transition (transition, source, roi->width, self->edge_lock); + gegl_buffer_set (output, + GEGL_RECTANGLE (roi->x, roi->y, + roi->width, 1), + 0, output_format, transition, + GEGL_AUTO_ROWSTRIDE); + + for (y = 1; y < roi->height; y++) + { + rotate_pointers (source, 3); + + if (y + 1 < roi->height) + { + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + y + 1, + roi->width, 1), + 1.0, input_format, source[2], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + } + else + { + /* Depending on `self->edge_lock', set the row below the + * image as either selected or non-selected. + */ + if (self->edge_lock) + { + for (i = 0; i < roi->width; i++) + source[2][i] = 1.0; + } + else + { + memset (source[2], 0, roi->width * sizeof (gfloat)); + } + } + + compute_transition (transition, source, roi->width, self->edge_lock); + gegl_buffer_set (output, + GEGL_RECTANGLE (roi->x, roi->y + y, + roi->width, 1), + 0, output_format, transition, + GEGL_AUTO_ROWSTRIDE); + } + + for (i = 0; i < 3; i++) + g_free (source[i]); + + g_free (transition); + + /* Finished handling the radius = 1 special case, return here. */ + return TRUE; + } + + max = g_new (gint16, roi->width + 2 * self->radius_x); + + for (i = 0; i < (roi->width + 2 * self->radius_x); i++) + max[i] = self->radius_y + 2; + + max += self->radius_x; + + for (i = 0; i < 3; i++) + buf[i] = g_new (gfloat, roi->width); + + transition = g_new (gfloat *, self->radius_y + 1); + + for (i = 0; i < self->radius_y + 1; i++) + { + transition[i] = g_new (gfloat, roi->width + 2 * self->radius_x); + memset (transition[i], 0, + (roi->width + 2 * self->radius_x) * sizeof (gfloat)); + transition[i] += self->radius_x; + } + + out = g_new (gfloat, roi->width); + + density = g_new (gfloat *, 2 * self->radius_x + 1); + density += self->radius_x; + + /* allocate density[][] */ + for (x = 0; x < (self->radius_x + 1); x++) + { + density[ x] = g_new (gfloat, 2 * self->radius_y + 1); + density[ x] += self->radius_y; + density[-x] = density[x]; + } + + /* compute density[][] */ + for (x = 0; x < (self->radius_x + 1); x++) + { + gdouble tmpx, tmpy, dist; + gfloat a; + + if (x > 0) + tmpx = x - 0.5; + else if (x < 0) + tmpx = x + 0.5; + else + tmpx = 0.0; + + for (y = 0; y < (self->radius_y + 1); y++) + { + if (y > 0) + tmpy = y - 0.5; + else if (y < 0) + tmpy = y + 0.5; + else + tmpy = 0.0; + + dist = ((tmpy * tmpy) / (self->radius_y * self->radius_y) + + (tmpx * tmpx) / (self->radius_x * self->radius_x)); + + if (dist < 1.0) + { + if (self->feather) + a = 1.0 - sqrt (dist); + else + a = 1.0; + } + else + { + a = 0.0; + } + + density[ x][ y] = a; + density[ x][-y] = a; + density[-x][ y] = a; + density[-x][-y] = a; + } + } + + /* Since the algorithm considerers `buf[0]' to be 'over' the row + * currently calculated, we must start with `buf[0]' as non-selected + * if there is no `self->edge_lock. If there is an + * 'self->edge_lock', initialize the first row to 'selected'. Refer + * to bug #350009. + */ + if (self->edge_lock) + { + for (i = 0; i < roi->width; i++) + buf[0][i] = 1.0; + } + else + { + memset (buf[0], 0, roi->width * sizeof (gfloat)); + } + + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + 0, + roi->width, 1), + 1.0, input_format, buf[1], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + + if (roi->height > 1) + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + 1, + roi->width, 1), + 1.0, input_format, buf[2], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + else + memcpy (buf[2], buf[1], roi->width * sizeof (gfloat)); + + compute_transition (transition[1], buf, roi->width, self->edge_lock); + + /* set up top of image */ + for (y = 1; y < self->radius_y && y + 1 < roi->height; y++) + { + rotate_pointers (buf, 3); + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + y + 1, + roi->width, 1), + 1.0, input_format, buf[2], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + compute_transition (transition[y + 1], buf, roi->width, self->edge_lock); + } + + /* set up max[] for top of image */ + for (x = 0; x < roi->width; x++) + { + max[x] = -(self->radius_y + 7); + + for (j = 1; j < self->radius_y + 1; j++) + if (transition[j][x]) + { + max[x] = j; + break; + } + } + + /* main calculation loop */ + for (y = 0; y < roi->height; y++) + { + rotate_pointers (buf, 3); + rotate_pointers (transition, self->radius_y + 1); + + if (y < roi->height - (self->radius_y + 1)) + { + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, + roi->y + y + self->radius_y + 1, + roi->width, 1), + 1.0, input_format, buf[2], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + compute_transition (transition[self->radius_y], buf, roi->width, self->edge_lock); + } + else + { + if (self->edge_lock) + { + memcpy (transition[self->radius_y], transition[self->radius_y - 1], roi->width * sizeof (gfloat)); + } + else + { + /* No edge lock, set everything 'below canvas' as seen + * from the algorithm as unselected. + */ + memset (buf[2], 0, roi->width * sizeof (gfloat)); + compute_transition (transition[self->radius_y], buf, roi->width, self->edge_lock); + } + } + + /* update max array */ + for (x = 0; x < roi->width; x++) + { + if (max[x] < 1) + { + if (max[x] <= -self->radius_y) + { + if (transition[self->radius_y][x]) + max[x] = self->radius_y; + else + max[x]--; + } + else + { + if (transition[-max[x]][x]) + max[x] = -max[x]; + else if (transition[-max[x] + 1][x]) + max[x] = -max[x] + 1; + else + max[x]--; + } + } + else + { + max[x]--; + } + + if (max[x] < -self->radius_y - 1) + max[x] = -self->radius_y - 1; + } + + last_index = 1; + + /* render scan line */ + for (x = 0 ; x < roi->width; x++) + { + gfloat last_max; + + last_index--; + + if (last_index >= 0) + { + last_max = 0.0; + + for (i = self->radius_x; i >= 0; i--) + if (max[x + i] <= self->radius_y && max[x + i] >= -self->radius_y && + density[i][max[x+i]] > last_max) + { + last_max = density[i][max[x + i]]; + last_index = i; + } + + out[x] = last_max; + } + else + { + last_max = 0.0; + + for (i = self->radius_x; i >= -self->radius_x; i--) + if (max[x + i] <= self->radius_y && max[x + i] >= -self->radius_y && + density[i][max[x + i]] > last_max) + { + last_max = density[i][max[x + i]]; + last_index = i; + } + + out[x] = last_max; + } + + if (last_max <= 0.0) + { + for (i = x + 1; i < roi->width; i++) + { + if (max[i] >= -self->radius_y) + break; + } + + if (i - x > self->radius_x) + { + for (; x < i - self->radius_x; x++) + out[x] = 0; + + x--; + } + + last_index = self->radius_x; + } + } + + gegl_buffer_set (output, + GEGL_RECTANGLE (roi->x, roi->y + y, + roi->width, 1), + 0, output_format, out, + GEGL_AUTO_ROWSTRIDE); + } + + g_free (out); + + for (i = 0; i < 3; i++) + g_free (buf[i]); + + max -= self->radius_x; + g_free (max); + + for (i = 0; i < self->radius_y + 1; i++) + { + transition[i] -= self->radius_x; + g_free (transition[i]); + } + + g_free (transition); + + for (i = 0; i < self->radius_x + 1 ; i++) + { + density[i] -= self->radius_y; + g_free (density[i]); + } + + density -= self->radius_x; + g_free (density); + + return TRUE; +} diff --git a/app/operations/gimpoperationborder.h b/app/operations/gimpoperationborder.h new file mode 100644 index 0000000..83eb9fa --- /dev/null +++ b/app/operations/gimpoperationborder.h @@ -0,0 +1,58 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationborder.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_BORDER_H__ +#define __GIMP_OPERATION_BORDER_H__ + + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_BORDER (gimp_operation_border_get_type ()) +#define GIMP_OPERATION_BORDER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_BORDER, GimpOperationBorder)) +#define GIMP_OPERATION_BORDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_BORDER, GimpOperationBorderClass)) +#define GIMP_IS_OPERATION_BORDER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_BORDER)) +#define GIMP_IS_OPERATION_BORDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_BORDER)) +#define GIMP_OPERATION_BORDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_BORDER, GimpOperationBorderClass)) + + +typedef struct _GimpOperationBorder GimpOperationBorder; +typedef struct _GimpOperationBorderClass GimpOperationBorderClass; + +struct _GimpOperationBorder +{ + GeglOperationFilter parent_instance; + + gint radius_x; + gint radius_y; + gboolean feather; + gboolean edge_lock; +}; + +struct _GimpOperationBorderClass +{ + GeglOperationFilterClass parent_class; +}; + + +GType gimp_operation_border_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_BORDER_H__ */ diff --git a/app/operations/gimpoperationbrightnesscontrast.c b/app/operations/gimpoperationbrightnesscontrast.c new file mode 100644 index 0000000..1dd9186 --- /dev/null +++ b/app/operations/gimpoperationbrightnesscontrast.c @@ -0,0 +1,140 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationbrightnesscontrast.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimpbrightnesscontrastconfig.h" +#include "gimpoperationbrightnesscontrast.h" + +#include "gimp-intl.h" + + +static gboolean gimp_operation_brightness_contrast_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationBrightnessContrast, gimp_operation_brightness_contrast, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_brightness_contrast_parent_class + + +static void +gimp_operation_brightness_contrast_class_init (GimpOperationBrightnessContrastClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_point_filter_set_property; + object_class->get_property = gimp_operation_point_filter_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:brightness-contrast", + "categories", "color", + "description", _("Adjust brightness and contrast"), + NULL); + + point_class->process = gimp_operation_brightness_contrast_process; + + g_object_class_install_property (object_class, + GIMP_OPERATION_POINT_FILTER_PROP_CONFIG, + g_param_spec_object ("config", + "Config", + "The config object", + GIMP_TYPE_BRIGHTNESS_CONTRAST_CONFIG, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_brightness_contrast_init (GimpOperationBrightnessContrast *self) +{ +} + +static inline gfloat +gimp_operation_brightness_contrast_map (gfloat value, + gdouble brightness, + gdouble slant) +{ + /* apply brightness */ + if (brightness < 0.0) + value = value * (1.0 + brightness); + else + value = value + ((1.0 - value) * brightness); + + value = (value - 0.5) * slant + 0.5; + + return value; +} + +static gboolean +gimp_operation_brightness_contrast_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationPointFilter *point = GIMP_OPERATION_POINT_FILTER (operation); + GimpBrightnessContrastConfig *config = GIMP_BRIGHTNESS_CONTRAST_CONFIG (point->config); + gfloat *src = in_buf; + gfloat *dest = out_buf; + gdouble brightness; + gdouble slant; + + if (! config) + return FALSE; + + brightness = config->brightness / 2.0; + slant = tan ((config->contrast + 1) * G_PI_4); + + while (samples--) + { + dest[RED] = gimp_operation_brightness_contrast_map (src[RED], + brightness, + slant); + dest[GREEN] = gimp_operation_brightness_contrast_map (src[GREEN], + brightness, + slant); + dest[BLUE] = gimp_operation_brightness_contrast_map (src[BLUE], + brightness, + slant); + dest[ALPHA] = src[ALPHA]; + + src += 4; + dest += 4; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationbrightnesscontrast.h b/app/operations/gimpoperationbrightnesscontrast.h new file mode 100644 index 0000000..d93ff20 --- /dev/null +++ b/app/operations/gimpoperationbrightnesscontrast.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationbrightnesscontrast.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_BRIGHTNESS_CONTRAST_H__ +#define __GIMP_OPERATION_BRIGHTNESS_CONTRAST_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_BRIGHTNESS_CONTRAST (gimp_operation_brightness_contrast_get_type ()) +#define GIMP_OPERATION_BRIGHTNESS_CONTRAST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_BRIGHTNESS_CONTRAST, GimpOperationBrightnessContrast)) +#define GIMP_OPERATION_BRIGHTNESS_CONTRAST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_BRIGHTNESS_CONTRAST, GimpOperationBrightnessContrastClass)) +#define GIMP_IS_OPERATION_BRIGHTNESS_CONTRAST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_BRIGHTNESS_CONTRAST)) +#define GIMP_IS_OPERATION_BRIGHTNESS_CONTRAST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_BRIGHTNESS_CONTRAST)) +#define GIMP_OPERATION_BRIGHTNESS_CONTRAST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_BRIGHTNESS_CONTRAST, GimpOperationBrightnessContrastClass)) + + +typedef struct _GimpOperationBrightnessContrast GimpOperationBrightnessContrast; +typedef struct _GimpOperationBrightnessContrastClass GimpOperationBrightnessContrastClass; + +struct _GimpOperationBrightnessContrast +{ + GimpOperationPointFilter parent_instance; +}; + +struct _GimpOperationBrightnessContrastClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_brightness_contrast_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_BRIGHTNESS_CONTRAST_H__ */ diff --git a/app/operations/gimpoperationbuffersourcevalidate.c b/app/operations/gimpoperationbuffersourcevalidate.c new file mode 100644 index 0000000..d277653 --- /dev/null +++ b/app/operations/gimpoperationbuffersourcevalidate.c @@ -0,0 +1,307 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationbuffersourcevalidate.c + * Copyright (C) 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl-plugin.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "operations-types.h" + +#include "gegl/gimptilehandlervalidate.h" + +#include "gimpoperationbuffersourcevalidate.h" + + +enum +{ + PROP_0, + PROP_BUFFER +}; + + +static void gimp_operation_buffer_source_validate_dispose (GObject *object); +static void gimp_operation_buffer_source_validate_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_buffer_source_validate_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static GeglRectangle gimp_operation_buffer_source_validate_get_bounding_box (GeglOperation *operation); +static void gimp_operation_buffer_source_validate_prepare (GeglOperation *operation); +static gboolean gimp_operation_buffer_source_validate_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_pad, + const GeglRectangle *result, + gint level); + +static void gimp_operation_buffer_source_validate_invalidate (gpointer object, + const GeglRectangle *rect, + GimpOperationBufferSourceValidate *buffer_source_validate); + + +G_DEFINE_TYPE (GimpOperationBufferSourceValidate, gimp_operation_buffer_source_validate, + GEGL_TYPE_OPERATION_SOURCE) + +#define parent_class gimp_operation_buffer_source_validate_parent_class + + +static void +gimp_operation_buffer_source_validate_class_init (GimpOperationBufferSourceValidateClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + + object_class->dispose = gimp_operation_buffer_source_validate_dispose; + object_class->set_property = gimp_operation_buffer_source_validate_set_property; + object_class->get_property = gimp_operation_buffer_source_validate_get_property; + + operation_class->get_bounding_box = gimp_operation_buffer_source_validate_get_bounding_box; + operation_class->prepare = gimp_operation_buffer_source_validate_prepare; + operation_class->process = gimp_operation_buffer_source_validate_process; + + operation_class->threaded = FALSE; + operation_class->cache_policy = GEGL_CACHE_POLICY_NEVER; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:buffer-source-validate", + "categories", "gimp", + "description", "GIMP Buffer-Source Validate operation", + NULL); + + g_object_class_install_property (object_class, PROP_BUFFER, + g_param_spec_object ("buffer", + "Buffer", + "Input buffer", + GEGL_TYPE_BUFFER, + G_PARAM_READWRITE)); +} + +static void +gimp_operation_buffer_source_validate_init (GimpOperationBufferSourceValidate *self) +{ +} + +static void +gimp_operation_buffer_source_validate_dispose (GObject *object) +{ + GimpOperationBufferSourceValidate *buffer_source_validate = GIMP_OPERATION_BUFFER_SOURCE_VALIDATE (object); + + if (buffer_source_validate->buffer) + { + GimpTileHandlerValidate *validate_handler; + + validate_handler = gimp_tile_handler_validate_get_assigned ( + buffer_source_validate->buffer); + + if (validate_handler) + { + g_signal_connect ( + validate_handler, + "invalidated", + G_CALLBACK (gimp_operation_buffer_source_validate_invalidate), + buffer_source_validate); + } + + g_signal_handlers_disconnect_by_func ( + buffer_source_validate->buffer, + gimp_operation_buffer_source_validate_invalidate, + buffer_source_validate); + + g_clear_object (&buffer_source_validate->buffer); + } + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gimp_operation_buffer_source_validate_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationBufferSourceValidate *buffer_source_validate = GIMP_OPERATION_BUFFER_SOURCE_VALIDATE (object); + + switch (property_id) + { + case PROP_BUFFER: + g_value_set_object (value, buffer_source_validate->buffer); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_buffer_source_validate_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationBufferSourceValidate *buffer_source_validate = GIMP_OPERATION_BUFFER_SOURCE_VALIDATE (object); + + switch (property_id) + { + case PROP_BUFFER: + { + if (buffer_source_validate->buffer) + { + GimpTileHandlerValidate *validate_handler; + + validate_handler = gimp_tile_handler_validate_get_assigned ( + buffer_source_validate->buffer); + + gimp_operation_buffer_source_validate_invalidate ( + buffer_source_validate->buffer, + gegl_buffer_get_extent (buffer_source_validate->buffer), + buffer_source_validate); + + g_signal_handlers_disconnect_by_func ( + buffer_source_validate->buffer, + gimp_operation_buffer_source_validate_invalidate, + buffer_source_validate); + + if (validate_handler) + { + g_signal_handlers_disconnect_by_func ( + validate_handler, + gimp_operation_buffer_source_validate_invalidate, + buffer_source_validate); + } + + g_clear_object (&buffer_source_validate->buffer); + } + + buffer_source_validate->buffer = g_value_dup_object (value); + + if (buffer_source_validate->buffer) + { + GimpTileHandlerValidate *validate_handler; + + validate_handler = gimp_tile_handler_validate_get_assigned ( + buffer_source_validate->buffer); + + if (validate_handler) + { + g_signal_connect ( + validate_handler, + "invalidated", + G_CALLBACK (gimp_operation_buffer_source_validate_invalidate), + buffer_source_validate); + } + + gegl_buffer_signal_connect ( + buffer_source_validate->buffer, + "changed", + G_CALLBACK (gimp_operation_buffer_source_validate_invalidate), + buffer_source_validate); + + gimp_operation_buffer_source_validate_invalidate ( + buffer_source_validate->buffer, + gegl_buffer_get_extent (buffer_source_validate->buffer), + buffer_source_validate); + } + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static GeglRectangle +gimp_operation_buffer_source_validate_get_bounding_box (GeglOperation *operation) +{ + GimpOperationBufferSourceValidate *buffer_source_validate = GIMP_OPERATION_BUFFER_SOURCE_VALIDATE (operation); + + GeglRectangle result = {}; + + if (buffer_source_validate->buffer) + result = *gegl_buffer_get_extent (buffer_source_validate->buffer); + + return result; +} + +static void +gimp_operation_buffer_source_validate_prepare (GeglOperation *operation) +{ + GimpOperationBufferSourceValidate *buffer_source_validate = GIMP_OPERATION_BUFFER_SOURCE_VALIDATE (operation); + const Babl *format = NULL; + + if (buffer_source_validate->buffer) + format = gegl_buffer_get_format (buffer_source_validate->buffer); + + gegl_operation_set_format (operation, "output", format); +} + +static gboolean +gimp_operation_buffer_source_validate_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_pad, + const GeglRectangle *result, + gint level) +{ + GimpOperationBufferSourceValidate *buffer_source_validate = GIMP_OPERATION_BUFFER_SOURCE_VALIDATE (operation); + GeglBuffer *buffer = buffer_source_validate->buffer; + + if (buffer) + { + GimpTileHandlerValidate *validate_handler; + + validate_handler = gimp_tile_handler_validate_get_assigned (buffer); + + if (validate_handler) + { + GeglRectangle rect; + + /* align the rectangle to the tile grid */ + gegl_rectangle_align_to_buffer ( + &rect, result, buffer_source_validate->buffer, + GEGL_RECTANGLE_ALIGNMENT_SUPERSET); + + gimp_tile_handler_validate_validate (validate_handler, + buffer_source_validate->buffer, + &rect, + TRUE, FALSE); + } + + gegl_operation_context_set_object (context, "output", G_OBJECT (buffer)); + + gegl_object_set_has_forked (G_OBJECT (buffer)); + } + + return TRUE; +} + +static void +gimp_operation_buffer_source_validate_invalidate (gpointer object, + const GeglRectangle *rect, + GimpOperationBufferSourceValidate *buffer_source_validate) +{ + gegl_operation_invalidate (GEGL_OPERATION (buffer_source_validate), + rect, FALSE); +} diff --git a/app/operations/gimpoperationbuffersourcevalidate.h b/app/operations/gimpoperationbuffersourcevalidate.h new file mode 100644 index 0000000..c47c333 --- /dev/null +++ b/app/operations/gimpoperationbuffersourcevalidate.h @@ -0,0 +1,52 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationbuffersourcevalidate.h + * Copyright (C) 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_BUFFER_SOURCE_VALIDATE_H__ +#define __GIMP_OPERATION_BUFFER_SOURCE_VALIDATE_H__ + + +#define GIMP_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE (gimp_operation_buffer_source_validate_get_type ()) +#define GIMP_OPERATION_BUFFER_SOURCE_VALIDATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE, GimpOperationBufferSourceValidate)) +#define GIMP_OPERATION_BUFFER_SOURCE_VALIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE, GimpOperationBufferSourceValidateClass)) +#define GIMP_IS_OPERATION_BUFFER_SOURCE_VALIDATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE)) +#define GIMP_IS_OPERATION_BUFFER_SOURCE_VALIDATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE)) +#define GIMP_OPERATION_BUFFER_SOURCE_VALIDATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_BUFFER_SOURCE_VALIDATE, GimpOperationBufferSourceValidateClass)) + + +typedef struct _GimpOperationBufferSourceValidate GimpOperationBufferSourceValidate; +typedef struct _GimpOperationBufferSourceValidateClass GimpOperationBufferSourceValidateClass; + +struct _GimpOperationBufferSourceValidate +{ + GeglOperationSource parent_instance; + + GeglBuffer *buffer; +}; + +struct _GimpOperationBufferSourceValidateClass +{ + GeglOperationSourceClass parent_class; +}; + + +GType gimp_operation_buffer_source_validate_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_BUFFER_SOURCE_VALIDATE_H__ */ diff --git a/app/operations/gimpoperationcagecoefcalc.c b/app/operations/gimpoperationcagecoefcalc.c new file mode 100644 index 0000000..9c78054 --- /dev/null +++ b/app/operations/gimpoperationcagecoefcalc.c @@ -0,0 +1,294 @@ +/* GIMP - The GNU Image Manipulation Program + * + * gimpoperationcagecoefcalc.c + * Copyright (C) 2010 Michael Muré <batolettre@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimpoperationcagecoefcalc.h" +#include "gimpcageconfig.h" + +#include "gimp-intl.h" + + +static void gimp_operation_cage_coef_calc_finalize (GObject *object); +static void gimp_operation_cage_coef_calc_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_cage_coef_calc_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_cage_coef_calc_prepare (GeglOperation *operation); +static GeglRectangle gimp_operation_cage_coef_calc_get_bounding_box (GeglOperation *operation); +static gboolean gimp_operation_cage_coef_calc_process (GeglOperation *operation, + GeglBuffer *output, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationCageCoefCalc, gimp_operation_cage_coef_calc, + GEGL_TYPE_OPERATION_SOURCE) + +#define parent_class gimp_operation_cage_coef_calc_parent_class + + +static void +gimp_operation_cage_coef_calc_class_init (GimpOperationCageCoefCalcClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationSourceClass *source_class = GEGL_OPERATION_SOURCE_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:cage-coef-calc", + "categories", "transform", + "description", _("Compute a set of coefficient buffer for the GIMP cage tool"), + NULL); + + operation_class->prepare = gimp_operation_cage_coef_calc_prepare; + operation_class->get_bounding_box = gimp_operation_cage_coef_calc_get_bounding_box; + operation_class->cache_policy = GEGL_CACHE_POLICY_ALWAYS; + operation_class->get_cached_region = NULL; + + source_class->process = gimp_operation_cage_coef_calc_process; + + object_class->get_property = gimp_operation_cage_coef_calc_get_property; + object_class->set_property = gimp_operation_cage_coef_calc_set_property; + object_class->finalize = gimp_operation_cage_coef_calc_finalize; + + g_object_class_install_property (object_class, + GIMP_OPERATION_CAGE_COEF_CALC_PROP_CONFIG, + g_param_spec_object ("config", + "Config", + "A GimpCageConfig object, that define the transformation", + GIMP_TYPE_CAGE_CONFIG, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_cage_coef_calc_init (GimpOperationCageCoefCalc *self) +{ +} + +static void +gimp_operation_cage_coef_calc_finalize (GObject *object) +{ + GimpOperationCageCoefCalc *self = GIMP_OPERATION_CAGE_COEF_CALC (object); + + g_clear_object (&self->config); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_operation_cage_coef_calc_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationCageCoefCalc *self = GIMP_OPERATION_CAGE_COEF_CALC (object); + + switch (property_id) + { + case GIMP_OPERATION_CAGE_COEF_CALC_PROP_CONFIG: + g_value_set_object (value, self->config); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_cage_coef_calc_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationCageCoefCalc *self = GIMP_OPERATION_CAGE_COEF_CALC (object); + + switch (property_id) + { + case GIMP_OPERATION_CAGE_COEF_CALC_PROP_CONFIG: + if (self->config) + g_object_unref (self->config); + self->config = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gboolean +gimp_operation_cage_coef_calc_is_on_straight (GimpVector2 *d1, + GimpVector2 *d2, + GimpVector2 *p) +{ + GimpVector2 v1, v2; + gfloat deter; + + v1.x = p->x - d1->x; + v1.y = p->y - d1->y; + v2.x = d2->x - d1->x; + v2.y = d2->y - d1->y; + + gimp_vector2_normalize (&v1); + gimp_vector2_normalize (&v2); + + deter = v1.x * v2.y - v2.x * v1.y; + + return (deter < 0.000000001) && (deter > -0.000000001); +} + +static void +gimp_operation_cage_coef_calc_prepare (GeglOperation *operation) +{ + GimpOperationCageCoefCalc *occc = GIMP_OPERATION_CAGE_COEF_CALC (operation); + GimpCageConfig *config = GIMP_CAGE_CONFIG (occc->config); + + gegl_operation_set_format (operation, + "output", + babl_format_n (babl_type ("float"), + 2 * gimp_cage_config_get_n_points (config))); +} + +static GeglRectangle +gimp_operation_cage_coef_calc_get_bounding_box (GeglOperation *operation) +{ + GimpOperationCageCoefCalc *occc = GIMP_OPERATION_CAGE_COEF_CALC (operation); + GimpCageConfig *config = GIMP_CAGE_CONFIG (occc->config); + + return gimp_cage_config_get_bounding_box (config); +} + +static gboolean +gimp_operation_cage_coef_calc_process (GeglOperation *operation, + GeglBuffer *output, + const GeglRectangle *roi, + gint level) +{ + GimpOperationCageCoefCalc *occc = GIMP_OPERATION_CAGE_COEF_CALC (operation); + GimpCageConfig *config = GIMP_CAGE_CONFIG (occc->config); + + const Babl *format; + + GeglBufferIterator *it; + guint n_cage_vertices; + GimpCagePoint *current, *last; + + if (! config) + return FALSE; + + format = babl_format_n (babl_type ("float"), 2 * gimp_cage_config_get_n_points (config)); + + n_cage_vertices = gimp_cage_config_get_n_points (config); + + it = gegl_buffer_iterator_new (output, roi, 0, format, + GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1); + + while (gegl_buffer_iterator_next (it)) + { + /* iterate inside the roi */ + gfloat *coef = it->items[0].data; + gint n_pixels = it->length; + gint x = it->items[0].roi.x; /* initial x */ + gint y = it->items[0].roi.y; /* and y coordinates */ + gint j; + + memset (coef, 0, sizeof * coef * n_pixels * 2 * n_cage_vertices); + while(n_pixels--) + { + if (gimp_cage_config_point_inside(config, x, y)) + { + last = &(g_array_index (config->cage_points, GimpCagePoint, 0)); + + for( j = 0; j < n_cage_vertices; j++) + { + GimpVector2 v1,v2,a,b,p; + gdouble BA,SRT,L0,L1,A0,A1,A10,L10, Q,S,R, absa; + + current = &(g_array_index (config->cage_points, GimpCagePoint, (j+1) % n_cage_vertices)); + v1 = last->src_point; + v2 = current->src_point; + p.x = x; + p.y = y; + a.x = v2.x - v1.x; + a.y = v2.y - v1.y; + absa = gimp_vector2_length (&a); + + b.x = v1.x - x; + b.y = v1.y - y; + Q = a.x * a.x + a.y * a.y; + S = b.x * b.x + b.y * b.y; + R = 2.0 * (a.x * b.x + a.y * b.y); + BA = b.x * a.y - b.y * a.x; + SRT = sqrt(4.0 * S * Q - R * R); + + L0 = log(S); + L1 = log(S + Q + R); + A0 = atan2(R, SRT) / SRT; + A1 = atan2(2.0 * Q + R, SRT) / SRT; + A10 = A1 - A0; + L10 = L1 - L0; + + /* edge coef */ + coef[j + n_cage_vertices] = (-absa / (4.0 * G_PI)) * ((4.0*S-(R*R)/Q) * A10 + (R / (2.0 * Q)) * L10 + L1 - 2.0); + + if (isnan(coef[j + n_cage_vertices])) + { + coef[j + n_cage_vertices] = 0.0; + } + + /* vertice coef */ + if (!gimp_operation_cage_coef_calc_is_on_straight (&v1, &v2, &p)) + { + coef[j] += (BA / (2.0 * G_PI)) * (L10 /(2.0*Q) - A10 * (2.0 + R / Q)); + coef[(j+1)%n_cage_vertices] -= (BA / (2.0 * G_PI)) * (L10 / (2.0 * Q) - A10 * (R / Q)); + } + + last = current; + } + } + + coef += 2 * n_cage_vertices; + + /* update x and y coordinates */ + x++; + if (x >= (it->items[0].roi.x + it->items[0].roi.width)) + { + x = it->items[0].roi.x; + y++; + } + } + } + + return TRUE; +} diff --git a/app/operations/gimpoperationcagecoefcalc.h b/app/operations/gimpoperationcagecoefcalc.h new file mode 100644 index 0000000..e63be27 --- /dev/null +++ b/app/operations/gimpoperationcagecoefcalc.h @@ -0,0 +1,62 @@ +/* GIMP - The GNU Image Manipulation Program + * + * gimpoperationcagecoefcalc.h + * Copyright (C) 2010 Michael Muré <batolettre@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_CAGE_COEF_CALC_H__ +#define __GIMP_OPERATION_CAGE_COEF_CALC_H__ + + +#include <gegl-plugin.h> +#include <operation/gegl-operation-source.h> + + +enum +{ + GIMP_OPERATION_CAGE_COEF_CALC_PROP_0, + GIMP_OPERATION_CAGE_COEF_CALC_PROP_CONFIG +}; + + +#define GIMP_TYPE_OPERATION_CAGE_COEF_CALC (gimp_operation_cage_coef_calc_get_type ()) +#define GIMP_OPERATION_CAGE_COEF_CALC(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_CAGE_COEF_CALC, GimpOperationCageCoefCalc)) +#define GIMP_OPERATION_CAGE_COEF_CALC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_CAGE_COEF_CALC, GimpOperationCageCoefCalcClass)) +#define GIMP_IS_OPERATION_CAGE_COEF_CALC(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_CAGE_COEF_CALC)) +#define GIMP_IS_OPERATION_CAGE_COEF_CALC_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_CAGE_COEF_CALC)) +#define GIMP_OPERATION_CAGE_COEF_CALC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_CAGE_COEF_CALC, GimpOperationCageCoefCalcClass)) + + +typedef struct _GimpOperationCageCoefCalc GimpOperationCageCoefCalc; +typedef struct _GimpOperationCageCoefCalcClass GimpOperationCageCoefCalcClass; + +struct _GimpOperationCageCoefCalc +{ + GeglOperationSource parent_instance; + + GimpCageConfig *config; +}; + +struct _GimpOperationCageCoefCalcClass +{ + GeglOperationSourceClass parent_class; +}; + + +GType gimp_operation_cage_coef_calc_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_CAGE_COEF_CALC_H__ */ diff --git a/app/operations/gimpoperationcagetransform.c b/app/operations/gimpoperationcagetransform.c new file mode 100644 index 0000000..d2f0450 --- /dev/null +++ b/app/operations/gimpoperationcagetransform.c @@ -0,0 +1,603 @@ +/* GIMP - The GNU Image Manipulation Program + * + * gimpoperationcage.c + * Copyright (C) 2010 Michael Muré <batolettre@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimpoperationcagetransform.h" +#include "gimpcageconfig.h" + +#include "gimp-intl.h" + +enum +{ + PROP_0, + PROP_CONFIG, + PROP_FILL, +}; + + +static void gimp_operation_cage_transform_finalize (GObject *object); +static void gimp_operation_cage_transform_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_cage_transform_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_operation_cage_transform_prepare (GeglOperation *operation); +static gboolean gimp_operation_cage_transform_process (GeglOperation *operation, + GeglBuffer *in_buf, + GeglBuffer *aux_buf, + GeglBuffer *out_buf, + const GeglRectangle *roi, + gint level); +static void gimp_operation_cage_transform_interpolate_source_coords_recurs + (GimpOperationCageTransform *oct, + GeglBuffer *out_buf, + const GeglRectangle *roi, + GimpVector2 p1_s, + GimpVector2 p1_d, + GimpVector2 p2_s, + GimpVector2 p2_d, + GimpVector2 p3_s, + GimpVector2 p3_d, + gint recursion_depth, + gfloat *coords); +static GimpVector2 gimp_cage_transform_compute_destination (GimpCageConfig *config, + gfloat *coef, + GeglSampler *coef_sampler, + GimpVector2 coords); +GeglRectangle gimp_operation_cage_transform_get_cached_region (GeglOperation *operation, + const GeglRectangle *roi); +GeglRectangle gimp_operation_cage_transform_get_required_for_output (GeglOperation *operation, + const gchar *input_pad, + const GeglRectangle *roi); +GeglRectangle gimp_operation_cage_transform_get_bounding_box (GeglOperation *operation); + + +G_DEFINE_TYPE (GimpOperationCageTransform, gimp_operation_cage_transform, + GEGL_TYPE_OPERATION_COMPOSER) + +#define parent_class gimp_operation_cage_transform_parent_class + + +static void +gimp_operation_cage_transform_class_init (GimpOperationCageTransformClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationComposerClass *filter_class = GEGL_OPERATION_COMPOSER_CLASS (klass); + + object_class->get_property = gimp_operation_cage_transform_get_property; + object_class->set_property = gimp_operation_cage_transform_set_property; + object_class->finalize = gimp_operation_cage_transform_finalize; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:cage-transform", + "categories", "transform", + "description", _("Convert a set of coefficient buffer to a coordinate buffer for the GIMP cage tool"), + NULL); + + operation_class->prepare = gimp_operation_cage_transform_prepare; + + operation_class->get_required_for_output = gimp_operation_cage_transform_get_required_for_output; + operation_class->get_cached_region = gimp_operation_cage_transform_get_cached_region; + operation_class->get_bounding_box = gimp_operation_cage_transform_get_bounding_box; + /* XXX Temporarily disable multi-threading on this operation because + * it is much faster when single-threaded. See bug 787663. + */ + operation_class->threaded = FALSE; + + filter_class->process = gimp_operation_cage_transform_process; + + g_object_class_install_property (object_class, PROP_CONFIG, + g_param_spec_object ("config", + "Config", + "A GimpCageConfig object, that define the transformation", + GIMP_TYPE_CAGE_CONFIG, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_FILL, + g_param_spec_boolean ("fill-plain-color", + _("Fill with plain color"), + _("Fill the original position of the cage with a plain color"), + FALSE, + G_PARAM_READWRITE)); +} + +static void +gimp_operation_cage_transform_init (GimpOperationCageTransform *self) +{ + self->format_coords = babl_format_n(babl_type("float"), 2); +} + +static void +gimp_operation_cage_transform_finalize (GObject *object) +{ + GimpOperationCageTransform *self = GIMP_OPERATION_CAGE_TRANSFORM (object); + + g_clear_object (&self->config); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_operation_cage_transform_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationCageTransform *self = GIMP_OPERATION_CAGE_TRANSFORM (object); + + switch (property_id) + { + case PROP_CONFIG: + g_value_set_object (value, self->config); + break; + case PROP_FILL: + g_value_set_boolean (value, self->fill_plain_color); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_cage_transform_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationCageTransform *self = GIMP_OPERATION_CAGE_TRANSFORM (object); + + switch (property_id) + { + case PROP_CONFIG: + if (self->config) + g_object_unref (self->config); + self->config = g_value_dup_object (value); + break; + case PROP_FILL: + self->fill_plain_color = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_cage_transform_prepare (GeglOperation *operation) +{ + GimpOperationCageTransform *oct = GIMP_OPERATION_CAGE_TRANSFORM (operation); + GimpCageConfig *config = GIMP_CAGE_CONFIG (oct->config); + + gegl_operation_set_format (operation, "input", + babl_format_n (babl_type ("float"), + 2 * gimp_cage_config_get_n_points (config))); + gegl_operation_set_format (operation, "output", + babl_format_n (babl_type ("float"), 2)); +} + +static gboolean +gimp_operation_cage_transform_process (GeglOperation *operation, + GeglBuffer *in_buf, + GeglBuffer *aux_buf, + GeglBuffer *out_buf, + const GeglRectangle *roi, + gint level) +{ + GimpOperationCageTransform *oct = GIMP_OPERATION_CAGE_TRANSFORM (operation); + GimpCageConfig *config = GIMP_CAGE_CONFIG (oct->config); + GeglRectangle cage_bb; + gfloat *coords; + gfloat *coef; + const Babl *format_coef; + GeglSampler *coef_sampler; + GimpVector2 plain_color; + GeglBufferIterator *it; + gint x, y; + gboolean output_set; + GimpCagePoint *point; + guint n_cage_vertices; + + /* pre-fill the out buffer with no-displacement coordinate */ + it = gegl_buffer_iterator_new (out_buf, roi, 0, NULL, + GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1); + cage_bb = gimp_cage_config_get_bounding_box (config); + + point = &(g_array_index (config->cage_points, GimpCagePoint, 0)); + plain_color.x = (gint) point->src_point.x; + plain_color.y = (gint) point->src_point.y; + + n_cage_vertices = gimp_cage_config_get_n_points (config); + + while (gegl_buffer_iterator_next (it)) + { + /* iterate inside the roi */ + gint n_pixels = it->length; + gfloat *output = it->items[0].data; + + x = it->items[0].roi.x; /* initial x */ + y = it->items[0].roi.y; /* and y coordinates */ + + while (n_pixels--) + { + output_set = FALSE; + if (oct->fill_plain_color) + { + if (x > cage_bb.x && + y > cage_bb.y && + x < cage_bb.x + cage_bb.width && + y < cage_bb.y + cage_bb.height) + { + if (gimp_cage_config_point_inside (config, x, y)) + { + output[0] = plain_color.x; + output[1] = plain_color.y; + output_set = TRUE; + } + } + } + if (!output_set) + { + output[0] = x + 0.5; + output[1] = y + 0.5; + } + + output += 2; + + /* update x and y coordinates */ + x++; + if (x >= (it->items[0].roi.x + it->items[0].roi.width)) + { + x = it->items[0].roi.x; + y++; + } + } + } + + if (! aux_buf) + return TRUE; + + gegl_operation_progress (operation, 0.0, ""); + + /* pre-allocate memory outside of the loop */ + coords = g_slice_alloc (2 * sizeof (gfloat)); + coef = g_malloc (n_cage_vertices * 2 * sizeof (gfloat)); + format_coef = babl_format_n (babl_type ("float"), 2 * n_cage_vertices); + coef_sampler = gegl_buffer_sampler_new (aux_buf, + format_coef, GEGL_SAMPLER_NEAREST); + + /* compute, reverse and interpolate the transformation */ + for (y = cage_bb.y; y < cage_bb.y + cage_bb.height - 1; y++) + { + GimpVector2 p1_d, p2_d, p3_d, p4_d; + GimpVector2 p1_s, p2_s, p3_s, p4_s; + + p1_s.y = y; + p2_s.y = y+1; + p3_s.y = y+1; + p3_s.x = cage_bb.x; + p4_s.y = y; + p4_s.x = cage_bb.x; + + p3_d = gimp_cage_transform_compute_destination (config, coef, coef_sampler, p3_s); + p4_d = gimp_cage_transform_compute_destination (config, coef, coef_sampler, p4_s); + + for (x = cage_bb.x; x < cage_bb.x + cage_bb.width - 1; x++) + { + p1_s = p4_s; + p2_s = p3_s; + p3_s.x = x+1; + p4_s.x = x+1; + + p1_d = p4_d; + p2_d = p3_d; + p3_d = gimp_cage_transform_compute_destination (config, coef, coef_sampler, p3_s); + p4_d = gimp_cage_transform_compute_destination (config, coef, coef_sampler, p4_s); + + if (gimp_cage_config_point_inside (config, x, y)) + { + gimp_operation_cage_transform_interpolate_source_coords_recurs (oct, + out_buf, + roi, + p1_s, p1_d, + p2_s, p2_d, + p3_s, p3_d, + 0, + coords); + + gimp_operation_cage_transform_interpolate_source_coords_recurs (oct, + out_buf, + roi, + p1_s, p1_d, + p3_s, p3_d, + p4_s, p4_d, + 0, + coords); + } + } + + if ((y - cage_bb.y) % 20 == 0) + { + gdouble fraction = ((gdouble) (y - cage_bb.y) / + (gdouble) (cage_bb.height)); + + /* 0.0 and 1.0 indicate progress start/end, so avoid them */ + if (fraction > 0.0 && fraction < 1.0) + { + gegl_operation_progress (operation, fraction, ""); + } + } + } + + g_object_unref (coef_sampler); + g_free (coef); + g_slice_free1 (2 * sizeof (gfloat), coords); + + gegl_operation_progress (operation, 1.0, ""); + + return TRUE; +} + + +static void +gimp_operation_cage_transform_interpolate_source_coords_recurs (GimpOperationCageTransform *oct, + GeglBuffer *out_buf, + const GeglRectangle *roi, + GimpVector2 p1_s, + GimpVector2 p1_d, + GimpVector2 p2_s, + GimpVector2 p2_d, + GimpVector2 p3_s, + GimpVector2 p3_d, + gint recursion_depth, + gfloat *coords) +{ + gint xmin, xmax, ymin, ymax, x, y; + + /* Stop recursion if all 3 vertices of the triangle are outside the + * ROI (left/right or above/below). + */ + if (p1_d.x >= roi->x + roi->width && + p2_d.x >= roi->x + roi->width && + p3_d.x >= roi->x + roi->width) return; + if (p1_d.y >= roi->y + roi->height && + p2_d.y >= roi->y + roi->height && + p3_d.y >= roi->y + roi->height) return; + + if (p1_d.x < roi->x && + p2_d.x < roi->x && + p3_d.x < roi->x) return; + if (p1_d.y < roi->y && + p2_d.y < roi->y && + p3_d.y < roi->y) return; + + xmin = xmax = lrint (p1_d.x); + ymin = ymax = lrint (p1_d.y); + + x = lrint (p2_d.x); + xmin = MIN (x, xmin); + xmax = MAX (x, xmax); + + x = lrint (p3_d.x); + xmin = MIN (x, xmin); + xmax = MAX (x, xmax); + + y = lrint (p2_d.y); + ymin = MIN (y, ymin); + ymax = MAX (y, ymax); + + y = lrint (p3_d.y); + ymin = MIN (y, ymin); + ymax = MAX (y, ymax); + + /* test if there is no more pixel in the triangle */ + if (xmin == xmax || ymin == ymax) + return; + + /* test if the triangle is implausibly large as manifested by too deep recursion */ + if (recursion_depth > 5) + return; + + /* test if the triangle is small enough. + * + * if yes, we compute the coefficient of the barycenter for the + * pixel (x,y) and see if a pixel is inside (ie the 3 coef have the + * same sign). + */ + if (xmax - xmin == 1 && ymax - ymin == 1) + { + gdouble a, b, c, denom, x, y; + + x = (gdouble) xmin + 0.5; + y = (gdouble) ymin + 0.5; + + denom = (p2_d.x - p1_d.x) * p3_d.y + (p1_d.x - p3_d.x) * p2_d.y + (p3_d.x - p2_d.x) * p1_d.y; + a = ((p2_d.x - x) * p3_d.y + (x - p3_d.x) * p2_d.y + (p3_d.x - p2_d.x) * y) / denom; + b = - ((p1_d.x - x) * p3_d.y + (x - p3_d.x) * p1_d.y + (p3_d.x - p1_d.x) * y) / denom; + c = 1.0 - a - b; + + /* if a pixel is inside, we compute its source coordinate and + * set it in the output buffer + */ + if ((a > 0 && b > 0 && c > 0) || (a < 0 && b < 0 && c < 0)) + { + GeglRectangle rect = { 0, 0, 1, 1 }; + gfloat coords[2]; + + rect.x = xmin; + rect.y = ymin; + + coords[0] = (a * p1_s.x + b * p2_s.x + c * p3_s.x); + coords[1] = (a * p1_s.y + b * p2_s.y + c * p3_s.y); + + gegl_buffer_set (out_buf, + &rect, + 0, + oct->format_coords, + coords, + GEGL_AUTO_ROWSTRIDE); + } + + return; + } + else + { + /* we cut the triangle in 4 sub-triangle and treat it recursively */ + /* + * /\ + * /__\ + * /\ /\ + * /__\/__\ + * + */ + + GimpVector2 pm1_d, pm2_d, pm3_d; + GimpVector2 pm1_s, pm2_s, pm3_s; + gint next_depth = recursion_depth + 1; + + pm1_d.x = (p1_d.x + p2_d.x) / 2.0; + pm1_d.y = (p1_d.y + p2_d.y) / 2.0; + + pm2_d.x = (p2_d.x + p3_d.x) / 2.0; + pm2_d.y = (p2_d.y + p3_d.y) / 2.0; + + pm3_d.x = (p3_d.x + p1_d.x) / 2.0; + pm3_d.y = (p3_d.y + p1_d.y) / 2.0; + + pm1_s.x = (p1_s.x + p2_s.x) / 2.0; + pm1_s.y = (p1_s.y + p2_s.y) / 2.0; + + pm2_s.x = (p2_s.x + p3_s.x) / 2.0; + pm2_s.y = (p2_s.y + p3_s.y) / 2.0; + + pm3_s.x = (p3_s.x + p1_s.x) / 2.0; + pm3_s.y = (p3_s.y + p1_s.y) / 2.0; + + gimp_operation_cage_transform_interpolate_source_coords_recurs (oct, + out_buf, + roi, + p1_s, p1_d, + pm1_s, pm1_d, + pm3_s, pm3_d, + next_depth, + coords); + + gimp_operation_cage_transform_interpolate_source_coords_recurs (oct, + out_buf, + roi, + pm1_s, pm1_d, + p2_s, p2_d, + pm2_s, pm2_d, + next_depth, + coords); + + gimp_operation_cage_transform_interpolate_source_coords_recurs (oct, + out_buf, + roi, + pm1_s, pm1_d, + pm2_s, pm2_d, + pm3_s, pm3_d, + next_depth, + coords); + + gimp_operation_cage_transform_interpolate_source_coords_recurs (oct, + out_buf, + roi, + pm3_s, pm3_d, + pm2_s, pm2_d, + p3_s, p3_d, + next_depth, + coords); + } +} + +static GimpVector2 +gimp_cage_transform_compute_destination (GimpCageConfig *config, + gfloat *coef, + GeglSampler *coef_sampler, + GimpVector2 coords) +{ + GimpVector2 result = {0, 0}; + gint n_cage_vertices = gimp_cage_config_get_n_points (config); + gint i; + GimpCagePoint *point; + + gegl_sampler_get (coef_sampler, + coords.x, coords.y, NULL, coef, GEGL_ABYSS_NONE); + + for (i = 0; i < n_cage_vertices; i++) + { + point = &g_array_index (config->cage_points, GimpCagePoint, i); + + result.x += coef[i] * point->dest_point.x; + result.y += coef[i] * point->dest_point.y; + + result.x += coef[i + n_cage_vertices] * point->edge_scaling_factor * point->edge_normal.x; + result.y += coef[i + n_cage_vertices] * point->edge_scaling_factor * point->edge_normal.y; + } + + return result; +} + +GeglRectangle +gimp_operation_cage_transform_get_cached_region (GeglOperation *operation, + const GeglRectangle *roi) +{ + GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, + "input"); + + return result; +} + +GeglRectangle +gimp_operation_cage_transform_get_required_for_output (GeglOperation *operation, + const gchar *input_pad, + const GeglRectangle *roi) +{ + GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, + "input"); + + return result; +} + +GeglRectangle +gimp_operation_cage_transform_get_bounding_box (GeglOperation *operation) +{ + GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, + "input"); + + return result; +} diff --git a/app/operations/gimpoperationcagetransform.h b/app/operations/gimpoperationcagetransform.h new file mode 100644 index 0000000..8ee9286 --- /dev/null +++ b/app/operations/gimpoperationcagetransform.h @@ -0,0 +1,58 @@ +/* GIMP - The GNU Image Manipulation Program + * + * gimpoperationcagetransform.h + * Copyright (C) 2010 Michael Muré <batolettre@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_CAGE_TRANSFORM_H__ +#define __GIMP_OPERATION_CAGE_TRANSFORM_H__ + + +#include <gegl-plugin.h> +#include <operation/gegl-operation-composer.h> + + +#define GIMP_TYPE_OPERATION_CAGE_TRANSFORM (gimp_operation_cage_transform_get_type ()) +#define GIMP_OPERATION_CAGE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_CAGE_TRANSFORM, GimpOperationCageTransform)) +#define GIMP_OPERATION_CAGE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_CAGE_TRANSFORM, GimpOperationCageTransformClass)) +#define GIMP_IS_OPERATION_CAGE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_CAGE_TRANSFORM)) +#define GIMP_IS_OPERATION_CAGE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_CAGE_TRANSFORM)) +#define GIMP_OPERATION_CAGE_TRANSFORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_CAGE_TRANSFORM, GimpOperationCageTransformClass)) + + +typedef struct _GimpOperationCageTransform GimpOperationCageTransform; +typedef struct _GimpOperationCageTransformClass GimpOperationCageTransformClass; + +struct _GimpOperationCageTransform +{ + GeglOperationComposer parent_instance; + + GimpCageConfig *config; + gboolean fill_plain_color; + + const Babl *format_coords; +}; + +struct _GimpOperationCageTransformClass +{ + GeglOperationComposerClass parent_class; +}; + + +GType gimp_operation_cage_transform_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_CAGE_TRANSFORM_H__ */ diff --git a/app/operations/gimpoperationcolorbalance.c b/app/operations/gimpoperationcolorbalance.c new file mode 100644 index 0000000..9988158 --- /dev/null +++ b/app/operations/gimpoperationcolorbalance.c @@ -0,0 +1,198 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationcolorbalance.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimpcolorbalanceconfig.h" +#include "gimpoperationcolorbalance.h" + +#include "gimp-intl.h" + + +static gboolean gimp_operation_color_balance_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationColorBalance, gimp_operation_color_balance, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_color_balance_parent_class + + +static void +gimp_operation_color_balance_class_init (GimpOperationColorBalanceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_point_filter_set_property; + object_class->get_property = gimp_operation_point_filter_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:color-balance", + "categories", "color", + "description", _("Adjust color distribution"), + NULL); + + point_class->process = gimp_operation_color_balance_process; + + g_object_class_install_property (object_class, + GIMP_OPERATION_POINT_FILTER_PROP_CONFIG, + g_param_spec_object ("config", + "Config", + "The config object", + GIMP_TYPE_COLOR_BALANCE_CONFIG, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_color_balance_init (GimpOperationColorBalance *self) +{ +} + +static inline gfloat +gimp_operation_color_balance_map (gfloat value, + gdouble lightness, + gdouble shadows, + gdouble midtones, + gdouble highlights) +{ + /* Apply masks to the corrections for shadows, midtones and + * highlights so that each correction affects only one range. + * Those masks look like this: + * ‾\___ + * _/‾\_ + * ___/‾ + * with ramps of width a at x = b and x = 1 - b. + * + * The sum of these masks equals 1 for x in 0..1, so applying the + * same correction in the shadows and in the midtones is equivalent + * to applying this correction on a virtual shadows_and_midtones + * range. + */ + static const gdouble a = 0.25, b = 0.333, scale = 0.7; + + shadows *= CLAMP ((lightness - b) / -a + 0.5, 0, 1) * scale; + midtones *= CLAMP ((lightness - b) / a + 0.5, 0, 1) * + CLAMP ((lightness + b - 1) / -a + 0.5, 0, 1) * scale; + highlights *= CLAMP ((lightness + b - 1) / a + 0.5, 0, 1) * scale; + + value += shadows; + value += midtones; + value += highlights; + value = CLAMP (value, 0.0, 1.0); + + return value; +} + +static gboolean +gimp_operation_color_balance_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationPointFilter *point = GIMP_OPERATION_POINT_FILTER (operation); + GimpColorBalanceConfig *config = GIMP_COLOR_BALANCE_CONFIG (point->config); + gfloat *src = in_buf; + gfloat *dest = out_buf; + + if (! config) + return FALSE; + + while (samples--) + { + gfloat r = src[RED]; + gfloat g = src[GREEN]; + gfloat b = src[BLUE]; + gfloat r_n; + gfloat g_n; + gfloat b_n; + + GimpRGB rgb = { r, g, b}; + GimpHSL hsl; + + gimp_rgb_to_hsl (&rgb, &hsl); + + r_n = gimp_operation_color_balance_map (r, hsl.l, + config->cyan_red[GIMP_TRANSFER_SHADOWS], + config->cyan_red[GIMP_TRANSFER_MIDTONES], + config->cyan_red[GIMP_TRANSFER_HIGHLIGHTS]); + + g_n = gimp_operation_color_balance_map (g, hsl.l, + config->magenta_green[GIMP_TRANSFER_SHADOWS], + config->magenta_green[GIMP_TRANSFER_MIDTONES], + config->magenta_green[GIMP_TRANSFER_HIGHLIGHTS]); + + b_n = gimp_operation_color_balance_map (b, hsl.l, + config->yellow_blue[GIMP_TRANSFER_SHADOWS], + config->yellow_blue[GIMP_TRANSFER_MIDTONES], + config->yellow_blue[GIMP_TRANSFER_HIGHLIGHTS]); + + if (config->preserve_luminosity) + { + GimpHSL hsl2; + + rgb.r = r_n; + rgb.g = g_n; + rgb.b = b_n; + gimp_rgb_to_hsl (&rgb, &hsl); + + rgb.r = r; + rgb.g = g; + rgb.b = b; + gimp_rgb_to_hsl (&rgb, &hsl2); + + hsl.l = hsl2.l; + + gimp_hsl_to_rgb (&hsl, &rgb); + + r_n = rgb.r; + g_n = rgb.g; + b_n = rgb.b; + } + + dest[RED] = r_n; + dest[GREEN] = g_n; + dest[BLUE] = b_n; + dest[ALPHA] = src[ALPHA]; + + src += 4; + dest += 4; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationcolorbalance.h b/app/operations/gimpoperationcolorbalance.h new file mode 100644 index 0000000..a6ba386 --- /dev/null +++ b/app/operations/gimpoperationcolorbalance.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationcolorbalance.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_COLOR_BALANCE_H__ +#define __GIMP_OPERATION_COLOR_BALANCE_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_COLOR_BALANCE (gimp_operation_color_balance_get_type ()) +#define GIMP_OPERATION_COLOR_BALANCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_COLOR_BALANCE, GimpOperationColorBalance)) +#define GIMP_OPERATION_COLOR_BALANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_COLOR_BALANCE, GimpOperationColorBalanceClass)) +#define GIMP_IS_OPERATION_COLOR_BALANCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_COLOR_BALANCE)) +#define GIMP_IS_OPERATION_COLOR_BALANCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_COLOR_BALANCE)) +#define GIMP_OPERATION_COLOR_BALANCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_COLOR_BALANCE, GimpOperationColorBalanceClass)) + + +typedef struct _GimpOperationColorBalance GimpOperationColorBalance; +typedef struct _GimpOperationColorBalanceClass GimpOperationColorBalanceClass; + +struct _GimpOperationColorBalance +{ + GimpOperationPointFilter parent_instance; +}; + +struct _GimpOperationColorBalanceClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_color_balance_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_COLOR_BALANCE_H__ */ diff --git a/app/operations/gimpoperationcolorize.c b/app/operations/gimpoperationcolorize.c new file mode 100644 index 0000000..fd64840 --- /dev/null +++ b/app/operations/gimpoperationcolorize.c @@ -0,0 +1,274 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationcolorize.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "gimpoperationcolorize.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_HUE, + PROP_SATURATION, + PROP_LIGHTNESS, + PROP_COLOR +}; + + +static void gimp_operation_colorize_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_colorize_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gboolean gimp_operation_colorize_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationColorize, gimp_operation_colorize, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_colorize_parent_class + + +static void +gimp_operation_colorize_class_init (GimpOperationColorizeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + GimpHSL hsl; + GimpRGB rgb; + + object_class->set_property = gimp_operation_colorize_set_property; + object_class->get_property = gimp_operation_colorize_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:colorize", + "categories", "color", + "description", _("Colorize the image"), + NULL); + + point_class->process = gimp_operation_colorize_process; + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_HUE, + "hue", + _("Hue"), + _("Hue"), + 0.0, 1.0, 0.5, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_SATURATION, + "saturation", + _("Saturation"), + _("Saturation"), + 0.0, 1.0, 0.5, 0); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LIGHTNESS, + "lightness", + _("Lightness"), + _("Lightness"), + -1.0, 1.0, 0.0, 0); + + gimp_hsl_set (&hsl, 0.5, 0.5, 0.5); + gimp_hsl_set_alpha (&hsl, 1.0); + gimp_hsl_to_rgb (&hsl, &rgb); + + g_object_class_install_property (object_class, PROP_COLOR, + gimp_param_spec_rgb ("color", + _("Color"), + _("Color"), + FALSE, &rgb, + G_PARAM_READWRITE)); +} + +static void +gimp_operation_colorize_init (GimpOperationColorize *self) +{ +} + +static void +gimp_operation_colorize_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationColorize *self = GIMP_OPERATION_COLORIZE (object); + + switch (property_id) + { + case PROP_HUE: + g_value_set_double (value, self->hue); + break; + + case PROP_SATURATION: + g_value_set_double (value, self->saturation); + break; + + case PROP_LIGHTNESS: + g_value_set_double (value, self->lightness); + break; + + case PROP_COLOR: + { + GimpHSL hsl; + GimpRGB rgb; + + gimp_hsl_set (&hsl, + self->hue, + self->saturation, + (self->lightness + 1.0) / 2.0); + gimp_hsl_set_alpha (&hsl, 1.0); + gimp_hsl_to_rgb (&hsl, &rgb); + gimp_value_set_rgb (value, &rgb); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_colorize_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationColorize *self = GIMP_OPERATION_COLORIZE (object); + + switch (property_id) + { + case PROP_HUE: + self->hue = g_value_get_double (value); + g_object_notify (object, "color"); + break; + + case PROP_SATURATION: + self->saturation = g_value_get_double (value); + g_object_notify (object, "color"); + break; + + case PROP_LIGHTNESS: + self->lightness = g_value_get_double (value); + g_object_notify (object, "color"); + break; + + case PROP_COLOR: + { + GimpRGB rgb; + GimpHSL hsl; + + gimp_value_get_rgb (value, &rgb); + gimp_rgb_to_hsl (&rgb, &hsl); + + if (hsl.h == -1) + hsl.h = self->hue; + + if (hsl.l == 0.0 || hsl.l == 1.0) + hsl.s = self->saturation; + + g_object_set (self, + "hue", hsl.h, + "saturation", hsl.s, + "lightness", hsl.l * 2.0 - 1.0, + NULL); + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gboolean +gimp_operation_colorize_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationColorize *colorize = GIMP_OPERATION_COLORIZE (operation); + gfloat *src = in_buf; + gfloat *dest = out_buf; + GimpHSL hsl; + + hsl.h = colorize->hue; + hsl.s = colorize->saturation; + + while (samples--) + { + GimpRGB rgb; + gfloat lum = GIMP_RGB_LUMINANCE (src[RED], + src[GREEN], + src[BLUE]); + + if (colorize->lightness > 0) + { + lum = lum * (1.0 - colorize->lightness); + + lum += 1.0 - (1.0 - colorize->lightness); + } + else if (colorize->lightness < 0) + { + lum = lum * (colorize->lightness + 1.0); + } + + hsl.l = lum; + + gimp_hsl_to_rgb (&hsl, &rgb); + + /* the code in base/colorize.c would multiply r,b,g with lum, + * but this is a bug since it should multiply with 255. We + * don't repeat this bug here (this is the reason why the gegl + * colorize is brighter than the legacy one). + */ + dest[RED] = rgb.r; /* * lum */ + dest[GREEN] = rgb.g; /* * lum */ + dest[BLUE] = rgb.b; /* * lum */ + dest[ALPHA] = src[ALPHA]; + + src += 4; + dest += 4; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationcolorize.h b/app/operations/gimpoperationcolorize.h new file mode 100644 index 0000000..cfb5545 --- /dev/null +++ b/app/operations/gimpoperationcolorize.h @@ -0,0 +1,57 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationcolorize.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_COLORIZE_H__ +#define __GIMP_OPERATION_COLORIZE_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_COLORIZE (gimp_operation_colorize_get_type ()) +#define GIMP_OPERATION_COLORIZE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_COLORIZE, GimpOperationColorize)) +#define GIMP_OPERATION_COLORIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_COLORIZE, GimpOperationColorizeClass)) +#define GIMP_IS_OPERATION_COLORIZE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_COLORIZE)) +#define GIMP_IS_OPERATION_COLORIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_COLORIZE)) +#define GIMP_OPERATION_COLORIZE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_COLORIZE, GimpOperationColorizeClass)) + + +typedef struct _GimpOperationColorize GimpOperationColorize; +typedef struct _GimpOperationColorizeClass GimpOperationColorizeClass; + +struct _GimpOperationColorize +{ + GimpOperationPointFilter parent_instance; + + gdouble hue; + gdouble saturation; + gdouble lightness; +}; + +struct _GimpOperationColorizeClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_colorize_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_COLORIZE_H__ */ diff --git a/app/operations/gimpoperationcomposecrop.c b/app/operations/gimpoperationcomposecrop.c new file mode 100644 index 0000000..25e6247 --- /dev/null +++ b/app/operations/gimpoperationcomposecrop.c @@ -0,0 +1,329 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationcomposecrop.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * Copyright (C) 2016 Massimo Valentini <mvalentini@src.gnome.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "operations-types.h" + +#include "gimpoperationcomposecrop.h" + + +enum +{ + PROP_0, + PROP_X, + PROP_Y, + PROP_WIDTH, + PROP_HEIGHT +}; + + +static void gimp_operation_compose_crop_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_compose_crop_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_compose_crop_prepare (GeglOperation *operation); +static GeglRectangle gimp_operation_compose_crop_get_required_for_output (GeglOperation *operation, + const gchar *input_pad, + const GeglRectangle *output_roi); +static gboolean gimp_operation_compose_crop_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_pad, + const GeglRectangle *roi, + gint level); + +static gboolean gimp_operation_compose_crop_process (GeglOperation *operation, + void *in_buf, + void *aux_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationComposeCrop, gimp_operation_compose_crop, + GEGL_TYPE_OPERATION_POINT_COMPOSER) + +#define parent_class gimp_operation_compose_crop_parent_class + + +static void +gimp_operation_compose_crop_class_init (GimpOperationComposeCropClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointComposerClass *point_class = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass); + + object_class->set_property = gimp_operation_compose_crop_set_property; + object_class->get_property = gimp_operation_compose_crop_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:compose-crop", + "categories", "gimp", + "description", "Selectively pick components from src or aux", + NULL); + + operation_class->prepare = gimp_operation_compose_crop_prepare; + operation_class->get_invalidated_by_change = gimp_operation_compose_crop_get_required_for_output; + operation_class->get_required_for_output = gimp_operation_compose_crop_get_required_for_output; + operation_class->process = gimp_operation_compose_crop_parent_process; + + point_class->process = gimp_operation_compose_crop_process; + + g_object_class_install_property (object_class, PROP_X, + g_param_spec_int ("x", + "x", + "x", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, PROP_Y, + g_param_spec_int ("y", + "y", + "y", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, PROP_WIDTH, + g_param_spec_int ("width", + "width", + "width", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + g_object_class_install_property (object_class, PROP_HEIGHT, + g_param_spec_int ("height", + "height", + "height", + 0, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_compose_crop_init (GimpOperationComposeCrop *self) +{ +} + +static void +gimp_operation_compose_crop_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationComposeCrop *self = GIMP_OPERATION_COMPOSE_CROP (object); + + switch (property_id) + { + case PROP_X: + g_value_set_int (value, self->rect.x); + break; + case PROP_Y: + g_value_set_int (value, self->rect.y); + break; + case PROP_WIDTH: + g_value_set_int (value, self->rect.width); + break; + case PROP_HEIGHT: + g_value_set_int (value, self->rect.height); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_compose_crop_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationComposeCrop *self = GIMP_OPERATION_COMPOSE_CROP (object); + + switch (property_id) + { + case PROP_X: + self->rect.x = g_value_get_int (value); + break; + case PROP_Y: + self->rect.y = g_value_get_int (value); + break; + case PROP_WIDTH: + self->rect.width = g_value_get_int (value); + break; + case PROP_HEIGHT: + self->rect.height = g_value_get_int (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_compose_crop_prepare (GeglOperation *operation) +{ + const Babl *input_format = gegl_operation_get_source_format (operation, "input"); + const Babl *aux_format = gegl_operation_get_source_format (operation, "aux"); + const Babl *format; + + if (input_format) + { + if (input_format == aux_format) + { + format = input_format; + } + else + { + const Babl *model = babl_format_get_model (input_format); + + if (model == babl_model ("R'G'B'A")) + format = babl_format_with_space ("R'G'B'A float", input_format); + else + format = babl_format_with_space ("RGBA float", input_format); + } + } + else + { + format = babl_format_with_space ("RGBA float", input_format); + } + + gegl_operation_set_format (operation, "input", format); + gegl_operation_set_format (operation, "aux", format); + gegl_operation_set_format (operation, "output", format); +} + +static GeglRectangle +gimp_operation_compose_crop_get_required_for_output (GeglOperation *operation, + const gchar *input_pad, + const GeglRectangle *output_roi) +{ + GimpOperationComposeCrop *self = GIMP_OPERATION_COMPOSE_CROP (operation); + GeglRectangle result; + + if (! strcmp (input_pad, "input")) + gegl_rectangle_intersect (&result, output_roi, &self->rect); + else if (! strcmp (input_pad, "aux")) + gegl_rectangle_subtract_bounding_box (&result, output_roi, &self->rect); + else + g_return_val_if_reached (*output_roi); + + return result; +} + +static gboolean +gimp_operation_compose_crop_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_pad, + const GeglRectangle *roi, + gint level) +{ + GimpOperationComposeCrop *self = GIMP_OPERATION_COMPOSE_CROP (operation); + + if (gegl_rectangle_contains (&self->rect, roi)) + { + GObject *input; + + input = gegl_operation_context_get_object (context, "input"); + gegl_operation_context_set_object (context, "output", input); + + return TRUE; + } + else if (! gegl_rectangle_intersect (NULL, &self->rect, roi)) + { + GObject *aux; + + aux = gegl_operation_context_get_object (context, "aux"); + gegl_operation_context_set_object (context, "output", aux); + + return TRUE; + } + + return GEGL_OPERATION_CLASS (parent_class)->process (operation, context, + output_pad, roi, level); +} + +static gboolean +gimp_operation_compose_crop_process (GeglOperation *operation, + void *in_buf, + void *aux_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationComposeCrop *self = GIMP_OPERATION_COMPOSE_CROP (operation); + const Babl *format = gegl_operation_get_format (operation, "output"); + gint bpp = babl_format_get_bytes_per_pixel (format); + const guchar *in = in_buf; + const guchar *aux = aux_buf; + guchar *out = out_buf; + gint x0, x1; + gint y0, y1; + gint y; + +#define COPY(src, n) \ + do \ + { \ + gint size = (n) * bpp; \ + \ + if (src) \ + memcpy (out, (src), size); \ + else \ + memset (out, 0, size); \ + \ + in += size; \ + if (aux) aux += size; \ + out += size; \ + } \ + while (FALSE) + + x0 = CLAMP (self->rect.x, roi->x, roi->x + roi->width); + x1 = CLAMP (self->rect.x + self->rect.width, roi->x, roi->x + roi->width); + + y0 = CLAMP (self->rect.y, roi->y, roi->y + roi->height); + y1 = CLAMP (self->rect.y + self->rect.height, roi->y, roi->y + roi->height); + + COPY (aux, (y0 - roi->y) * roi->width); + + for (y = y0; y < y1; y++) + { + COPY (aux, x0 - roi->x); + COPY (in, x1 - x0); + COPY (aux, roi->x + roi->width - x1); + } + + COPY (aux, (roi->y + roi->height - y1) * roi->width); + +#undef COPY + + return TRUE; +} diff --git a/app/operations/gimpoperationcomposecrop.h b/app/operations/gimpoperationcomposecrop.h new file mode 100644 index 0000000..83b7613 --- /dev/null +++ b/app/operations/gimpoperationcomposecrop.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationcomposecrop.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * Copyright (C) 2016 Massimo Valentini <mvalentini@src.gnome.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_COMPOSE_CROP_H__ +#define __GIMP_OPERATION_COMPOSE_CROP_H__ + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_COMPOSE_CROP (gimp_operation_compose_crop_get_type ()) +#define GIMP_OPERATION_COMPOSE_CROP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_COMPOSE_CROP, GimpOperationComposeCrop)) +#define GIMP_OPERATION_COMPOSE_CROP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_COMPOSE_CROP, GimpOperationComposeCropClass)) +#define GIMP_IS_OPERATION_COMPOSE_CROP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_COMPOSE_CROP)) +#define GIMP_IS_OPERATION_COMPOSE_CROP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_COMPOSE_CROP)) +#define GIMP_OPERATION_COMPOSE_CROP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_COMPOSE_CROP, GimpOperationComposeCropClass)) + + +typedef struct _GimpOperationComposeCrop GimpOperationComposeCrop; +typedef struct _GimpOperationComposeCropClass GimpOperationComposeCropClass; + +struct _GimpOperationComposeCrop +{ + GeglOperationPointComposer parent_instance; + + GeglRectangle rect; +}; + +struct _GimpOperationComposeCropClass +{ + GeglOperationPointComposerClass parent_class; +}; + + +GType gimp_operation_compose_crop_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_COMPOSE_CROP_H__ */ diff --git a/app/operations/gimpoperationcurves.c b/app/operations/gimpoperationcurves.c new file mode 100644 index 0000000..e83b142 --- /dev/null +++ b/app/operations/gimpoperationcurves.c @@ -0,0 +1,118 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationcurves.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "core/gimpcurve.h" +#include "core/gimpcurve-map.h" + +#include "gimpcurvesconfig.h" +#include "gimpoperationcurves.h" + +#include "gimp-intl.h" + + +static gboolean gimp_operation_curves_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationCurves, gimp_operation_curves, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_curves_parent_class + + +static void +gimp_operation_curves_class_init (GimpOperationCurvesClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_point_filter_set_property; + object_class->get_property = gimp_operation_point_filter_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:curves", + "categories", "color", + "description", _("Adjust color curves"), + NULL); + + point_class->process = gimp_operation_curves_process; + + g_object_class_install_property (object_class, + GIMP_OPERATION_POINT_FILTER_PROP_LINEAR, + g_param_spec_boolean ("linear", + "Linear", + "Whether to operate on linear RGB", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + GIMP_OPERATION_POINT_FILTER_PROP_CONFIG, + g_param_spec_object ("config", + "Config", + "The config object", + GIMP_TYPE_CURVES_CONFIG, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_curves_init (GimpOperationCurves *self) +{ +} + +static gboolean +gimp_operation_curves_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationPointFilter *point = GIMP_OPERATION_POINT_FILTER (operation); + GimpCurvesConfig *config = GIMP_CURVES_CONFIG (point->config); + gfloat *src = in_buf; + gfloat *dest = out_buf; + + if (! config) + return FALSE; + + gimp_curve_map_pixels (config->curve[0], + config->curve[1], + config->curve[2], + config->curve[3], + config->curve[4], src, dest, samples); + + return TRUE; +} diff --git a/app/operations/gimpoperationcurves.h b/app/operations/gimpoperationcurves.h new file mode 100644 index 0000000..ab097b2 --- /dev/null +++ b/app/operations/gimpoperationcurves.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationcurves.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_CURVES_H__ +#define __GIMP_OPERATION_CURVES_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_CURVES (gimp_operation_curves_get_type ()) +#define GIMP_OPERATION_CURVES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_CURVES, GimpOperationCurves)) +#define GIMP_OPERATION_CURVES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_CURVES, GimpOperationCurvesClass)) +#define GIMP_IS_OPERATION_CURVES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_CURVES)) +#define GIMP_IS_OPERATION_CURVES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_CURVES)) +#define GIMP_OPERATION_CURVES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_CURVES, GimpOperationCurvesClass)) + + +typedef struct _GimpOperationCurves GimpOperationCurves; +typedef struct _GimpOperationCurvesClass GimpOperationCurvesClass; + +struct _GimpOperationCurves +{ + GimpOperationPointFilter parent_instance; +}; + +struct _GimpOperationCurvesClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_curves_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_CURVES_H__ */ diff --git a/app/operations/gimpoperationdesaturate.c b/app/operations/gimpoperationdesaturate.c new file mode 100644 index 0000000..9f833db --- /dev/null +++ b/app/operations/gimpoperationdesaturate.c @@ -0,0 +1,257 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdesaturate.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "gimpoperationdesaturate.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_MODE +}; + + +static void gimp_operation_desaturate_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_desaturate_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_desaturate_prepare (GeglOperation *operation); +static gboolean gimp_operation_desaturate_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationDesaturate, gimp_operation_desaturate, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_desaturate_parent_class + + +static void +gimp_operation_desaturate_class_init (GimpOperationDesaturateClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_desaturate_set_property; + object_class->get_property = gimp_operation_desaturate_get_property; + + operation_class->prepare = gimp_operation_desaturate_prepare; + + point_class->process = gimp_operation_desaturate_process; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:desaturate", + "categories", "color", + "description", _("Turn colors into shades of gray"), + NULL); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_MODE, + "mode", + _("Mode"), + _("Choose shade of gray based on"), + GIMP_TYPE_DESATURATE_MODE, + GIMP_DESATURATE_LUMINANCE, + GIMP_PARAM_STATIC_STRINGS); +} + +static void +gimp_operation_desaturate_init (GimpOperationDesaturate *self) +{ +} + +static void +gimp_operation_desaturate_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationDesaturate *desaturate = GIMP_OPERATION_DESATURATE (object); + + switch (property_id) + { + case PROP_MODE: + g_value_set_enum (value, desaturate->mode); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_desaturate_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationDesaturate *desaturate = GIMP_OPERATION_DESATURATE (object); + + switch (property_id) + { + case PROP_MODE: + desaturate->mode = g_value_get_enum (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_desaturate_prepare (GeglOperation *operation) +{ + GimpOperationDesaturate *desaturate = GIMP_OPERATION_DESATURATE (operation); + const Babl *format = gegl_operation_get_source_format (operation, "input"); + + if (desaturate->mode == GIMP_DESATURATE_LUMINANCE) + { + format = babl_format_with_space ("RGBA float", format); + } + else + { + format = babl_format_with_space ("R'G'B'A float", format); + } + + gegl_operation_set_format (operation, "input", format); + gegl_operation_set_format (operation, "output", format); +} + +static gboolean +gimp_operation_desaturate_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationDesaturate *desaturate = GIMP_OPERATION_DESATURATE (operation); + gfloat *src = in_buf; + gfloat *dest = out_buf; + + switch (desaturate->mode) + { + case GIMP_DESATURATE_LIGHTNESS: + /* This is the formula for Lightness in the HSL "bi-hexcone" + * model: https://en.wikipedia.org/wiki/HSL_and_HSV + */ + while (samples--) + { + gfloat min, max, value; + + max = MAX (src[0], src[1]); + max = MAX (max, src[2]); + min = MIN (src[0], src[1]); + min = MIN (min, src[2]); + + value = (max + min) / 2; + + dest[0] = value; + dest[1] = value; + dest[2] = value; + dest[3] = src[3]; + + src += 4; + dest += 4; + } + break; + + case GIMP_DESATURATE_LUMA: + case GIMP_DESATURATE_LUMINANCE: + while (samples--) + { + gfloat value = GIMP_RGB_LUMINANCE (src[0], src[1], src[2]); + + dest[0] = value; + dest[1] = value; + dest[2] = value; + dest[3] = src[3]; + + src += 4; + dest += 4; + } + break; + + case GIMP_DESATURATE_AVERAGE: + /* This is the formula for Intensity in the HSI model: + * https://en.wikipedia.org/wiki/HSL_and_HSV + */ + while (samples--) + { + gfloat value = (src[0] + src[1] + src[2]) / 3; + + dest[0] = value; + dest[1] = value; + dest[2] = value; + dest[3] = src[3]; + + src += 4; + dest += 4; + } + break; + + case GIMP_DESATURATE_VALUE: + /* This is the formula for Value in the HSV model: + * https://en.wikipedia.org/wiki/HSL_and_HSV + */ + while (samples--) + { + gfloat value; + + value = MAX (src[0], src[1]); + value = MAX (value, src[2]); + + dest[0] = value; + dest[1] = value; + dest[2] = value; + dest[3] = src[3]; + + src += 4; + dest += 4; + } + break; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationdesaturate.h b/app/operations/gimpoperationdesaturate.h new file mode 100644 index 0000000..3117a61 --- /dev/null +++ b/app/operations/gimpoperationdesaturate.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdesaturate.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_DESATURATE_H__ +#define __GIMP_OPERATION_DESATURATE_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_DESATURATE (gimp_operation_desaturate_get_type ()) +#define GIMP_OPERATION_DESATURATE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_DESATURATE, GimpOperationDesaturate)) +#define GIMP_OPERATION_DESATURATE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_DESATURATE, GimpOperationDesaturateClass)) +#define GIMP_IS_OPERATION_DESATURATE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_DESATURATE)) +#define GIMP_IS_OPERATION_DESATURATE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_DESATURATE)) +#define GIMP_OPERATION_DESATURATE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_DESATURATE, GimpOperationDesaturateClass)) + + +typedef struct _GimpOperationDesaturate GimpOperationDesaturate; +typedef struct _GimpOperationDesaturateClass GimpOperationDesaturateClass; + +struct _GimpOperationDesaturate +{ + GimpOperationPointFilter parent_instance; + + GimpDesaturateMode mode; +}; + +struct _GimpOperationDesaturateClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_desaturate_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_DESATURATE_H__ */ diff --git a/app/operations/gimpoperationequalize.c b/app/operations/gimpoperationequalize.c new file mode 100644 index 0000000..119be23 --- /dev/null +++ b/app/operations/gimpoperationequalize.c @@ -0,0 +1,248 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationequalize.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "core/gimphistogram.h" + +#include "gimpoperationequalize.h" + + +enum +{ + PROP_0, + PROP_HISTOGRAM +}; + + +static void gimp_operation_equalize_finalize (GObject *object); +static void gimp_operation_equalize_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_equalize_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gboolean gimp_operation_equalize_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationEqualize, gimp_operation_equalize, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_equalize_parent_class + + +static void +gimp_operation_equalize_class_init (GimpOperationEqualizeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->finalize = gimp_operation_equalize_finalize; + object_class->set_property = gimp_operation_equalize_set_property; + object_class->get_property = gimp_operation_equalize_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:equalize", + "categories", "color", + "description", "GIMP Equalize operation", + NULL); + + point_class->process = gimp_operation_equalize_process; + + g_object_class_install_property (object_class, PROP_HISTOGRAM, + g_param_spec_object ("histogram", + "Histogram", + "The histogram", + GIMP_TYPE_HISTOGRAM, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gimp_operation_equalize_init (GimpOperationEqualize *self) +{ + self->values = NULL; + self->n_bins = 0; +} + +static void +gimp_operation_equalize_finalize (GObject *object) +{ + GimpOperationEqualize *self = GIMP_OPERATION_EQUALIZE (object); + + g_clear_pointer (&self->values, g_free); + g_clear_object (&self->histogram); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_operation_equalize_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationEqualize *self = GIMP_OPERATION_EQUALIZE (object); + + switch (property_id) + { + case PROP_HISTOGRAM: + g_value_set_pointer (value, self->histogram); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_equalize_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationEqualize *self = GIMP_OPERATION_EQUALIZE (object); + + switch (property_id) + { + case PROP_HISTOGRAM: + if (self->histogram) + g_object_unref (self->histogram); + + self->histogram = g_value_dup_object (value); + + if (self->histogram) + { + gdouble pixels; + gint n_bins; + gint max; + gint k; + + n_bins = gimp_histogram_n_bins (self->histogram); + + if ((self->values != NULL) && (self->n_bins != n_bins)) + { + g_free (self->values); + self->values = NULL; + } + + if (self->values == NULL) + { + self->values = g_new (gdouble, 3 * n_bins); + } + + self->n_bins = n_bins; + + pixels = gimp_histogram_get_count (self->histogram, + GIMP_HISTOGRAM_VALUE, 0, n_bins - 1); + + if (gimp_histogram_n_components (self->histogram) == 1 || + gimp_histogram_n_components (self->histogram) == 2) + max = 1; + else + max = 3; + + for (k = 0; k < 3; k++) + { + gdouble sum = 0; + gint i; + + for (i = 0; i < n_bins; i++) + { + gdouble histi; + + histi = gimp_histogram_get_component (self->histogram, k, i); + + sum += histi; + + self->values[k * n_bins + i] = sum / pixels; + + if (max == 1) + { + self->values[n_bins + i] = self->values[i]; + self->values[2 * n_bins + i] = self->values[i]; + } + } + } + } + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static inline float +gimp_operation_equalize_map (GimpOperationEqualize *self, + gint component, + gfloat value) +{ + gint index; + index = component * self->n_bins + \ + (gint) (CLAMP (value * (self->n_bins - 1), 0.0, self->n_bins - 1)); + + return self->values[index]; +} + +static gboolean +gimp_operation_equalize_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationEqualize *self = GIMP_OPERATION_EQUALIZE (operation); + gfloat *src = in_buf; + gfloat *dest = out_buf; + + while (samples--) + { + dest[RED] = gimp_operation_equalize_map (self, RED, src[RED]); + dest[GREEN] = gimp_operation_equalize_map (self, GREEN, src[GREEN]); + dest[BLUE] = gimp_operation_equalize_map (self, BLUE, src[BLUE]); + dest[ALPHA] = src[ALPHA]; + + src += 4; + dest += 4; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationequalize.h b/app/operations/gimpoperationequalize.h new file mode 100644 index 0000000..ea03b18 --- /dev/null +++ b/app/operations/gimpoperationequalize.h @@ -0,0 +1,57 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationequalize.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_EQUALIZE_H__ +#define __GIMP_OPERATION_EQUALIZE_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_EQUALIZE (gimp_operation_equalize_get_type ()) +#define GIMP_OPERATION_EQUALIZE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_EQUALIZE, GimpOperationEqualize)) +#define GIMP_OPERATION_EQUALIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_EQUALIZE, GimpOperationEqualizeClass)) +#define GIMP_IS_OPERATION_EQUALIZE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_EQUALIZE)) +#define GIMP_IS_OPERATION_EQUALIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_EQUALIZE)) +#define GIMP_OPERATION_EQUALIZE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_EQUALIZE, GimpOperationEqualizeClass)) + + +typedef struct _GimpOperationEqualize GimpOperationEqualize; +typedef struct _GimpOperationEqualizeClass GimpOperationEqualizeClass; + +struct _GimpOperationEqualize +{ + GimpOperationPointFilter parent_instance; + + GimpHistogram *histogram; + gdouble *values; + gint n_bins; +}; + +struct _GimpOperationEqualizeClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_equalize_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_EQUALIZE_H__ */ diff --git a/app/operations/gimpoperationfillsource.c b/app/operations/gimpoperationfillsource.c new file mode 100644 index 0000000..5811611 --- /dev/null +++ b/app/operations/gimpoperationfillsource.c @@ -0,0 +1,254 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationfillsource.c + * Copyright (C) 2019 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl-plugin.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "operations-types.h" + +#include "core/gimpdrawable.h" +#include "core/gimpfilloptions.h" + +#include "gimpoperationfillsource.h" + + +enum +{ + PROP_0, + PROP_OPTIONS, + PROP_DRAWABLE, + PROP_PATTERN_OFFSET_X, + PROP_PATTERN_OFFSET_Y, +}; + + +static void gimp_operation_fill_source_dispose (GObject *object); +static void gimp_operation_fill_source_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_fill_source_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static GeglRectangle gimp_operation_fill_source_get_bounding_box (GeglOperation *operation); +static void gimp_operation_fill_source_prepare (GeglOperation *operation); +static gboolean gimp_operation_fill_source_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_pad, + const GeglRectangle *result, + gint level); + + +G_DEFINE_TYPE (GimpOperationFillSource, gimp_operation_fill_source, + GEGL_TYPE_OPERATION_SOURCE) + +#define parent_class gimp_operation_fill_source_parent_class + + +static void +gimp_operation_fill_source_class_init (GimpOperationFillSourceClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + + object_class->dispose = gimp_operation_fill_source_dispose; + object_class->set_property = gimp_operation_fill_source_set_property; + object_class->get_property = gimp_operation_fill_source_get_property; + + operation_class->get_bounding_box = gimp_operation_fill_source_get_bounding_box; + operation_class->prepare = gimp_operation_fill_source_prepare; + operation_class->process = gimp_operation_fill_source_process; + + operation_class->threaded = FALSE; + operation_class->cache_policy = GEGL_CACHE_POLICY_NEVER; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:fill-source", + "categories", "gimp", + "description", "GIMP Fill Source operation", + NULL); + + g_object_class_install_property (object_class, PROP_OPTIONS, + g_param_spec_object ("options", + "Options", + "Fill options", + GIMP_TYPE_FILL_OPTIONS, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_DRAWABLE, + g_param_spec_object ("drawable", + "Drawable", + "Fill drawable", + GIMP_TYPE_DRAWABLE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, PROP_PATTERN_OFFSET_X, + g_param_spec_int ("pattern-offset-x", + "Pattern X-offset", + "Pattern X-offset", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_PATTERN_OFFSET_Y, + g_param_spec_int ("pattern-offset-y", + "Pattern Y-offset", + "Pattern Y-offset", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_fill_source_init (GimpOperationFillSource *self) +{ +} + +static void +gimp_operation_fill_source_dispose (GObject *object) +{ + GimpOperationFillSource *fill_source = GIMP_OPERATION_FILL_SOURCE (object); + + g_clear_object (&fill_source->options); + g_clear_object (&fill_source->drawable); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gimp_operation_fill_source_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationFillSource *fill_source = GIMP_OPERATION_FILL_SOURCE (object); + + switch (property_id) + { + case PROP_OPTIONS: + g_value_set_object (value, fill_source->options); + break; + + case PROP_DRAWABLE: + g_value_set_object (value, fill_source->drawable); + break; + + case PROP_PATTERN_OFFSET_X: + g_value_set_int (value, fill_source->pattern_offset_x); + break; + + case PROP_PATTERN_OFFSET_Y: + g_value_set_int (value, fill_source->pattern_offset_y); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_fill_source_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationFillSource *fill_source = GIMP_OPERATION_FILL_SOURCE (object); + + switch (property_id) + { + case PROP_OPTIONS: + g_set_object (&fill_source->options, g_value_get_object (value)); + break; + + case PROP_DRAWABLE: + g_set_object (&fill_source->drawable, g_value_get_object (value)); + break; + + case PROP_PATTERN_OFFSET_X: + fill_source->pattern_offset_x = g_value_get_int (value); + break; + + case PROP_PATTERN_OFFSET_Y: + fill_source->pattern_offset_y = g_value_get_int (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static GeglRectangle +gimp_operation_fill_source_get_bounding_box (GeglOperation *operation) +{ + return gegl_rectangle_infinite_plane (); +} + +static void +gimp_operation_fill_source_prepare (GeglOperation *operation) +{ + GimpOperationFillSource *fill_source = GIMP_OPERATION_FILL_SOURCE (operation); + const Babl *format = NULL; + + if (fill_source->options && fill_source->drawable) + { + format = gimp_fill_options_get_format (fill_source->options, + fill_source->drawable); + } + + gegl_operation_set_format (operation, "output", format); +} + +static gboolean +gimp_operation_fill_source_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_pad, + const GeglRectangle *result, + gint level) +{ + GimpOperationFillSource *fill_source = GIMP_OPERATION_FILL_SOURCE (operation); + + if (fill_source->options && fill_source->drawable) + { + GeglBuffer *buffer; + GeglRectangle rect; + + gegl_rectangle_align_to_buffer ( + &rect, result, + gimp_drawable_get_buffer (fill_source->drawable), + GEGL_RECTANGLE_ALIGNMENT_SUPERSET); + + buffer = gimp_fill_options_create_buffer (fill_source->options, + fill_source->drawable, + &rect, + fill_source->pattern_offset_x, + fill_source->pattern_offset_y); + + gegl_operation_context_take_object (context, "output", G_OBJECT (buffer)); + } + + return TRUE; +} diff --git a/app/operations/gimpoperationfillsource.h b/app/operations/gimpoperationfillsource.h new file mode 100644 index 0000000..6a9f468 --- /dev/null +++ b/app/operations/gimpoperationfillsource.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationfillsource.h + * Copyright (C) 2019 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_FILL_SOURCE_H__ +#define __GIMP_OPERATION_FILL_SOURCE_H__ + + +#define GIMP_TYPE_OPERATION_FILL_SOURCE (gimp_operation_fill_source_get_type ()) +#define GIMP_OPERATION_FILL_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_FILL_SOURCE, GimpOperationFillSource)) +#define GIMP_OPERATION_FILL_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_FILL_SOURCE, GimpOperationFillSourceClass)) +#define GIMP_IS_OPERATION_FILL_SOURCE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_FILL_SOURCE)) +#define GIMP_IS_OPERATION_FILL_SOURCE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_FILL_SOURCE)) +#define GIMP_OPERATION_FILL_SOURCE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_FILL_SOURCE, GimpOperationFillSourceClass)) + + +typedef struct _GimpOperationFillSource GimpOperationFillSource; +typedef struct _GimpOperationFillSourceClass GimpOperationFillSourceClass; + +struct _GimpOperationFillSource +{ + GeglOperationSource parent_instance; + + GimpFillOptions *options; + GimpDrawable *drawable; + gint pattern_offset_x; + gint pattern_offset_y; +}; + +struct _GimpOperationFillSourceClass +{ + GeglOperationSourceClass parent_class; +}; + + +GType gimp_operation_fill_source_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_FILL_SOURCE_H__ */ diff --git a/app/operations/gimpoperationflood.c b/app/operations/gimpoperationflood.c new file mode 100644 index 0000000..b35fe2e --- /dev/null +++ b/app/operations/gimpoperationflood.c @@ -0,0 +1,1104 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationflood.c + * Copyright (C) 2016 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + + +/* Implementation of the Flood algorithm. + * See https://wiki.gimp.org/wiki/Algorithms:Flood for details. + */ + + +#include "config.h" + +#include <string.h> /* For `memcpy()`. */ + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpbase/gimpbase.h" + +#include "operations-types.h" + +#include "gimpoperationflood.h" + + +/* Maximal gap, in pixels, between consecutive dirty ranges, below (and + * including) which they are coalesced, at the beginning of the distribution + * step. + */ +#define GIMP_OPERATION_FLOOD_COALESCE_MAX_GAP 32 + + +typedef struct _GimpOperationFloodSegment GimpOperationFloodSegment; +typedef struct _GimpOperationFloodDirtyRange GimpOperationFloodDirtyRange; +typedef struct _GimpOperationFloodContext GimpOperationFloodContext; + + +/* A segment. */ +struct _GimpOperationFloodSegment +{ + /* A boolean flag indicating whether the image- and ROI-virtual coordinate + * systems should be transposed when processing this segment. TRUE iff the + * segment is vertical. + */ + guint transpose : 1; + + /* The y-coordinate of the segment, in the ROI-virtual coordinate system. */ + guint y : 8 * sizeof (guint) - 3; + /* The difference between the y-coordinates of the source segment and this + * segment, in the ROI-virtual coordinate system. Either -1 or +1 for + * ordinary segments, and 0 for seed segments, as a special case. + * + * Note the use of `signed` as the type specifier. The C standard doesn't + * specify the signedness of bit-fields whose type specifier is `int`, or a + * typedef-name defined as `int`, such as `gint`. + */ + signed source_y_delta : 2; + + /* The x-coordinates of the first and last pixels of the segment, in the ROI- + * virtual coordinate system. Note that this is a closed range: + * [x[0], x[1]]. + */ + gint x[2]; +}; +/* Make sure the maximal image dimension fits in + * `GimpOperationFloodSegment::y`. + */ +G_STATIC_ASSERT (GIMP_MAX_IMAGE_SIZE <= (1 << (8 * sizeof (guint) - 3))); + +/* A dirty range of the current segment. */ +struct _GimpOperationFloodDirtyRange +{ + /* A boolean flag indicating whether the range was extended, or its existing + * pixels were modified, during the horizontal propagation step. + */ + gboolean modified; + + /* The x-coordinates of the first and last pixels of the range, in the ROI- + * virtual coordinate system. Note that this is a closed range: + * [x[0], x[1]]. + */ + gint x[2]; +}; + +/* Common parameters for the various parts of the algorithm. */ +struct _GimpOperationFloodContext +{ + /* Input image. */ + GeglBuffer *input; + /* Input image format. */ + const Babl *input_format; + /* Output image. */ + GeglBuffer *output; + /* Output image format. */ + const Babl *output_format; + + /* Region of interset. */ + GeglRectangle roi; + + /* Current segment. */ + GimpOperationFloodSegment segment; + + /* The following arrays hold the ground- and water-level of the current- and + * source-segments. The vertical- and horizontal-propagation steps don't + * generally access the input and output GEGL buffers directly, but rather + * read from, and write to, these arrays, for efficiency. These arrays are + * read-from, and written-to, the corresponding GEGL buffers before and after + * these steps. + */ + + /* Ground level of the current segment, indexed by x-coordinate in the ROI- + * virtual coordinate system. Only valid inside the range + * `[segment.x[0], segment.x[1]]`. + */ + gfloat *ground; + /* Water level of the current segment, indexed by x-coordinate in the ROI- + * virtual coordinate system. Initially only valid inside the range + * `[segment.x[0], segment.x[1]]`, but may be written-to outside this range + * during horizontal propagation, if the dirty ranges are extended past the + * bounds of the segment. + */ + gfloat *water; + /* Water level of the source segment, indexed by x-coordinate in the ROI- + * virtual coordinate system. Only valid inside the range + * `[segment.x[0], segment.x[1]]`. + */ + gfloat *source_water; + + /* A common buffer for the water level of the current- and source-segments. + * `water` and `source_water` are pointers into this buffer. This buffer is + * used as an optimization, in order to read the water level of both segments + * from the output GEGL buffer in a single call, and is otherwise not used + * directly (`water` and `source_water` are used to access the water level + * instead.) + */ + gfloat *water_buffer; +}; + + +static void gimp_operation_flood_prepare (GeglOperation *operation); +static GeglRectangle gimp_operation_flood_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi); +static GeglRectangle gimp_operation_flood_get_cached_region (GeglOperation *self, + const GeglRectangle *roi); + +static void gimp_operation_flood_process_push (GQueue *queue, + gboolean transpose, + gint y, + gint source_y_delta, + gint x0, + gint x1); +static void gimp_operation_flood_process_seed (GQueue *queue, + const GeglRectangle *roi); +static void gimp_operation_flood_process_transform_rect (const GimpOperationFloodContext *ctx, + GeglRectangle *dest, + const GeglRectangle *src); +static void gimp_operation_flood_process_fetch (GimpOperationFloodContext *ctx); +static gint gimp_operation_flood_process_propagate_vertical (GimpOperationFloodContext *ctx, + GimpOperationFloodDirtyRange *dirty_ranges); +static void gimp_operation_flood_process_propagate_horizontal (GimpOperationFloodContext *ctx, + gint dir, + GimpOperationFloodDirtyRange *dirty_ranges, + gint range_count); +static gint gimp_operation_flood_process_coalesce (const GimpOperationFloodContext *ctx, + GimpOperationFloodDirtyRange *dirty_ranges, + gint range_count, + gint gap); +static void gimp_operation_flood_process_commit (const GimpOperationFloodContext *ctx, + const GimpOperationFloodDirtyRange *dirty_ranges, + gint range_count); +static void gimp_operation_flood_process_distribute (const GimpOperationFloodContext *ctx, + GQueue *queue, + const GimpOperationFloodDirtyRange *dirty_ranges, + gint range_count); +static gboolean gimp_operation_flood_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationFlood, gimp_operation_flood, + GEGL_TYPE_OPERATION_FILTER) + +#define parent_class gimp_operation_flood_parent_class + + +/* GEGL graph for the test case. */ +static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>" +"<gegl>" +"<node operation='gimp:flood'> </node>" +"<node operation='gegl:load'>" +" <params>" +" <param name='path'>flood-input.png</param>" +" </params>" +"</node>" +"</gegl>"; + + +static void +gimp_operation_flood_class_init (GimpOperationFloodClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass); + + /* The input and output buffers must be different, since we generally need to + * be able to access the input-image values after having written to the + * output buffer. + */ + operation_class->want_in_place = FALSE; + /* We don't want `GeglOperationFilter` to split the image across multiple + * threads, since this operation depends on, and affects, the image as a + * whole. + */ + operation_class->threaded = FALSE; + /* Note that both of these options are the default; we set them here for + * explicitness. + */ + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:flood", + "categories", "gimp", + "description", "GIMP Flood operation", + "reference", "https://wiki.gimp.org/wiki/Algorithms:Flood", + "reference-image", "flood-output.png", + "reference-composition", reference_xml, + NULL); + + operation_class->prepare = gimp_operation_flood_prepare; + operation_class->get_required_for_output = gimp_operation_flood_get_required_for_output; + operation_class->get_cached_region = gimp_operation_flood_get_cached_region; + + filter_class->process = gimp_operation_flood_process; +} + +static void +gimp_operation_flood_init (GimpOperationFlood *self) +{ +} + +static void +gimp_operation_flood_prepare (GeglOperation *operation) +{ + const Babl *space = gegl_operation_get_source_space (operation, "input"); + gegl_operation_set_format (operation, "input", babl_format_with_space ("Y float", space)); + gegl_operation_set_format (operation, "output", babl_format_with_space ("Y float", space)); +} + +static GeglRectangle +gimp_operation_flood_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi) +{ + return *gegl_operation_source_get_bounding_box (self, "input"); +} + +static GeglRectangle +gimp_operation_flood_get_cached_region (GeglOperation *self, + const GeglRectangle *roi) +{ + return *gegl_operation_source_get_bounding_box (self, "input"); +} + + +/* Pushes a single segment into the queue. */ +static void +gimp_operation_flood_process_push (GQueue *queue, + gboolean transpose, + gint y, + gint source_y_delta, + gint x0, + gint x1) +{ + GimpOperationFloodSegment *segment; + + segment = g_slice_new (GimpOperationFloodSegment); + + segment->transpose = transpose; + segment->y = y; + segment->source_y_delta = source_y_delta; + segment->x[0] = x0; + segment->x[1] = x1; + + g_queue_push_tail (queue, segment); +} + +/* Pushes the seed segments into the queue. Recall that the seed segments are + * indicated by having their `source_y_delta` field equal 0. + * + * `roi` is given in the image-physical coordinate system. + */ +static void +gimp_operation_flood_process_seed (GQueue *queue, + const GeglRectangle *roi) +{ + if (roi->width == 0 || roi->height == 0) + return; + + /* Top edge. */ + gimp_operation_flood_process_push (queue, + /* transpose = */ FALSE, + /* y = */ 0, + /* source_y_delta = */ 0, + /* x0 = */ 0, + /* x1 = */ roi->width - 1); + + if (roi->height == 1) + return; + + /* Bottom edge. */ + gimp_operation_flood_process_push (queue, + /* transpose = */ FALSE, + /* y = */ roi->height - 1, + /* source_y_delta = */ 0, + /* x0 = */ 0, + /* x1 = */ roi->width - 1); + + if (roi->height == 2) + return; + + /* Left edge. */ + gimp_operation_flood_process_push (queue, + /* transpose = */ TRUE, + /* y = */ 0, + /* source_y_delta = */ 0, + /* x0 = */ 1, + /* x1 = */ roi->height - 2); + + if (roi->width == 1) + return; + + /* Right edge. */ + gimp_operation_flood_process_push (queue, + /* transpose = */ TRUE, + /* y = */ roi->width - 1, + /* source_y_delta = */ 0, + /* x0 = */ 1, + /* x1 = */ roi->height - 2); +} + +/* Transforms a `GeglRectangle` between the image-physical and image-virtual + * coordinate systems, in either direction, based on the attributes of the + * current segment (namely, its `transpose` flag.) + * + * Takes the input rectangle through `src`, and stores the result in `dest`. + * Both parameters may refer to the same object. + */ +static void +gimp_operation_flood_process_transform_rect (const GimpOperationFloodContext *ctx, + GeglRectangle *dest, + const GeglRectangle *src) +{ + if (! ctx->segment.transpose) + *dest = *src; + else + { + gint temp; + + temp = src->x; + dest->x = src->y; + dest->y = temp; + + temp = src->width; + dest->width = src->height; + dest->height = temp; + } +} + +/* Reads the ground- and water-level for the current- and source-segments from + * the GEGL buffers into the corresponding arrays. Sets up the `water` and + * `source_water` pointers of `ctx` to point to the right location in + * `water_buffer`. + */ +static void +gimp_operation_flood_process_fetch (GimpOperationFloodContext *ctx) +{ + /* Image-virtual and image-physical rectangles, respectively. */ + GeglRectangle iv_rect, ip_rect; + + /* Set the horizontal extent of the rectangle to span the entire segment. */ + iv_rect.x = ctx->roi.x + ctx->segment.x[0]; + iv_rect.width = ctx->segment.x[1] - ctx->segment.x[0] + 1; + + /* For reading the water level, we treat ordinary (non-seed) and seed + * segments differently. + */ + if (ctx->segment.source_y_delta != 0) + { + /* Ordinary segment. */ + + /* We set the vertical extent of the rectangle to span both the current- + * and the source-segments, and set the `water` and `source_water` + * pointers to point to two consecutive rows of the `water_buffer` array + * (the y-coordinate of the rectangle, and which row is above which, + * depends on whether the source segment is above, or below, the current + * one.) + */ + if (ctx->segment.source_y_delta < 0) + { + iv_rect.y = ctx->roi.y + ctx->segment.y - 1; + ctx->water = ctx->water_buffer + ctx->roi.width; + ctx->source_water = ctx->water_buffer; + } + else + { + iv_rect.y = ctx->roi.y + ctx->segment.y; + ctx->water = ctx->water_buffer; + ctx->source_water = ctx->water_buffer + ctx->roi.width; + } + iv_rect.height = 2; + + /* Transform `iv_rect` to the image-physical coordinate system, and store + * the result in `ip_rect`. + */ + gimp_operation_flood_process_transform_rect (ctx, &ip_rect, &iv_rect); + + /* Read the water level from the output GEGL buffer into `water_buffer`. + * + * Notice the stride: If the current segment is horizontal, then we're + * reading a pair of rows directly into the correct locations inside + * `water_buffer` (i.e., `water` and `source_water`). On the other hand, + * if the current segment is vertical, then we're reading a pair of + * *columns*; we set the stride to 2-pixels so that the current- and + * source-water levels are interleaved in `water_buffer`, and reorder + * them below. + */ + gegl_buffer_get (ctx->output, &ip_rect, 1.0, ctx->output_format, + ctx->water_buffer + ctx->segment.x[0], + sizeof (gfloat) * + (ctx->segment.transpose ? 2 : ctx->roi.width), + GEGL_ABYSS_NONE); + + /* As mentioned above, if the current segment is vertical, then the + * water levels of the current- and source-segments are interleaved in + * `water_buffer`. We deinterleave the water levels into `water` and + * `source_water`, using the yet-to-be-written-to `ground` array as a + * temporary buffer, as necessary. + */ + if (ctx->segment.transpose) + { + const gfloat *src; + gfloat *dest1, *dest2, *temp; + gint size, temp_size; + gint i; + + src = ctx->water_buffer + ctx->segment.x[0]; + + dest1 = ctx->water_buffer + ctx->segment.x[0]; + dest2 = ctx->water_buffer + ctx->roi.width + ctx->segment.x[0]; + temp = ctx->ground; + + size = ctx->segment.x[1] - ctx->segment.x[0] + 1; + temp_size = MAX (0, 2 * size - ctx->roi.width); + + for (i = 0; i < temp_size; i++) + { + dest1[i] = src[2 * i]; + temp[i] = src[2 * i + 1]; + } + for (; i < size; i++) + { + dest1[i] = src[2 * i]; + dest2[i] = src[2 * i + 1]; + } + + memcpy (dest2, temp, sizeof (gfloat) * temp_size); + } + } + else + { + /* Seed segment. */ + + gint x; + + /* Set the `water` and `source_water` pointers to point to consecutive + * rows of the `water_buffer` array. + */ + ctx->water = ctx->water_buffer; + ctx->source_water = ctx->water_buffer + ctx->roi.width; + + /* Set the vertical extent of the rectangle to span a the current + * segment's row. + */ + iv_rect.y = ctx->roi.y + ctx->segment.y; + iv_rect.height = 1; + + /* Transform `iv_rect` to the image-physical coordinate system, and store + * the result in `ip_rect`. + */ + gimp_operation_flood_process_transform_rect (ctx, &ip_rect, &iv_rect); + + /* Read the water level of the current segment from the output GEGL + * buffer into `water`. + */ + gegl_buffer_get (ctx->output, &ip_rect, 1.0, ctx->output_format, + ctx->water + ctx->segment.x[0], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + + /* Initialize `source_water` to 0, as this is a seed segment. */ + for (x = ctx->segment.x[0]; x <= ctx->segment.x[1]; x++) + ctx->source_water[x] = 0.0; + } + + /* Set the vertical extent of the rectangle to span a the current segment's + * row. + */ + iv_rect.y = ctx->roi.y + ctx->segment.y; + iv_rect.height = 1; + + /* Transform `iv_rect` to the image-physical coordinate system, and store the + * result in `ip_rect`. + */ + gimp_operation_flood_process_transform_rect (ctx, &ip_rect, &iv_rect); + + /* Read the ground level of the current segment from the input GEGL buffer + * into `ground`. + */ + gegl_buffer_get (ctx->input, &ip_rect, 1.0, ctx->input_format, + ctx->ground + ctx->segment.x[0], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); +} + +/* Performs the vertical propagation step of the algorithm. Writes the dirty + * ranges to the `dirty_ranges` parameter, and returns the number of dirty + * ranges as the function's result. + */ +static gint +gimp_operation_flood_process_propagate_vertical (GimpOperationFloodContext *ctx, + GimpOperationFloodDirtyRange *dirty_ranges) +{ + GimpOperationFloodDirtyRange *range = dirty_ranges; + gint x; + + for (x = ctx->segment.x[0]; x <= ctx->segment.x[1]; x++) + { + /* Scan the segment until we find a pixel whose water level needs to be + * updated. + */ + if (ctx->source_water[x] < ctx->water[x] && + ctx->ground[x] < ctx->water[x]) + { + /* Compute and update the water level. */ + gfloat level = MAX (ctx->source_water[x], ctx->ground[x]); + + ctx->water[x] = level; + + /* Start a new dirty range at the current pixel. */ + range->x[0] = x; + range->modified = FALSE; + + for (x++; x <= ctx->segment.x[1]; x++) + { + /* Keep scanning the segment while the water level of consecutive + * pixels needs to be updated. + */ + if (ctx->source_water[x] < ctx->water[x] && + ctx->ground[x] < ctx->water[x]) + { + /* Compute and update the water level. */ + gfloat other_level = MAX (ctx->source_water[x], + ctx->ground[x]); + + ctx->water[x] = other_level; + + /* If the water level of the current pixel, `other_level`, + * equals the water level of the current dirty range, + * `level`, we keep scanning, making the current pixel part + * of the current range. On the other hand, if the current + * pixel's water level is different than the that of the + * current range, we finalize the range, and start a new one + * at the current pixel. + */ + if (other_level != level) + { + range->x[1] = x - 1; + range++; + + range->x[0] = x; + range->modified = FALSE; + level = other_level; + } + } + else + break; + } + + /* Finalize the current dirty range. */ + range->x[1] = x - 1; + range++; + + /* Make sure we don't over-increment `x` on the continuation of the + * loop. + */ + if (x > ctx->segment.x[1]) + break; + } + } + + /* Return the number of dirty ranges. */ + return range - dirty_ranges; +} + +/* Performs a single pass of the horizontal propagation step of the algorithm. + * `dir` controls the direction of the pass: either +1 for a left-to-right + * pass, or -1 for a right-to-left pass. The dirty ranges are passed through + * the `dirty_ranges` array (and their number in `range_count`), and are + * modified in-place. + */ +static void +gimp_operation_flood_process_propagate_horizontal (GimpOperationFloodContext *ctx, + gint dir, + GimpOperationFloodDirtyRange *dirty_ranges, + gint range_count) +{ + /* The index of the terminal (i.e., "`dir`-most") component of the `x[]` + * array of `GimpOperationFloodSegment` and `GimpOperationFloodDirtyRange`, + * based on the scan direction. Equals 1 (i.e., the right component) when + * `dir` is +1 (i.e., left-to-right), and equals 0 (i.e., the left component) + * when `dir` is -1 (i.e., right-to-left). + */ + gint x_component; + /* One-past the final x-coordinate of the ROI, in the ROI-virtual coordinate + * system, based on the scan direction. That is, the x-coordinate of the + * pixel to the right of the rightmost pixel, for a left-to-right scan, and + * of the pixel to the left of the leftmost pixel, for a right-to-left scan. + */ + gint roi_lim; + /* One-past the final x-coordinate of the segment, in the ROI-virtual + * coordinate system, based on the scan direction, in a similar fashion to + * `roi_lim`. + */ + gint segment_lim; + /* The indices of the first, and one-past-the-last dirty ranges, based on the + * direction of the scan. Recall that when scanning right-to-left, we + * iterate over the ranges in reverse. + */ + gint first_range, last_range; + /* Index of the current dirty range. */ + gint range_index; + /* Image-virtual and image-physical rectangles, respectively. */ + GeglRectangle iv_rect, ip_rect; + + /* Initialize the above variables based on the scan direction. */ + if (dir > 0) + { + /* Left-to-right. */ + x_component = 1; + roi_lim = ctx->roi.width; + first_range = 0; + last_range = range_count; + } + else + { + /* Right-to-left. */ + x_component = 0; + roi_lim = -1; + first_range = range_count - 1; + last_range = -1; + } + segment_lim = ctx->segment.x[x_component] + dir; + + /* We loop over the dirty ranges, in the direction of the scan. For each + * range, we iterate over the pixels, in the scan direction, starting at the + * outer edge of the range, and update the water level, considering only the + * water level of the previous and current pixels, until we arrive at a pixel + * whose water level remains the same, at which point we move to the next + * range, as described in the algorithm overview. + */ + for (range_index = first_range; + range_index != last_range; + range_index += dir) + { + /* Current dirty range. */ + GimpOperationFloodDirtyRange *range; + /* Current pixel, in the ROI-virtual coordinate system. */ + gint x; + /* We use `level` to compute the water level of the current pixel. At + * the beginning of each iteration, it holds the water level of the + * previous pixel. + */ + gfloat level; + /* The `inside` flag indicates whether `x` is inside the current segment. + * Recall that we may iterate past the bounds of the current segment, in + * which case we need to read the ground- and water-levels from the GEGL + * buffers directly, instead of the corresponding arrays. + */ + gboolean inside; + /* Loop limit. */ + gint lim; + + range = &dirty_ranges[range_index]; + /* Last x-coordinate of the range, in the direction of the scan. */ + x = range->x[x_component]; + /* We start iterating on the pixel after `x`; initialize `level` to the + * water level of the previous pixel. + */ + level = ctx->water[x]; + /* The ranges produced by the vertical propagation step are all within + * the bounds of the segment; the horizontal propagation step may only + * extend them in the direction of the scan. Therefore, on both passes + * of the horizontal propagation step, the last pixel of each range, in + * the direction of the scan, is initially inside the segment. + */ + inside = TRUE; + /* If this isn't the last range, break the loop at the beginning of the + * next range. Otherwise, break the loop at the edge of the ROI. + */ + if (range_index + dir != last_range) + lim = (range + dir)->x[1 - x_component]; + else + lim = roi_lim; + + /* Loop over the pixels between the edge of the current range, and the + * beginning of the next range (or the edge of the ROI). + */ + for (x += dir; x != lim; x += dir) + { + gfloat ground_level, water_level; + + /* Recall that `segment_lim` is one-past the last pixel of the + * segment. If we hit it, we've gone outside the segment bounds. + */ + if (x == segment_lim) + { + inside = FALSE; + /* Initialize the rectangle to sample pixels directly from the + * GEGL buffers. + */ + iv_rect.y = ctx->roi.y + ctx->segment.y; + iv_rect.width = 1; + iv_rect.height = 1; + } + + /* If we're inside the segment, read the ground- and water-levels + * from the corresponding arrays; otherwise, read them from the GEGL + * buffers directly. Note that, on each pass, we may only write to + * pixels outside the segment *in direction of the scan* (in which + * case, the new values are written to the `water` array, but not + * directly to the output GEGL buffer), hence, when reading from the + * GEGL buffers, there's no danger of reading stale values, that were + * changed on the previous pass. + */ + if (inside) + { + ground_level = ctx->ground[x]; + water_level = ctx->water[x]; + } + else + { + iv_rect.x = ctx->roi.x + x; + + /* Transform `iv_rect` to the image-physical coordinate system, + * and store the result in `ip_rect`. + */ + gimp_operation_flood_process_transform_rect (ctx, + &ip_rect, &iv_rect); + + /* Read the current pixel's ground level. */ + gegl_buffer_get (ctx->input, &ip_rect, 1.0, ctx->input_format, + &ground_level, + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + /* Read the current pixel's water level. */ + gegl_buffer_get (ctx->output, &ip_rect, 1.0, ctx->output_format, + &water_level, + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + } + + /* The new water level is the maximum of the current ground level, + * and the minimum of the current and previous water levels. Recall + * that `level` holds the previous water level, and that the current + * water level is never less than the ground level. + */ + if (level < ground_level) + level = ground_level; + if (level < water_level) + { + /* The water level changed. Update the current pixel, and set + * the `modified` flag of the current range, since it will be + * extended to include the current pixel. + */ + ctx->water[x] = level; + range->modified = TRUE; + } + else + /* The water level stayed the same. Break the loop. */ + break; + } + + /* Extend the current dirty range to include the last modified pixel, if + * any. + */ + range->x[x_component] = x - dir; + + /* If we stopped the loop before hitting the edge of the next range, or + * if we're at the last range, continue to the next range (or quit). + */ + if (x != lim || range_index + dir == last_range) + continue; + + /* If we hit the edge of the next range, we keep propagating the changes + * *inside* the next range, until we hit its other edge, or until the + * water level stays the same. + */ + range += dir; + lim = range->x[x_component] + dir; + + for (; x != lim; x += dir) + { + /* Note that we're necessarily inside the segment right now, since + * the only range that could have been extended past the edge of the + * segment by the previous pass, is the first range of the current + * pass, while the range we're currently inside is at least the + * second. + */ + if (level < ctx->ground[x]) + level = ctx->ground[x]; + if (level < ctx->water[x]) + { + ctx->water[x] = level; + /* Set the `modified` flag of the range, since the water level of + * its existing pixels changed. + */ + range->modified = TRUE; + } + else + break; + } + } +} + +/* Coalesces consecutive dirty ranges that are separated by a gap less-than or + * equal-to `max_gap`, in-place, and returns the new number of ranges. + */ +static gint +gimp_operation_flood_process_coalesce (const GimpOperationFloodContext *ctx, + GimpOperationFloodDirtyRange *dirty_ranges, + gint range_count, + gint max_gap) +{ + /* First and last ranges to coalesce, respectively. */ + const GimpOperationFloodDirtyRange *first_range, *last_range; + /* Destination range. */ + GimpOperationFloodDirtyRange *range = dirty_ranges; + + for (first_range = dirty_ranges; + first_range != dirty_ranges + range_count; + first_range++) + { + /* The `modified` flag of the coalesced range -- the logical-OR of the + * `modified` flags of the individual ranges. + */ + gboolean modified = first_range->modified; + + /* Find all consecutive ranges with a small-enough gap. */ + for (last_range = first_range; + last_range + 1 != dirty_ranges + range_count; + last_range++) + { + if ((last_range + 1)->x[0] - last_range->x[1] > max_gap) + break; + + modified |= (last_range + 1)->modified; + } + + /* Write the coalesced range, or copy the current range, to the + * destination range. + */ + if (first_range != last_range || first_range != range) + { + range->x[0] = first_range->x[0]; + range->x[1] = last_range->x[1]; + range->modified = modified; + } + + first_range = last_range; + range++; + } + + /* Return the new range count. */ + return range - dirty_ranges; +} + +/* Writes the updated water level of the dirty ranges back to the output GEGL + * buffer. + */ +static void +gimp_operation_flood_process_commit (const GimpOperationFloodContext *ctx, + const GimpOperationFloodDirtyRange *dirty_ranges, + gint range_count) +{ + const GimpOperationFloodDirtyRange *range; + /* Image-virtual and image-physical rectangles, respectively. */ + GeglRectangle iv_rect, ip_rect; + + /* Set the vertical extent of the rectangle to span a the current segment's + * row. + */ + iv_rect.y = ctx->roi.y + ctx->segment.y; + iv_rect.height = 1; + + for (range = dirty_ranges; range != dirty_ranges + range_count; range++) + { + /* Set the horizontal extent of the rectangle to span the dirty range. */ + iv_rect.x = ctx->roi.x + range->x[0]; + iv_rect.width = range->x[1] - range->x[0] + 1; + + /* Transform `iv_rect` to the image-physical coordinate system, and store + * the result in `ip_rect`. + */ + gimp_operation_flood_process_transform_rect (ctx, &ip_rect, &iv_rect); + + /* Write the updated water level to the output GEGL buffer. */ + gegl_buffer_set (ctx->output, &ip_rect, 0, ctx->output_format, + ctx->water + range->x[0], + GEGL_AUTO_ROWSTRIDE); + } +} + +/* Pushes the new segments, corresponding to the dirty ranges of the current + * segment, into the queue. + */ +static void +gimp_operation_flood_process_distribute (const GimpOperationFloodContext *ctx, + GQueue *queue, + const GimpOperationFloodDirtyRange *dirty_ranges, + gint range_count) +{ + const GimpOperationFloodDirtyRange *range; + static const gint y_deltas[] = {-1, +1}; + gint i; + + /* For each neighboring row... */ + for (i = 0; i < G_N_ELEMENTS (y_deltas); i++) + { + /* The difference between the negihboring row's y-coordinate and the + * current row's y-corindate, in the ROI-virtual coordinate system. + */ + gint y_delta = y_deltas[i]; + /* The negihboring row's y-coordinate in the ROI-virtual coordinate + * system. + */ + gint y = ctx->segment.y + y_delta; + + /* If the neighboring row is outside the ROI, skip it. */ + if (y < 0 || y >= ctx->roi.height) + continue; + + /* For each dirty range... */ + for (range = dirty_ranges; range != dirty_ranges + range_count; range++) + { + /* If the range was modified during horizontal propagation, or if the + * neighboring row is not the source segment's row... (note that the + * latter is always true for seed segments.) + */ + if (range->modified || y_delta != ctx->segment.source_y_delta) + { + /* Push a new segment into the queue, spanning the same pixels as + * the dirty range on the neighboring row, using the current row + * as its source segment. + */ + gimp_operation_flood_process_push (queue, + ctx->segment.transpose, + y, + -y_delta, + range->x[0], + range->x[1]); + } + } + } +} + +/* Main algorithm. */ +static gboolean +gimp_operation_flood_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level) +{ + const Babl *input_format = gegl_operation_get_format (operation, "input"); + const Babl *output_format = gegl_operation_get_format (operation, "output"); + GeglColor *color; + gint max_size; + GimpOperationFloodContext ctx; + GimpOperationFloodDirtyRange *dirty_ranges; + GQueue *queue; + + /* Make sure the input- and output-buffers are different. */ + g_return_val_if_fail (input != output, FALSE); + + /* Make sure the ROI is small enough for the `GimpOperationFloodSegment::y` + * field. + */ + g_return_val_if_fail (roi->width <= GIMP_MAX_IMAGE_SIZE && + roi->height <= GIMP_MAX_IMAGE_SIZE, FALSE); + + ctx.input = input; + ctx.input_format = input_format; + ctx.output = output; + ctx.output_format = output_format; + + /* All buffers need to have enough capacity to process a full row, or a full + * column, since, when processing vertical segments, we treat the image as + * transposed. + */ + max_size = MAX (roi->width, roi->height); + ctx.ground = g_new (gfloat, max_size); + /* The `water_buffer` array needs to be able to hold two rows (or columns). */ + ctx.water_buffer = g_new (gfloat, 2 * max_size); + dirty_ranges = g_new (GimpOperationFloodDirtyRange, max_size); + + /* Initialize the water level to 1 everywhere. */ + color = gegl_color_new ("#fff"); + gegl_buffer_set_color (output, roi, color); + g_object_unref (color); + + /* Create the queue and push the seed segments. */ + queue = g_queue_new (); + gimp_operation_flood_process_seed (queue, roi); + + /* While there are segments to process in the queue... */ + while (! g_queue_is_empty (queue)) + { + GimpOperationFloodSegment *segment; + gint range_count; + + /* Pop a segment off the top of the queue, copy it to `ctx.segment`, and + * free its memory. + */ + segment = (GimpOperationFloodSegment *) g_queue_pop_head (queue); + ctx.segment = *segment; + g_slice_free (GimpOperationFloodSegment, segment); + + /* Transform the ROI from the image-physical coordinate system to the + * image-virtual coordinate system, and store the result in `ctx.roi`. + */ + gimp_operation_flood_process_transform_rect (&ctx, &ctx.roi, roi); + + /* Read the ground- and water-levels of the current- and source-segments + * from the corresponding GEGL buffers to the corresponding arrays. + */ + gimp_operation_flood_process_fetch (&ctx); + + /* Perform the vertical propagation step. */ + range_count = gimp_operation_flood_process_propagate_vertical (&ctx, + dirty_ranges); + /* If no dirty ranges were produced during vertical propagation, then the + * water level of the current segment didn't change, and we can short- + * circuit early. + */ + if (range_count == 0) + continue; + + /* Perform both passes of the horizontal propagation step. */ + gimp_operation_flood_process_propagate_horizontal (&ctx, + /* Left-to-right */ +1, + dirty_ranges, + range_count); + gimp_operation_flood_process_propagate_horizontal (&ctx, + /* Right-to-left */ -1, + dirty_ranges, + range_count); + + /* Coalesce consecutive dirty ranges separated by a gap less-than or + * equal-to `GIMP_OPERATION_FLOOD_COALESCE_MAX_GAP`. + */ + range_count = gimp_operation_flood_process_coalesce (&ctx, + dirty_ranges, + range_count, + GIMP_OPERATION_FLOOD_COALESCE_MAX_GAP); + + /* Write the updated water level back to the output GEGL buffer. */ + gimp_operation_flood_process_commit (&ctx, dirty_ranges, range_count); + + /* Push the new segments into the queue. */ + gimp_operation_flood_process_distribute (&ctx, queue, + dirty_ranges, range_count); + } + + g_queue_free (queue); + + g_free (dirty_ranges); + g_free (ctx.water_buffer); + g_free (ctx.ground); + + return TRUE; +} diff --git a/app/operations/gimpoperationflood.h b/app/operations/gimpoperationflood.h new file mode 100644 index 0000000..ed2c1c6 --- /dev/null +++ b/app/operations/gimpoperationflood.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationflood.h + * Copyright (C) 2016 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_FLOOD_H__ +#define __GIMP_OPERATION_FLOOD_H__ + + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_FLOOD (gimp_operation_flood_get_type ()) +#define GIMP_OPERATION_FLOOD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_FLOOD, GimpOperationFlood)) +#define GIMP_OPERATION_FLOOD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_FLOOD, GimpOperationFloodClass)) +#define GIMP_IS_OPERATION_FLOOD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_FLOOD)) +#define GIMP_IS_OPERATION_FLOOD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_FLOOD)) +#define GIMP_OPERATION_FLOOD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_FLOOD, GimpOperationFloodClass)) + + +typedef struct _GimpOperationFlood GimpOperationFlood; +typedef struct _GimpOperationFloodClass GimpOperationFloodClass; + +struct _GimpOperationFlood +{ + GeglOperationFilter parent_instance; +}; + +struct _GimpOperationFloodClass +{ + GeglOperationFilterClass parent_class; +}; + + +GType gimp_operation_flood_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_FLOOD_H__ */ diff --git a/app/operations/gimpoperationgradient.c b/app/operations/gimpoperationgradient.c new file mode 100644 index 0000000..2dbb746 --- /dev/null +++ b/app/operations/gimpoperationgradient.c @@ -0,0 +1,1283 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * Largely based on gimpdrawable-gradient.c + * + * gimpoperationgradient.c + * Copyright (C) 2014 Michael Henning <drawoc@darkrefraction.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "core/gimpgradient.h" + +#include "gimpoperationgradient.h" + + +#define GRADIENT_CACHE_N_SUPERSAMPLES 4 +#define GRADIENT_CACHE_MAX_SIZE ((1 << 20) / sizeof (GimpRGB)) + + +enum +{ + PROP_0, + PROP_CONTEXT, + PROP_GRADIENT, + PROP_START_X, + PROP_START_Y, + PROP_END_X, + PROP_END_Y, + PROP_GRADIENT_TYPE, + PROP_GRADIENT_REPEAT, + PROP_OFFSET, + PROP_GRADIENT_REVERSE, + PROP_GRADIENT_BLEND_COLOR_SPACE, + PROP_SUPERSAMPLE, + PROP_SUPERSAMPLE_DEPTH, + PROP_SUPERSAMPLE_THRESHOLD, + PROP_DITHER +}; + +typedef struct +{ + GimpGradient *gradient; + gboolean reverse; + GimpGradientBlendColorSpace blend_color_space; + GimpRGB *gradient_cache; + gint gradient_cache_size; + GimpGradientSegment *last_seg; + gdouble offset; + gdouble sx, sy; + GimpGradientType gradient_type; + gdouble dist; + gdouble vec[2]; + GimpRepeatMode repeat; + GeglSampler *dist_sampler; +} RenderBlendData; + + +typedef struct +{ + gfloat *data; + GeglRectangle roi; + GRand *dither_rand; +} PutPixelData; + + +/* local function prototypes */ + +static void gimp_operation_gradient_dispose (GObject *gobject); +static void gimp_operation_gradient_finalize (GObject *gobject); +static void gimp_operation_gradient_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_gradient_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_gradient_prepare (GeglOperation *operation); + +static GeglRectangle gimp_operation_gradient_get_bounding_box (GeglOperation *operation); + +static gdouble gradient_calc_conical_sym_factor (gdouble dist, + gdouble *axis, + gdouble offset, + gdouble x, + gdouble y); +static gdouble gradient_calc_conical_asym_factor (gdouble dist, + gdouble *axis, + gdouble offset, + gdouble x, + gdouble y); +static gdouble gradient_calc_square_factor (gdouble dist, + gdouble offset, + gdouble x, + gdouble y); +static gdouble gradient_calc_radial_factor (gdouble dist, + gdouble offset, + gdouble x, + gdouble y); +static gdouble gradient_calc_linear_factor (gdouble dist, + gdouble *vec, + gdouble offset, + gdouble x, + gdouble y); +static gdouble gradient_calc_bilinear_factor (gdouble dist, + gdouble *vec, + gdouble offset, + gdouble x, + gdouble y); +static gdouble gradient_calc_spiral_factor (gdouble dist, + gdouble *axis, + gdouble offset, + gdouble x, + gdouble y, + gboolean clockwise); + +static gdouble gradient_calc_shapeburst_angular_factor (GeglSampler *dist_sampler, + gdouble offset, + gdouble x, + gdouble y); +static gdouble gradient_calc_shapeburst_spherical_factor (GeglSampler *dist_sampler, + gdouble offset, + gdouble x, + gdouble y); +static gdouble gradient_calc_shapeburst_dimpled_factor (GeglSampler *dist_sampler, + gdouble offset, + gdouble x, + gdouble y); + +static void gradient_render_pixel (gdouble x, + gdouble y, + GimpRGB *color, + gpointer render_data); + +static void gradient_put_pixel (gint x, + gint y, + GimpRGB *color, + gpointer put_pixel_data); + +static void gradient_dither_pixel (GimpRGB *color, + GRand *dither_rand, + gfloat *dest); + +static gboolean gimp_operation_gradient_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *result, + gint level); + +static void gimp_operation_gradient_invalidate_cache (GimpOperationGradient *self); +static void gimp_operation_gradient_validate_cache (GimpOperationGradient *self); + + +G_DEFINE_TYPE (GimpOperationGradient, gimp_operation_gradient, + GEGL_TYPE_OPERATION_FILTER) + +#define parent_class gimp_operation_gradient_parent_class + + +static void +gimp_operation_gradient_class_init (GimpOperationGradientClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass); + + object_class->dispose = gimp_operation_gradient_dispose; + object_class->finalize = gimp_operation_gradient_finalize; + object_class->set_property = gimp_operation_gradient_set_property; + object_class->get_property = gimp_operation_gradient_get_property; + + operation_class->prepare = gimp_operation_gradient_prepare; + operation_class->get_bounding_box = gimp_operation_gradient_get_bounding_box; + + filter_class->process = gimp_operation_gradient_process; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:gradient", + "categories", "gimp", + "description", "GIMP Gradient operation", + NULL); + + g_object_class_install_property (object_class, PROP_CONTEXT, + g_param_spec_object ("context", + "Context", + "A GimpContext", + GIMP_TYPE_OBJECT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_GRADIENT, + g_param_spec_object ("gradient", + "Gradient", + "A GimpGradient to render", + GIMP_TYPE_OBJECT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_START_X, + g_param_spec_double ("start-x", + "Start X", + "X coordinate of the first point", + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_START_Y, + g_param_spec_double ("start-y", + "Start Y", + "Y coordinate of the first point", + -G_MAXDOUBLE, G_MAXDOUBLE, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_END_X, + g_param_spec_double ("end-x", + "End X", + "X coordinate of the second point", + -G_MAXDOUBLE, G_MAXDOUBLE, 200, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_END_Y, + g_param_spec_double ("end-y", + "End Y", + "Y coordinate of the second point", + -G_MAXDOUBLE, G_MAXDOUBLE, 200, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_GRADIENT_TYPE, + g_param_spec_enum ("gradient-type", + "Gradient Type", + "The type of gradient to render", + GIMP_TYPE_GRADIENT_TYPE, + GIMP_GRADIENT_LINEAR, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_GRADIENT_REPEAT, + g_param_spec_enum ("gradient-repeat", + "Repeat mode", + "Repeat mode", + GIMP_TYPE_REPEAT_MODE, + GIMP_REPEAT_NONE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_OFFSET, + g_param_spec_double ("offset", + "Offset", + "Offset relates to the starting and ending coordinates " + "specified for the blend. This parameter is mode dependent.", + 0, G_MAXDOUBLE, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_GRADIENT_REVERSE, + g_param_spec_boolean ("gradient-reverse", + "Reverse", + "Reverse the gradient", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_GRADIENT_BLEND_COLOR_SPACE, + g_param_spec_enum ("gradient-blend-color-space", + "Blend Color Space", + "Which color space to use when blending RGB gradient segments", + GIMP_TYPE_GRADIENT_BLEND_COLOR_SPACE, + GIMP_GRADIENT_BLEND_RGB_PERCEPTUAL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_SUPERSAMPLE, + g_param_spec_boolean ("supersample", + "Supersample", + "Do adaptive supersampling", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_SUPERSAMPLE_DEPTH, + g_param_spec_int ("supersample-depth", + "Max depth", + "Maximum recursion levels for supersampling", + 1, 9, 3, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_SUPERSAMPLE_THRESHOLD, + g_param_spec_double ("supersample-threshold", + "Threshold", + "Supersampling threshold", + 0, 4, 0.20, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_DITHER, + g_param_spec_boolean ("dither", + "Dither", + "Use dithering to reduce banding", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_gradient_init (GimpOperationGradient *self) +{ + g_mutex_init (&self->gradient_cache_mutex); +} + +static void +gimp_operation_gradient_dispose (GObject *object) +{ + GimpOperationGradient *self = GIMP_OPERATION_GRADIENT (object); + + gimp_operation_gradient_invalidate_cache (self); + + g_clear_object (&self->gradient); + g_clear_object (&self->context); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gimp_operation_gradient_finalize (GObject *object) +{ + GimpOperationGradient *self = GIMP_OPERATION_GRADIENT (object); + + g_mutex_clear (&self->gradient_cache_mutex); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_operation_gradient_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationGradient *self = GIMP_OPERATION_GRADIENT (object); + + switch (property_id) + { + case PROP_CONTEXT: + g_value_set_object (value, self->context); + break; + + case PROP_GRADIENT: + g_value_set_object (value, self->gradient); + break; + + case PROP_START_X: + g_value_set_double (value, self->start_x); + break; + + case PROP_START_Y: + g_value_set_double (value, self->start_y); + break; + + case PROP_END_X: + g_value_set_double (value, self->end_x); + break; + + case PROP_END_Y: + g_value_set_double (value, self->end_y); + break; + + case PROP_GRADIENT_TYPE: + g_value_set_enum (value, self->gradient_type); + break; + + case PROP_GRADIENT_REPEAT: + g_value_set_enum (value, self->gradient_repeat); + break; + + case PROP_OFFSET: + g_value_set_double (value, self->offset); + break; + + case PROP_GRADIENT_REVERSE: + g_value_set_boolean (value, self->gradient_reverse); + break; + + case PROP_GRADIENT_BLEND_COLOR_SPACE: + g_value_set_enum (value, self->gradient_blend_color_space); + break; + + case PROP_SUPERSAMPLE: + g_value_set_boolean (value, self->supersample); + break; + + case PROP_SUPERSAMPLE_DEPTH: + g_value_set_int (value, self->supersample_depth); + break; + + case PROP_SUPERSAMPLE_THRESHOLD: + g_value_set_double (value, self->supersample_threshold); + break; + + case PROP_DITHER: + g_value_set_boolean (value, self->dither); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_gradient_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationGradient *self = GIMP_OPERATION_GRADIENT (object); + + switch (property_id) + { + case PROP_CONTEXT: + if (self->context) + g_object_unref (self->context); + + self->context = g_value_dup_object (value); + break; + + case PROP_GRADIENT: + { + GimpGradient *gradient = g_value_get_object (value); + + g_clear_object (&self->gradient); + + if (gradient) + { + if (gimp_gradient_has_fg_bg_segments (gradient)) + self->gradient = gimp_gradient_flatten (gradient, self->context); + else + self->gradient = g_object_ref (gradient); + } + + gimp_operation_gradient_invalidate_cache (self); + } + break; + + case PROP_START_X: + self->start_x = g_value_get_double (value); + + gimp_operation_gradient_invalidate_cache (self); + break; + + case PROP_START_Y: + self->start_y = g_value_get_double (value); + + gimp_operation_gradient_invalidate_cache (self); + break; + + case PROP_END_X: + self->end_x = g_value_get_double (value); + + gimp_operation_gradient_invalidate_cache (self); + break; + + case PROP_END_Y: + self->end_y = g_value_get_double (value); + + gimp_operation_gradient_invalidate_cache (self); + break; + + case PROP_GRADIENT_TYPE: + self->gradient_type = g_value_get_enum (value); + break; + + case PROP_GRADIENT_REPEAT: + self->gradient_repeat = g_value_get_enum (value); + break; + + case PROP_OFFSET: + self->offset = g_value_get_double (value); + break; + + case PROP_GRADIENT_REVERSE: + self->gradient_reverse = g_value_get_boolean (value); + + gimp_operation_gradient_invalidate_cache (self); + break; + + case PROP_GRADIENT_BLEND_COLOR_SPACE: + self->gradient_blend_color_space = g_value_get_enum (value); + + gimp_operation_gradient_invalidate_cache (self); + break; + + case PROP_SUPERSAMPLE: + self->supersample = g_value_get_boolean (value); + break; + + case PROP_SUPERSAMPLE_DEPTH: + self->supersample_depth = g_value_get_int (value); + break; + + case PROP_SUPERSAMPLE_THRESHOLD: + self->supersample_threshold = g_value_get_double (value); + break; + + case PROP_DITHER: + self->dither = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_gradient_prepare (GeglOperation *operation) +{ + gegl_operation_set_format (operation, "output", babl_format ("R'G'B'A float")); +} + +static GeglRectangle +gimp_operation_gradient_get_bounding_box (GeglOperation *operation) +{ + return gegl_rectangle_infinite_plane (); +} + +static gdouble +gradient_calc_conical_sym_factor (gdouble dist, + gdouble *axis, + gdouble offset, + gdouble x, + gdouble y) +{ + if (dist == 0.0) + { + return 0.0; + } + else if ((x != 0) || (y != 0)) + { + gdouble vec[2]; + gdouble r; + gdouble rat; + + /* Calculate offset from the start in pixels */ + + r = sqrt (SQR (x) + SQR (y)); + + vec[0] = x / r; + vec[1] = y / r; + + rat = axis[0] * vec[0] + axis[1] * vec[1]; /* Dot product */ + + if (rat > 1.0) + rat = 1.0; + else if (rat < -1.0) + rat = -1.0; + + /* This cool idea is courtesy Josh MacDonald, + * Ali Rahimi --- two more XCF losers. */ + + rat = acos (rat) / G_PI; + rat = pow (rat, (offset / 10.0) + 1.0); + + return CLAMP (rat, 0.0, 1.0); + } + else + { + return 0.5; + } +} + +static gdouble +gradient_calc_conical_asym_factor (gdouble dist, + gdouble *axis, + gdouble offset, + gdouble x, + gdouble y) +{ + if (dist == 0.0) + { + return 0.0; + } + else if (x != 0 || y != 0) + { + gdouble ang0, ang1; + gdouble ang; + gdouble rat; + + ang0 = atan2 (axis[0], axis[1]) + G_PI; + + ang1 = atan2 (x, y) + G_PI; + + ang = ang1 - ang0; + + if (ang < 0.0) + ang += (2.0 * G_PI); + + rat = ang / (2.0 * G_PI); + rat = pow (rat, (offset / 10.0) + 1.0); + + return CLAMP (rat, 0.0, 1.0); + } + else + { + return 0.5; /* We are on middle point */ + } +} + +static gdouble +gradient_calc_square_factor (gdouble dist, + gdouble offset, + gdouble x, + gdouble y) +{ + if (dist == 0.0) + { + return 0.0; + } + else + { + gdouble r; + gdouble rat; + + /* Calculate offset from start as a value in [0, 1] */ + + offset = offset / 100.0; + + r = MAX (fabs (x), fabs (y)); + rat = r / dist; + + if (rat < offset) + return 0.0; + else if (offset == 1.0) + return (rat >= 1.0) ? 1.0 : 0.0; + else + return (rat - offset) / (1.0 - offset); + } +} + +static gdouble +gradient_calc_radial_factor (gdouble dist, + gdouble offset, + gdouble x, + gdouble y) +{ + if (dist == 0.0) + { + return 0.0; + } + else + { + gdouble r; + gdouble rat; + + /* Calculate radial offset from start as a value in [0, 1] */ + + offset = offset / 100.0; + + r = sqrt (SQR (x) + SQR (y)); + rat = r / dist; + + if (rat < offset) + return 0.0; + else if (offset == 1.0) + return (rat >= 1.0) ? 1.0 : 0.0; + else + return (rat - offset) / (1.0 - offset); + } +} + +static gdouble +gradient_calc_linear_factor (gdouble dist, + gdouble *vec, + gdouble offset, + gdouble x, + gdouble y) +{ + if (dist == 0.0) + { + return 0.0; + } + else + { + gdouble r; + gdouble rat; + + offset = offset / 100.0; + + r = vec[0] * x + vec[1] * y; + rat = r / dist; + + if (rat >= 0.0 && rat < offset) + return 0.0; + else if (offset == 1.0) + return (rat >= 1.0) ? 1.0 : 0.0; + else if (rat < 0.0) + return rat / (1.0 - offset); + else + return (rat - offset) / (1.0 - offset); + } +} + +static gdouble +gradient_calc_bilinear_factor (gdouble dist, + gdouble *vec, + gdouble offset, + gdouble x, + gdouble y) +{ + if (dist == 0.0) + { + return 0.0; + } + else + { + gdouble r; + gdouble rat; + + /* Calculate linear offset from the start line outward */ + + offset = offset / 100.0; + + r = vec[0] * x + vec[1] * y; + rat = r / dist; + + if (fabs (rat) < offset) + return 0.0; + else if (offset == 1.0) + return (rat == 1.0) ? 1.0 : 0.0; + else + return (fabs (rat) - offset) / (1.0 - offset); + } +} + +static gdouble +gradient_calc_spiral_factor (gdouble dist, + gdouble *axis, + gdouble offset, + gdouble x, + gdouble y, + gboolean clockwise) +{ + if (dist == 0.0) + { + return 0.0; + } + else if (x != 0.0 || y != 0.0) + { + gdouble ang0, ang1; + gdouble ang; + double r; + + offset = offset / 100.0; + + ang0 = atan2 (axis[0], axis[1]) + G_PI; + ang1 = atan2 (x, y) + G_PI; + + if (clockwise) + ang = ang1 - ang0; + else + ang = ang0 - ang1; + + if (ang < 0.0) + ang += (2.0 * G_PI); + + r = sqrt (SQR (x) + SQR (y)) / dist; + + return fmod (ang / (2.0 * G_PI) + r + offset, 1.0); + } + else + { + return 0.5 ; /* We are on the middle point */ + } +} + +static gdouble +gradient_calc_shapeburst_angular_factor (GeglSampler *dist_sampler, + gdouble offset, + gdouble x, + gdouble y) +{ + gfloat value; + + offset = offset / 100.0; + + gegl_sampler_get (dist_sampler, x, y, NULL, &value, GEGL_ABYSS_NONE); + + value = 1.0 - value; + + if (value < offset) + value = 0.0; + else if (offset == 1.0) + value = (value >= 1.0) ? 1.0 : 0.0; + else + value = (value - offset) / (1.0 - offset); + + return value; +} + + +static gdouble +gradient_calc_shapeburst_spherical_factor (GeglSampler *dist_sampler, + gdouble offset, + gdouble x, + gdouble y) +{ + gfloat value; + + offset = 1.0 - offset / 100.0; + + gegl_sampler_get (dist_sampler, x, y, NULL, &value, GEGL_ABYSS_NONE); + + if (value > offset) + value = 1.0; + else if (offset == 0.0) + value = (value <= 0.0) ? 0.0 : 1.0; + else + value = value / offset; + + value = 1.0 - sin (0.5 * G_PI * value); + + return value; +} + + +static gdouble +gradient_calc_shapeburst_dimpled_factor (GeglSampler *dist_sampler, + gdouble offset, + gdouble x, + gdouble y) +{ + gfloat value; + + offset = 1.0 - offset / 100.0; + + gegl_sampler_get (dist_sampler, x, y, NULL, &value, GEGL_ABYSS_NONE); + + if (value > offset) + value = 1.0; + else if (offset == 0.0) + value = (value <= 0.0) ? 0.0 : 1.0; + else + value = value / offset; + + value = cos (0.5 * G_PI * value); + + return value; +} + +static void +gradient_render_pixel (gdouble x, + gdouble y, + GimpRGB *color, + gpointer render_data) +{ + RenderBlendData *rbd = render_data; + gdouble factor; + + /* we want to calculate the color at the pixel's center */ + x += 0.5; + y += 0.5; + + /* Calculate blending factor */ + + switch (rbd->gradient_type) + { + case GIMP_GRADIENT_LINEAR: + factor = gradient_calc_linear_factor (rbd->dist, + rbd->vec, rbd->offset, + x - rbd->sx, y - rbd->sy); + break; + + case GIMP_GRADIENT_BILINEAR: + factor = gradient_calc_bilinear_factor (rbd->dist, + rbd->vec, rbd->offset, + x - rbd->sx, y - rbd->sy); + break; + + case GIMP_GRADIENT_RADIAL: + factor = gradient_calc_radial_factor (rbd->dist, + rbd->offset, + x - rbd->sx, y - rbd->sy); + break; + + case GIMP_GRADIENT_SQUARE: + factor = gradient_calc_square_factor (rbd->dist, rbd->offset, + x - rbd->sx, y - rbd->sy); + break; + + case GIMP_GRADIENT_CONICAL_SYMMETRIC: + factor = gradient_calc_conical_sym_factor (rbd->dist, + rbd->vec, rbd->offset, + x - rbd->sx, y - rbd->sy); + break; + + case GIMP_GRADIENT_CONICAL_ASYMMETRIC: + factor = gradient_calc_conical_asym_factor (rbd->dist, + rbd->vec, rbd->offset, + x - rbd->sx, y - rbd->sy); + break; + + case GIMP_GRADIENT_SHAPEBURST_ANGULAR: + factor = gradient_calc_shapeburst_angular_factor (rbd->dist_sampler, + rbd->offset, + x, y); + break; + + case GIMP_GRADIENT_SHAPEBURST_SPHERICAL: + factor = gradient_calc_shapeburst_spherical_factor (rbd->dist_sampler, + rbd->offset, + x, y); + break; + + case GIMP_GRADIENT_SHAPEBURST_DIMPLED: + factor = gradient_calc_shapeburst_dimpled_factor (rbd->dist_sampler, + rbd->offset, + x, y); + break; + + case GIMP_GRADIENT_SPIRAL_CLOCKWISE: + factor = gradient_calc_spiral_factor (rbd->dist, + rbd->vec, rbd->offset, + x - rbd->sx, y - rbd->sy, TRUE); + break; + + case GIMP_GRADIENT_SPIRAL_ANTICLOCKWISE: + factor = gradient_calc_spiral_factor (rbd->dist, + rbd->vec, rbd->offset, + x - rbd->sx, y - rbd->sy, FALSE); + break; + + default: + g_return_if_reached (); + break; + } + + /* Adjust for repeat */ + + switch (rbd->repeat) + { + case GIMP_REPEAT_NONE: + break; + + case GIMP_REPEAT_SAWTOOTH: + factor = factor - floor (factor); + break; + + case GIMP_REPEAT_TRIANGULAR: + { + guint ifactor; + + if (factor < 0.0) + factor = -factor; + + ifactor = (guint) factor; + factor = factor - floor (factor); + + if (ifactor & 1) + factor = 1.0 - factor; + } + break; + + case GIMP_REPEAT_TRUNCATE: + if (factor < 0.0 || factor > 1.0) + { + gimp_rgba_set (color, 0.0, 0.0, 0.0, 0.0); + return; + } + break; + } + + /* Blend the colors */ + + if (rbd->gradient_cache) + { + factor = CLAMP (factor, 0.0, 1.0); + + *color = + rbd->gradient_cache[ROUND (factor * (rbd->gradient_cache_size - 1))]; + } + else + { + rbd->last_seg = gimp_gradient_get_color_at (rbd->gradient, NULL, + rbd->last_seg, factor, + rbd->reverse, + rbd->blend_color_space, + color); + } +} + +static void +gradient_put_pixel (gint x, + gint y, + GimpRGB *color, + gpointer put_pixel_data) +{ + PutPixelData *ppd = put_pixel_data; + const gint index = (y - ppd->roi.y) * ppd->roi.width + (x - ppd->roi.x); + gfloat *dest = ppd->data + 4 * index; + + if (ppd->dither_rand) + { + gradient_dither_pixel (color, ppd->dither_rand, dest); + + dest += 4; + } + else + { + *dest++ = color->r; + *dest++ = color->g; + *dest++ = color->b; + *dest++ = color->a; + } +} + +static void +gradient_dither_pixel (GimpRGB *color, + GRand *dither_rand, + gfloat *dest) +{ + gfloat r, g, b, a; + guint i; + + i = g_rand_int (dither_rand); + + r = color->r + (gdouble) (i & 0xff) / 256.0 / 256.0 - 0.5 / 256.0; i >>= 8; + g = color->g + (gdouble) (i & 0xff) / 256.0 / 256.0 - 0.5 / 256.0; i >>= 8; + b = color->b + (gdouble) (i & 0xff) / 256.0 / 256.0 - 0.5 / 256.0; i >>= 8; + + if (color->a > 0.0 && color->a < 1.0) + a = color->a + (gdouble) (i & 0xff) / 256.0 / 256.0 - 0.5 / 256.0; + else + a = color->a; + + *dest++ = CLAMP (r, 0.0, 1.0); + *dest++ = CLAMP (g, 0.0, 1.0); + *dest++ = CLAMP (b, 0.0, 1.0); + *dest++ = CLAMP (a, 0.0, 1.0); +} + +static gboolean +gimp_operation_gradient_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *result, + gint level) +{ + GimpOperationGradient *self = GIMP_OPERATION_GRADIENT (operation); + + const gdouble sx = self->start_x; + const gdouble sy = self->start_y; + const gdouble ex = self->end_x; + const gdouble ey = self->end_y; + + RenderBlendData rbd = { 0, }; + + GeglBufferIterator *iter; + GeglRectangle *roi; + GRand *dither_rand = NULL; + + if (! self->gradient) + return TRUE; + + gimp_operation_gradient_validate_cache (self); + + rbd.gradient = self->gradient; + rbd.reverse = self->gradient_reverse; + rbd.blend_color_space = self->gradient_blend_color_space; + rbd.gradient_cache = self->gradient_cache; + rbd.gradient_cache_size = self->gradient_cache_size; + + /* Calculate type-specific parameters */ + + switch (self->gradient_type) + { + case GIMP_GRADIENT_RADIAL: + rbd.dist = sqrt (SQR (ex - sx) + SQR (ey - sy)); + break; + + case GIMP_GRADIENT_SQUARE: + rbd.dist = MAX (fabs (ex - sx), fabs (ey - sy)); + break; + + case GIMP_GRADIENT_CONICAL_SYMMETRIC: + case GIMP_GRADIENT_CONICAL_ASYMMETRIC: + case GIMP_GRADIENT_SPIRAL_CLOCKWISE: + case GIMP_GRADIENT_SPIRAL_ANTICLOCKWISE: + case GIMP_GRADIENT_LINEAR: + case GIMP_GRADIENT_BILINEAR: + rbd.dist = sqrt (SQR (ex - sx) + SQR (ey - sy)); + + if (rbd.dist > 0.0) + { + rbd.vec[0] = (ex - sx) / rbd.dist; + rbd.vec[1] = (ey - sy) / rbd.dist; + } + + break; + + case GIMP_GRADIENT_SHAPEBURST_ANGULAR: + case GIMP_GRADIENT_SHAPEBURST_SPHERICAL: + case GIMP_GRADIENT_SHAPEBURST_DIMPLED: + rbd.dist = sqrt (SQR (ex - sx) + SQR (ey - sy)); + rbd.dist_sampler = gegl_buffer_sampler_new_at_level ( + input, babl_format ("Y float"), GEGL_SAMPLER_NEAREST, level); + break; + + default: + g_return_val_if_reached (FALSE); + break; + } + + /* Initialize render data */ + + rbd.offset = self->offset; + rbd.sx = self->start_x; + rbd.sy = self->start_y; + rbd.gradient_type = self->gradient_type; + rbd.repeat = self->gradient_repeat; + + /* Render the gradient! */ + + iter = gegl_buffer_iterator_new (output, result, 0, + babl_format ("R'G'B'A float"), + GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1); + roi = &iter->items[0].roi; + + if (self->dither) + dither_rand = g_rand_new (); + + if (self->supersample) + { + PutPixelData ppd; + + ppd.dither_rand = dither_rand; + + while (gegl_buffer_iterator_next (iter)) + { + ppd.data = iter->items[0].data; + ppd.roi = *roi; + + gimp_adaptive_supersample_area (roi->x, roi->y, + roi->x + roi->width - 1, + roi->y + roi->height - 1, + self->supersample_depth, + self->supersample_threshold, + gradient_render_pixel, &rbd, + gradient_put_pixel, &ppd, + NULL, + NULL); + } + } + else + { + while (gegl_buffer_iterator_next (iter)) + { + gfloat *dest = iter->items[0].data; + gint endx = roi->x + roi->width; + gint endy = roi->y + roi->height; + gint x, y; + + if (dither_rand) + { + for (y = roi->y; y < endy; y++) + for (x = roi->x; x < endx; x++) + { + GimpRGB color = { 0.0, 0.0, 0.0, 1.0 }; + + gradient_render_pixel (x, y, &color, &rbd); + gradient_dither_pixel (&color, dither_rand, dest); + + dest += 4; + } + } + else + { + for (y = roi->y; y < endy; y++) + for (x = roi->x; x < endx; x++) + { + GimpRGB color = { 0.0, 0.0, 0.0, 1.0 }; + + gradient_render_pixel (x, y, &color, &rbd); + + *dest++ = color.r; + *dest++ = color.g; + *dest++ = color.b; + *dest++ = color.a; + } + } + } + } + + if (self->dither) + g_rand_free (dither_rand); + + g_clear_object (&rbd.dist_sampler); + + return TRUE; +} + +static void +gimp_operation_gradient_invalidate_cache (GimpOperationGradient *self) +{ + g_clear_pointer (&self->gradient_cache, g_free); +} + +static void +gimp_operation_gradient_validate_cache (GimpOperationGradient *self) +{ + GimpGradientSegment *last_seg = NULL; + gint cache_size; + gint i; + + if (! self->gradient) + return; + + g_mutex_lock (&self->gradient_cache_mutex); + + if (self->gradient_cache) + { + g_mutex_unlock (&self->gradient_cache_mutex); + + return; + } + + cache_size = ceil (hypot (self->start_x - self->end_x, + self->start_y - self->end_y)) * + GRADIENT_CACHE_N_SUPERSAMPLES; + + /* have at least two values in the cache */ + cache_size = MAX (cache_size, 2); + + /* don't use a cache if its necessary size is too big */ + if (cache_size > GRADIENT_CACHE_MAX_SIZE) + { + g_mutex_unlock (&self->gradient_cache_mutex); + + return; + } + + self->gradient_cache = g_new0 (GimpRGB, cache_size); + self->gradient_cache_size = cache_size; + + for (i = 0; i < self->gradient_cache_size; i++) + { + gdouble factor = (gdouble) i / (gdouble) (self->gradient_cache_size - 1); + + last_seg = gimp_gradient_get_color_at (self->gradient, NULL, last_seg, + factor, + self->gradient_reverse, + self->gradient_blend_color_space, + self->gradient_cache + i); + } + + g_mutex_unlock (&self->gradient_cache_mutex); +} diff --git a/app/operations/gimpoperationgradient.h b/app/operations/gimpoperationgradient.h new file mode 100644 index 0000000..e2aa19c --- /dev/null +++ b/app/operations/gimpoperationgradient.h @@ -0,0 +1,73 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationgradient.h + * Copyright (C) 2014 Michael Henning <drawoc@darkrefraction.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_GRADIENT_H__ +#define __GIMP_OPERATION_GRADIENT_H__ + + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_GRADIENT (gimp_operation_gradient_get_type ()) +#define GIMP_OPERATION_GRADIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_GRADIENT, GimpOperationGradient)) +#define GIMP_OPERATION_GRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_GRADIENT, GimpOperationGradientClass)) +#define GIMP_IS_OPERATION_GRADIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_GRADIENT)) +#define GIMP_IS_OPERATION_GRADIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_GRADIENT)) +#define GIMP_OPERATION_GRADIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_GRADIENT, GimpOperationGradientClass)) + + +typedef struct _GimpOperationGradient GimpOperationGradient; +typedef struct _GimpOperationGradientClass GimpOperationGradientClass; + +struct _GimpOperationGradient +{ + GeglOperationFilter parent_instance; + + GimpContext *context; + + GimpGradient *gradient; + gdouble start_x, start_y, end_x, end_y; + GimpGradientType gradient_type; + GimpRepeatMode gradient_repeat; + gdouble offset; + gboolean gradient_reverse; + GimpGradientBlendColorSpace gradient_blend_color_space; + + gboolean supersample; + gint supersample_depth; + gdouble supersample_threshold; + + gboolean dither; + + GimpRGB *gradient_cache; + gint gradient_cache_size; + GMutex gradient_cache_mutex; +}; + +struct _GimpOperationGradientClass +{ + GeglOperationFilterClass parent_class; +}; + + +GType gimp_operation_gradient_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_GRADIENT_H__ */ diff --git a/app/operations/gimpoperationgrow.c b/app/operations/gimpoperationgrow.c new file mode 100644 index 0000000..2aabcee --- /dev/null +++ b/app/operations/gimpoperationgrow.c @@ -0,0 +1,391 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationgrow.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimpoperationgrow.h" + + +enum +{ + PROP_0, + PROP_RADIUS_X, + PROP_RADIUS_Y +}; + + +static void gimp_operation_grow_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_grow_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_grow_prepare (GeglOperation *operation); +static GeglRectangle + gimp_operation_grow_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi); +static GeglRectangle + gimp_operation_grow_get_cached_region (GeglOperation *self, + const GeglRectangle *roi); + +static gboolean gimp_operation_grow_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationGrow, gimp_operation_grow, + GEGL_TYPE_OPERATION_FILTER) + +#define parent_class gimp_operation_grow_parent_class + + +static void +gimp_operation_grow_class_init (GimpOperationGrowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_grow_set_property; + object_class->get_property = gimp_operation_grow_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:grow", + "categories", "gimp", + "description", "GIMP Grow operation", + NULL); + + operation_class->prepare = gimp_operation_grow_prepare; + operation_class->get_required_for_output = gimp_operation_grow_get_required_for_output; + operation_class->get_cached_region = gimp_operation_grow_get_cached_region; + operation_class->threaded = FALSE; + + filter_class->process = gimp_operation_grow_process; + + g_object_class_install_property (object_class, PROP_RADIUS_X, + g_param_spec_int ("radius-x", + "Radius X", + "Grow radius in X direction", + 1, 2342, 1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_RADIUS_Y, + g_param_spec_int ("radius-y", + "Radius Y", + "Grow radius in Y direction", + 1, 2342, 1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_grow_init (GimpOperationGrow *self) +{ +} + +static void +gimp_operation_grow_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationGrow *self = GIMP_OPERATION_GROW (object); + + switch (property_id) + { + case PROP_RADIUS_X: + g_value_set_int (value, self->radius_x); + break; + + case PROP_RADIUS_Y: + g_value_set_int (value, self->radius_y); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_grow_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationGrow *self = GIMP_OPERATION_GROW (object); + + switch (property_id) + { + case PROP_RADIUS_X: + self->radius_x = g_value_get_int (value); + break; + + case PROP_RADIUS_Y: + self->radius_y = g_value_get_int (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_grow_prepare (GeglOperation *operation) +{ + const Babl *space = gegl_operation_get_source_space (operation, "input"); + gegl_operation_set_format (operation, "input", babl_format_with_space ("Y float", space)); + gegl_operation_set_format (operation, "output", babl_format_with_space ("Y float", space)); +} + +static GeglRectangle +gimp_operation_grow_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi) +{ + return *gegl_operation_source_get_bounding_box (self, "input"); +} + +static GeglRectangle +gimp_operation_grow_get_cached_region (GeglOperation *self, + const GeglRectangle *roi) +{ + return *gegl_operation_source_get_bounding_box (self, "input"); +} + +static void +compute_border (gint16 *circ, + guint16 xradius, + guint16 yradius) +{ + gint32 i; + gint32 diameter = xradius * 2 + 1; + gdouble tmp; + + for (i = 0; i < diameter; i++) + { + if (i > xradius) + tmp = (i - xradius) - 0.5; + else if (i < xradius) + tmp = (xradius - i) - 0.5; + else + tmp = 0.0; + + circ[i] = RINT (yradius / + (gdouble) xradius * sqrt (SQR (xradius) - SQR (tmp))); + } +} + +static inline void +rotate_pointers (gfloat **p, + guint32 n) +{ + guint32 i; + gfloat *tmp; + + tmp = p[0]; + + for (i = 0; i < n - 1; i++) + p[i] = p[i + 1]; + + p[i] = tmp; +} + +static gboolean +gimp_operation_grow_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level) +{ + /* Any bugs in this function are probably also in thin_region. + * Blame all bugs in this function on jaycox@gimp.org + */ + GimpOperationGrow *self = GIMP_OPERATION_GROW (operation); + const Babl *input_format = gegl_operation_get_format (operation, "input"); + const Babl *output_format = gegl_operation_get_format (operation, "output"); + gint32 i, j, x, y; + gfloat **buf; /* caches the region's pixel data */ + gfloat *out; /* holds the new scan line we are computing */ + gfloat **max; /* caches the largest values for each column */ + gint16 *circ; /* holds the y coords of the filter's mask */ + gfloat last_max; + gint16 last_index; + gfloat *buffer; + + max = g_new (gfloat *, roi->width + 2 * self->radius_x); + buf = g_new (gfloat *, self->radius_y + 1); + + for (i = 0; i < self->radius_y + 1; i++) + buf[i] = g_new (gfloat, roi->width); + + buffer = g_new (gfloat, + (roi->width + 2 * self->radius_x) * (self->radius_y + 1)); + + for (i = 0; i < roi->width + 2 * self->radius_x; i++) + { + if (i < self->radius_x) + max[i] = buffer; + else if (i < roi->width + self->radius_x) + max[i] = &buffer[(self->radius_y + 1) * (i - self->radius_x)]; + else + max[i] = &buffer[(self->radius_y + 1) * (roi->width + self->radius_x - 1)]; + + for (j = 0; j < self->radius_y + 1; j++) + max[i][j] = 0.0; + } + + /* offset the max pointer by self->radius_x so the range of the + * array is [-self->radius_x] to [roi->width + self->radius_x] + */ + max += self->radius_x; + + out = g_new (gfloat, roi->width); + + circ = g_new (gint16, 2 * self->radius_x + 1); + compute_border (circ, self->radius_x, self->radius_y); + + /* offset the circ pointer by self->radius_x so the range of the + * array is [-self->radius_x] to [self->radius_x] + */ + circ += self->radius_x; + + memset (buf[0], 0, roi->width * sizeof (gfloat)); + + for (i = 0; i < self->radius_y && i < roi->height; i++) /* load top of image */ + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + i, + roi->width, 1), + 1.0, input_format, buf[i + 1], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + + for (x = 0; x < roi->width; x++) /* set up max for top of image */ + { + max[x][0] = 0.0; /* buf[0][x] is always 0 */ + max[x][1] = buf[1][x]; /* MAX (buf[1][x], max[x][0]) always = buf[1][x]*/ + + for (j = 2; j < self->radius_y + 1; j++) + max[x][j] = MAX (buf[j][x], max[x][j - 1]); + } + + for (y = 0; y < roi->height; y++) + { + rotate_pointers (buf, self->radius_y + 1); + + if (y < roi->height - (self->radius_y)) + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + y + self->radius_y, + roi->width, 1), + 1.0, input_format, buf[self->radius_y], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + else + memset (buf[self->radius_y], 0, roi->width * sizeof (gfloat)); + + for (x = 0; x < roi->width; x++) /* update max array */ + { + for (i = self->radius_y; i > 0; i--) + max[x][i] = MAX (MAX (max[x][i - 1], buf[i - 1][x]), buf[i][x]); + + max[x][0] = buf[0][x]; + } + + last_max = max[0][circ[-1]]; + last_index = 1; + + for (x = 0; x < roi->width; x++) /* render scan line */ + { + last_index--; + + if (last_index >= 0) + { + if (last_max >= 1.0) + { + out[x] = 1.0; + } + else + { + last_max = 0.0; + + for (i = self->radius_x; i >= 0; i--) + if (last_max < max[x + i][circ[i]]) + { + last_max = max[x + i][circ[i]]; + last_index = i; + } + + out[x] = last_max; + } + } + else + { + last_index = self->radius_x; + last_max = max[x + self->radius_x][circ[self->radius_x]]; + + for (i = self->radius_x - 1; i >= -self->radius_x; i--) + if (last_max < max[x + i][circ[i]]) + { + last_max = max[x + i][circ[i]]; + last_index = i; + } + + out[x] = last_max; + } + } + + gegl_buffer_set (output, + GEGL_RECTANGLE (roi->x, roi->y + y, + roi->width, 1), + 0, output_format, out, + GEGL_AUTO_ROWSTRIDE); + } + + /* undo the offsets to the pointers so we can free the malloced memory */ + circ -= self->radius_x; + max -= self->radius_x; + + g_free (circ); + g_free (buffer); + g_free (max); + + for (i = 0; i < self->radius_y + 1; i++) + g_free (buf[i]); + + g_free (buf); + g_free (out); + + return TRUE; +} diff --git a/app/operations/gimpoperationgrow.h b/app/operations/gimpoperationgrow.h new file mode 100644 index 0000000..d680997 --- /dev/null +++ b/app/operations/gimpoperationgrow.h @@ -0,0 +1,56 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationgrow.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_GROW_H__ +#define __GIMP_OPERATION_GROW_H__ + + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_GROW (gimp_operation_grow_get_type ()) +#define GIMP_OPERATION_GROW(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_GROW, GimpOperationGrow)) +#define GIMP_OPERATION_GROW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_GROW, GimpOperationGrowClass)) +#define GIMP_IS_OPERATION_GROW(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_GROW)) +#define GIMP_IS_OPERATION_GROW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_GROW)) +#define GIMP_OPERATION_GROW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_GROW, GimpOperationGrowClass)) + + +typedef struct _GimpOperationGrow GimpOperationGrow; +typedef struct _GimpOperationGrowClass GimpOperationGrowClass; + +struct _GimpOperationGrow +{ + GeglOperationFilter parent_instance; + + gint radius_x; + gint radius_y; +}; + +struct _GimpOperationGrowClass +{ + GeglOperationFilterClass parent_class; +}; + + +GType gimp_operation_grow_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_GROW_H__ */ diff --git a/app/operations/gimpoperationhistogramsink.c b/app/operations/gimpoperationhistogramsink.c new file mode 100644 index 0000000..cb0a7ac --- /dev/null +++ b/app/operations/gimpoperationhistogramsink.c @@ -0,0 +1,244 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhistogramsink.c + * Copyright (C) 2012 Øyvind Kolås + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "operations-types.h" + +#include "core/gimphistogram.h" + +#include "gimpoperationhistogramsink.h" + + +enum +{ + PROP_0, + PROP_AUX, + PROP_HISTOGRAM +}; + + +static void gimp_operation_histogram_sink_finalize (GObject *object); +static void gimp_operation_histogram_sink_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_histogram_sink_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_histogram_sink_attach (GeglOperation *operation); +static void gimp_operation_histogram_sink_prepare (GeglOperation *operation); +static GeglRectangle + gimp_operation_histogram_sink_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi); +static gboolean gimp_operation_histogram_sink_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level); + + +G_DEFINE_TYPE (GimpOperationHistogramSink, gimp_operation_histogram_sink, + GEGL_TYPE_OPERATION_SINK) + +#define parent_class gimp_operation_histogram_sink_parent_class + + +static void +gimp_operation_histogram_sink_class_init (GimpOperationHistogramSinkClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + + object_class->finalize = gimp_operation_histogram_sink_finalize; + object_class->set_property = gimp_operation_histogram_sink_set_property; + object_class->get_property = gimp_operation_histogram_sink_get_property; + + gegl_operation_class_set_keys (operation_class, + "name" , "gimp:histogram-sink", + "categories" , "color", + "description", "GIMP Histogram sink operation", + NULL); + + operation_class->attach = gimp_operation_histogram_sink_attach; + operation_class->prepare = gimp_operation_histogram_sink_prepare; + operation_class->get_required_for_output = gimp_operation_histogram_sink_get_required_for_output; + operation_class->process = gimp_operation_histogram_sink_process; + + g_object_class_install_property (object_class, PROP_AUX, + g_param_spec_object ("aux", + "Aux", + "Auxiliary image buffer input pad.", + GEGL_TYPE_BUFFER, + G_PARAM_READWRITE | + GEGL_PARAM_PAD_INPUT)); + + g_object_class_install_property (object_class, PROP_HISTOGRAM, + g_param_spec_object ("histogram", + "Histogram", + "The result histogram", + GIMP_TYPE_HISTOGRAM, + G_PARAM_READWRITE)); +} + +static void +gimp_operation_histogram_sink_init (GimpOperationHistogramSink *self) +{ +} + +static void +gimp_operation_histogram_sink_finalize (GObject *object) +{ + GimpOperationHistogramSink *sink = GIMP_OPERATION_HISTOGRAM_SINK (object); + + g_clear_object (&sink->histogram); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_operation_histogram_sink_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationHistogramSink *sink = GIMP_OPERATION_HISTOGRAM_SINK (object); + + switch (prop_id) + { + case PROP_AUX: + break; + + case PROP_HISTOGRAM: + g_value_set_pointer (value, sink->histogram); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gimp_operation_histogram_sink_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationHistogramSink *sink = GIMP_OPERATION_HISTOGRAM_SINK (object); + + switch (prop_id) + { + case PROP_AUX: + break; + + case PROP_HISTOGRAM: + if (sink->histogram) + g_object_unref (sink->histogram); + sink->histogram = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +gimp_operation_histogram_sink_attach (GeglOperation *self) +{ + GeglOperation *operation = GEGL_OPERATION (self); + GObjectClass *object_class = G_OBJECT_GET_CLASS (self); + + GEGL_OPERATION_CLASS (parent_class)->attach (self); + + gegl_operation_create_pad (operation, + g_object_class_find_property (object_class, + "aux")); +} + +static void +gimp_operation_histogram_sink_prepare (GeglOperation *operation) +{ + /* XXX gegl_operation_set_format (operation, "input", babl_format ("Y u8")); */ + gegl_operation_set_format (operation, "aux", babl_format ("Y float")); +} + +static GeglRectangle +gimp_operation_histogram_sink_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi) +{ + /* dunno what to do here, make a wild guess */ + return *roi; +} + +static gboolean +gimp_operation_histogram_sink_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level) +{ + GeglBuffer *input; + GeglBuffer *aux; + + if (strcmp (output_prop, "output")) + { + g_warning ("requested processing of %s pad on a sink", output_prop); + return FALSE; + } + + input = (GeglBuffer*) gegl_operation_context_dup_object (context, "input"); + aux = (GeglBuffer*) gegl_operation_context_dup_object (context, "aux"); + + if (! input) + { + g_warning ("received NULL input"); + + return FALSE; + } + + if (aux) + { + /* do hist with mask */ + + g_printerr ("aux format: %s\n", + babl_get_name (gegl_buffer_get_format (aux))); + + g_object_unref (aux); + } + else + { + /* without */ + } + + g_printerr ("input format: %s\n", + babl_get_name (gegl_buffer_get_format (input))); + + g_object_unref (input); + + return TRUE; +} diff --git a/app/operations/gimpoperationhistogramsink.h b/app/operations/gimpoperationhistogramsink.h new file mode 100644 index 0000000..719719c --- /dev/null +++ b/app/operations/gimpoperationhistogramsink.h @@ -0,0 +1,56 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhistogramsink.h + * Copyright (C) 2012 Øyvind Kolås + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_HISTOGRAM_SINK_H__ +#define __GIMP_OPERATION_HISTOGRAM_SINK_H__ + + +#include <gegl-plugin.h> +#include <operation/gegl-operation-sink.h> + + +#define GIMP_TYPE_OPERATION_HISTOGRAM_SINK (gimp_operation_histogram_sink_get_type ()) +#define GIMP_OPERATION_HISTOGRAM_SINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_HISTOGRAM_SINK, GimpOperationHistogramSink)) +#define GIMP_OPERATION_HISTOGRAM_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_HISTOGRAM_SINK, GimpOperationHistogramSinkClass)) +#define GEGL_IS_OPERATION_HISTOGRAM_SINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_HISTOGRAM_SINK)) +#define GEGL_IS_OPERATION_HISTOGRAM_SINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_HISTOGRAM_SINK)) +#define GIMP_OPERATION_HISTOGRAM_SINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_HISTOGRAM_SINK, GimpOperationHistogramSinkClass)) + + +typedef struct _GimpOperationHistogramSink GimpOperationHistogramSink; +typedef struct _GimpOperationHistogramSinkClass GimpOperationHistogramSinkClass; + +struct _GimpOperationHistogramSink +{ + GeglOperation parent_instance; + + GimpHistogram *histogram; +}; + +struct _GimpOperationHistogramSinkClass +{ + GeglOperationSinkClass parent_class; +}; + + +GType gimp_operation_histogram_sink_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_HISTOGRAM_SINK_C__ */ diff --git a/app/operations/gimpoperationhuesaturation.c b/app/operations/gimpoperationhuesaturation.c new file mode 100644 index 0000000..cdfb7d7 --- /dev/null +++ b/app/operations/gimpoperationhuesaturation.c @@ -0,0 +1,302 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhuesaturation.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimphuesaturationconfig.h" +#include "gimpoperationhuesaturation.h" + +#include "gimp-intl.h" + + +static gboolean gimp_operation_hue_saturation_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationHueSaturation, gimp_operation_hue_saturation, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_hue_saturation_parent_class + + +static void +gimp_operation_hue_saturation_class_init (GimpOperationHueSaturationClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_point_filter_set_property; + object_class->get_property = gimp_operation_point_filter_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:hue-saturation", + "categories", "color", + "description", _("Adjust hue, saturation, and lightness"), + NULL); + + point_class->process = gimp_operation_hue_saturation_process; + + g_object_class_install_property (object_class, + GIMP_OPERATION_POINT_FILTER_PROP_CONFIG, + g_param_spec_object ("config", + "Config", + "The config object", + GIMP_TYPE_HUE_SATURATION_CONFIG, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_hue_saturation_init (GimpOperationHueSaturation *self) +{ +} + +static inline gdouble +map_hue (GimpHueSaturationConfig *config, + GimpHueRange range, + gdouble value) +{ + value += (config->hue[GIMP_HUE_RANGE_ALL] + config->hue[range]) / 2.0; + + if (value < 0) + return value + 1.0; + else if (value > 1.0) + return value - 1.0; + else + return value; +} + +static inline gdouble +map_hue_overlap (GimpHueSaturationConfig *config, + GimpHueRange primary_range, + GimpHueRange secondary_range, + gdouble value, + gdouble primary_intensity, + gdouble secondary_intensity) +{ + /* When calculating an overlap between two ranges, interpolate the + * hue adjustment from config->hue[primary_range] and + * config->hue[secondary_range] BEFORE mapping it to the input + * value. This fixes odd edge cases where only one of the ranges + * crosses the red/magenta wraparound (bug #527085), or if + * adjustments to different channels yield more than 180 degree + * difference from each other. (Why anyone would do that is beyond + * me, but still.) + * + * See bugs #527085 and #644032 for examples of such cases. + */ + gdouble v = config->hue[primary_range] * primary_intensity + + config->hue[secondary_range] * secondary_intensity; + + value += (config->hue[GIMP_HUE_RANGE_ALL] + v) / 2.0; + + if (value < 0) + return value + 1.0; + else if (value > 1.0) + return value - 1.0; + else + return value; +} + +static inline gdouble +map_saturation (GimpHueSaturationConfig *config, + GimpHueRange range, + gdouble value) +{ + gdouble v = config->saturation[GIMP_HUE_RANGE_ALL] + config->saturation[range]; + + /* This change affects the way saturation is computed. With the old + * code (different code for value < 0), increasing the saturation + * affected muted colors very much, and bright colors less. With the + * new code, it affects muted colors and bright colors more or less + * evenly. For enhancing the color in photos, the new behavior is + * exactly what you want. It's hard for me to imagine a case in + * which the old behavior is better. + */ + value *= (v + 1.0); + + return CLAMP (value, 0.0, 1.0); +} + +static inline gdouble +map_lightness (GimpHueSaturationConfig *config, + GimpHueRange range, + gdouble value) +{ + gdouble v = (config->lightness[GIMP_HUE_RANGE_ALL] + config->lightness[range]) / 2.0; + + if (v < 0) + return value * (v + 1.0); + else + return value + (v * (1.0 - value)); +} + +static gboolean +gimp_operation_hue_saturation_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationPointFilter *point = GIMP_OPERATION_POINT_FILTER (operation); + GimpHueSaturationConfig *config = GIMP_HUE_SATURATION_CONFIG (point->config); + gfloat *src = in_buf; + gfloat *dest = out_buf; + gfloat overlap; + + if (! config) + return FALSE; + + overlap = config->overlap / 2.0; + + while (samples--) + { + GimpRGB rgb; + GimpHSL hsl; + gdouble h; + gint hue_counter; + gint hue = 0; + gint secondary_hue = 0; + gboolean use_secondary_hue = FALSE; + gfloat primary_intensity = 0.0; + gfloat secondary_intensity = 0.0; + + rgb.r = src[RED]; + rgb.g = src[GREEN]; + rgb.b = src[BLUE]; + rgb.a = src[ALPHA]; + + gimp_rgb_to_hsl (&rgb, &hsl); + + h = hsl.h * 6.0; + + for (hue_counter = 0; hue_counter < 7; hue_counter++) + { + gdouble hue_threshold = (gdouble) hue_counter + 0.5; + + if (h < ((gdouble) hue_threshold + overlap)) + { + hue = hue_counter; + + if (overlap > 0.0 && h > ((gdouble) hue_threshold - overlap)) + { + use_secondary_hue = TRUE; + + secondary_hue = hue_counter + 1; + + secondary_intensity = + (h - (gdouble) hue_threshold + overlap) / (2.0 * overlap); + + primary_intensity = 1.0 - secondary_intensity; + } + else + { + use_secondary_hue = FALSE; + } + + break; + } + } + + if (hue >= 6) + { + hue = 0; + use_secondary_hue = FALSE; + } + + if (secondary_hue >= 6) + { + secondary_hue = 0; + } + + /* transform into GimpHueRange values */ + hue++; + secondary_hue++; + + if (use_secondary_hue) + { + hsl.h = map_hue_overlap (config, hue, secondary_hue, hsl.h, + primary_intensity, secondary_intensity); + + hsl.s = (map_saturation (config, hue, hsl.s) * primary_intensity + + map_saturation (config, secondary_hue, hsl.s) * secondary_intensity); + + hsl.l = (map_lightness (config, hue, hsl.l) * primary_intensity + + map_lightness (config, secondary_hue, hsl.l) * secondary_intensity); + } + else + { + hsl.h = map_hue (config, hue, hsl.h); + hsl.s = map_saturation (config, hue, hsl.s); + hsl.l = map_lightness (config, hue, hsl.l); + } + + gimp_hsl_to_rgb (&hsl, &rgb); + + dest[RED] = rgb.r; + dest[GREEN] = rgb.g; + dest[BLUE] = rgb.b; + dest[ALPHA] = rgb.a; + + src += 4; + dest += 4; + } + + return TRUE; +} + + +/* public functions */ + +void +gimp_operation_hue_saturation_map (GimpHueSaturationConfig *config, + const GimpRGB *color, + GimpHueRange range, + GimpRGB *result) +{ + GimpHSL hsl; + + g_return_if_fail (GIMP_IS_HUE_SATURATION_CONFIG (config)); + g_return_if_fail (color != NULL); + g_return_if_fail (result != NULL); + + gimp_rgb_to_hsl (color, &hsl); + + hsl.h = map_hue (config, range, hsl.h); + hsl.s = map_saturation (config, range, hsl.s); + hsl.l = map_lightness (config, range, hsl.l); + + gimp_hsl_to_rgb (&hsl, result); +} diff --git a/app/operations/gimpoperationhuesaturation.h b/app/operations/gimpoperationhuesaturation.h new file mode 100644 index 0000000..b084bbe --- /dev/null +++ b/app/operations/gimpoperationhuesaturation.h @@ -0,0 +1,58 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhuesaturation.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_HUE_SATURATION_H__ +#define __GIMP_OPERATION_HUE_SATURATION_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_HUE_SATURATION (gimp_operation_hue_saturation_get_type ()) +#define GIMP_OPERATION_HUE_SATURATION(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_HUE_SATURATION, GimpOperationHueSaturation)) +#define GIMP_OPERATION_HUE_SATURATION_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_HUE_SATURATION, GimpOperationHueSaturationClass)) +#define GIMP_IS_OPERATION_HUE_SATURATION(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_HUE_SATURATION)) +#define GIMP_IS_OPERATION_HUE_SATURATION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_HUE_SATURATION)) +#define GIMP_OPERATION_HUE_SATURATION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_HUE_SATURATION, GimpOperationHueSaturationClass)) + + +typedef struct _GimpOperationHueSaturation GimpOperationHueSaturation; +typedef struct _GimpOperationHueSaturationClass GimpOperationHueSaturationClass; + +struct _GimpOperationHueSaturation +{ + GimpOperationPointFilter parent_instance; +}; + +struct _GimpOperationHueSaturationClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_hue_saturation_get_type (void) G_GNUC_CONST; + +void gimp_operation_hue_saturation_map (GimpHueSaturationConfig *config, + const GimpRGB *color, + GimpHueRange range, + GimpRGB *result); + + +#endif /* __GIMP_OPERATION_HUE_SATURATION_H__ */ diff --git a/app/operations/gimpoperationlevels.c b/app/operations/gimpoperationlevels.c new file mode 100644 index 0000000..1bf0b06 --- /dev/null +++ b/app/operations/gimpoperationlevels.c @@ -0,0 +1,208 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlevels.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimplevelsconfig.h" +#include "gimpoperationlevels.h" + +#include "gimp-intl.h" + + +static gboolean gimp_operation_levels_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationLevels, gimp_operation_levels, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_levels_parent_class + + +static void +gimp_operation_levels_class_init (GimpOperationLevelsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_point_filter_set_property; + object_class->get_property = gimp_operation_point_filter_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:levels", + "categories", "color", + "description", _("Adjust color levels"), + NULL); + + point_class->process = gimp_operation_levels_process; + + g_object_class_install_property (object_class, + GIMP_OPERATION_POINT_FILTER_PROP_LINEAR, + g_param_spec_boolean ("linear", + "Linear", + "Whether to operate on linear RGB", + FALSE, + G_PARAM_READWRITE)); + + g_object_class_install_property (object_class, + GIMP_OPERATION_POINT_FILTER_PROP_CONFIG, + g_param_spec_object ("config", + "Config", + "The config object", + GIMP_TYPE_LEVELS_CONFIG, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_levels_init (GimpOperationLevels *self) +{ +} + +static inline gdouble +gimp_operation_levels_map (gdouble value, + gdouble low_input, + gdouble high_input, + gboolean clamp_input, + gdouble inv_gamma, + gdouble low_output, + gdouble high_output, + gboolean clamp_output) +{ + /* determine input intensity */ + if (high_input != low_input) + value = (value - low_input) / (high_input - low_input); + else + value = (value - low_input); + + if (clamp_input) + value = CLAMP (value, 0.0, 1.0); + + if (inv_gamma != 1.0 && value > 0) + value = pow (value, inv_gamma); + + /* determine the output intensity */ + if (high_output >= low_output) + value = value * (high_output - low_output) + low_output; + else if (high_output < low_output) + value = low_output - value * (low_output - high_output); + + if (clamp_output) + value = CLAMP (value, 0.0, 1.0); + + return value; +} + +static gboolean +gimp_operation_levels_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationPointFilter *point = GIMP_OPERATION_POINT_FILTER (operation); + GimpLevelsConfig *config = GIMP_LEVELS_CONFIG (point->config); + gfloat *src = in_buf; + gfloat *dest = out_buf; + gfloat inv_gamma[5]; + gint channel; + + if (! config) + return FALSE; + + for (channel = 0; channel < 5; channel++) + { + g_return_val_if_fail (config->gamma[channel] != 0.0, FALSE); + + inv_gamma[channel] = 1.0 / config->gamma[channel]; + } + + while (samples--) + { + for (channel = 0; channel < 4; channel++) + { + gdouble value; + + value = gimp_operation_levels_map (src[channel], + config->low_input[channel + 1], + config->high_input[channel + 1], + config->clamp_input, + inv_gamma[channel + 1], + config->low_output[channel + 1], + config->high_output[channel + 1], + config->clamp_output); + + /* don't apply the overall curve to the alpha channel */ + if (channel != ALPHA) + value = gimp_operation_levels_map (value, + config->low_input[0], + config->high_input[0], + config->clamp_input, + inv_gamma[0], + config->low_output[0], + config->high_output[0], + config->clamp_output); + + dest[channel] = value; + } + + src += 4; + dest += 4; + } + + return TRUE; +} + + +/* public functions */ + +gdouble +gimp_operation_levels_map_input (GimpLevelsConfig *config, + GimpHistogramChannel channel, + gdouble value) +{ + g_return_val_if_fail (GIMP_IS_LEVELS_CONFIG (config), 0.0); + + /* determine input intensity */ + if (config->high_input[channel] != config->low_input[channel]) + value = ((value - config->low_input[channel]) / + (config->high_input[channel] - config->low_input[channel])); + else + value = (value - config->low_input[channel]); + + if (config->gamma[channel] != 0.0 && value > 0.0) + value = pow (value, 1.0 / config->gamma[channel]); + + return value; +} diff --git a/app/operations/gimpoperationlevels.h b/app/operations/gimpoperationlevels.h new file mode 100644 index 0000000..d977f42 --- /dev/null +++ b/app/operations/gimpoperationlevels.h @@ -0,0 +1,57 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlevels.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_LEVELS_H__ +#define __GIMP_OPERATION_LEVELS_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_LEVELS (gimp_operation_levels_get_type ()) +#define GIMP_OPERATION_LEVELS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_LEVELS, GimpOperationLevels)) +#define GIMP_OPERATION_LEVELS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_LEVELS, GimpOperationLevelsClass)) +#define GIMP_IS_OPERATION_LEVELS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_LEVELS)) +#define GIMP_IS_OPERATION_LEVELS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_LEVELS)) +#define GIMP_OPERATION_LEVELS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_LEVELS, GimpOperationLevelsClass)) + + +typedef struct _GimpOperationLevels GimpOperationLevels; +typedef struct _GimpOperationLevelsClass GimpOperationLevelsClass; + +struct _GimpOperationLevels +{ + GimpOperationPointFilter parent_instance; +}; + +struct _GimpOperationLevelsClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_levels_get_type (void) G_GNUC_CONST; + +gdouble gimp_operation_levels_map_input (GimpLevelsConfig *config, + GimpHistogramChannel channel, + gdouble value); + + +#endif /* __GIMP_OPERATION_LEVELS_H__ */ diff --git a/app/operations/gimpoperationmaskcomponents.cc b/app/operations/gimpoperationmaskcomponents.cc new file mode 100644 index 0000000..779dfac --- /dev/null +++ b/app/operations/gimpoperationmaskcomponents.cc @@ -0,0 +1,586 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationmaskcomponents.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +extern "C" +{ + +#include "operations-types.h" + +#include "gimpoperationmaskcomponents.h" + +} /* extern "C" */ + + +enum +{ + PROP_0, + PROP_MASK, + PROP_ALPHA +}; + + +static void gimp_operation_mask_components_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_mask_components_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_mask_components_prepare (GeglOperation *operation); +static GeglRectangle gimp_operation_mask_components_get_bounding_box (GeglOperation *operation); +static gboolean gimp_operation_mask_components_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level); + +static gboolean gimp_operation_mask_components_process (GeglOperation *operation, + void *in_buf, + void *aux_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationMaskComponents, gimp_operation_mask_components, + GEGL_TYPE_OPERATION_POINT_COMPOSER) + +#define parent_class gimp_operation_mask_components_parent_class + + +static void +gimp_operation_mask_components_class_init (GimpOperationMaskComponentsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointComposerClass *point_class = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass); + + object_class->set_property = gimp_operation_mask_components_set_property; + object_class->get_property = gimp_operation_mask_components_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:mask-components", + "categories", "gimp", + "description", "Selectively pick components from src or aux", + NULL); + + operation_class->prepare = gimp_operation_mask_components_prepare; + operation_class->get_bounding_box = gimp_operation_mask_components_get_bounding_box; + operation_class->process = gimp_operation_mask_components_parent_process; + + point_class->process = gimp_operation_mask_components_process; + + g_object_class_install_property (object_class, PROP_MASK, + g_param_spec_flags ("mask", + "Mask", + "The component mask", + GIMP_TYPE_COMPONENT_MASK, + GIMP_COMPONENT_MASK_ALL, + (GParamFlags) ( + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT))); + + g_object_class_install_property (object_class, PROP_ALPHA, + g_param_spec_double ("alpha", + "Alpha", + "The masked-in alpha value when there's no aux input", + -G_MAXDOUBLE, + G_MAXDOUBLE, + 0.0, + (GParamFlags) ( + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT))); +} + +static void +gimp_operation_mask_components_init (GimpOperationMaskComponents *self) +{ +} + +static void +gimp_operation_mask_components_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationMaskComponents *self = GIMP_OPERATION_MASK_COMPONENTS (object); + + switch (property_id) + { + case PROP_MASK: + g_value_set_flags (value, self->mask); + break; + + case PROP_ALPHA: + g_value_set_double (value, self->alpha); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_mask_components_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationMaskComponents *self = GIMP_OPERATION_MASK_COMPONENTS (object); + + switch (property_id) + { + case PROP_MASK: + self->mask = (GimpComponentMask) g_value_get_flags (value); + break; + + case PROP_ALPHA: + self->alpha = g_value_get_double (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static guint32 +get_alpha_value (const Babl *format, + gfloat alpha) +{ + switch (babl_format_get_bytes_per_pixel (format)) + { + #define DEF_CASE(bpp, type) \ + case bpp: \ + { \ + type alpha_value; \ + \ + babl_process ( \ + babl_fish (babl_format_n (babl_type ("float"), 1), \ + babl_format_n (babl_format_get_type (format, 0), 1)), \ + &alpha, &alpha_value, 1); \ + \ + return alpha_value; \ + } + + DEF_CASE ( 4, guint8) + DEF_CASE ( 8, guint16) + DEF_CASE (16, guint32) + + #undef DEF_CASE + + default: + g_return_val_if_reached (0); + } +} + +template <class T> +struct ProcessGeneric +{ + static void + process (gconstpointer in_buf, + gconstpointer aux_buf, + gpointer out_buf, + gint n, + GimpComponentMask mask, + T alpha_value) + { + T *out = (T *) out_buf; + gint i; + gint c; + + if (aux_buf) + { + const T *in[4]; + + for (c = 0; c < 4; c++) + { + if (mask & (1 << c)) + in[c] = (const T *) aux_buf + c; + else + in[c] = (const T *) in_buf + c; + } + + for (i = 0; i < n; i++) + { + for (c = 0; c < 4; c++) + { + out[c] = *in[c]; + + in[c] += 4; + } + + out += 4; + } + } + else + { + const T *in = (const T*) in_buf; + + for (i = 0; i < n; i++) + { + for (c = 0; c < 3; c++) + { + if (mask & (1 << c)) + out[c] = 0; + else + out[c] = in[c]; + } + + if (mask & (1 << 3)) + out[3] = alpha_value; + else + out[3] = in[3]; + + in += 4; + out += 4; + } + } + } +}; + +template <class T> +struct Process : ProcessGeneric<T> +{ +}; + +#if G_BYTE_ORDER == G_LITTLE_ENDIAN + +template <> +struct Process<guint8> +{ + static void + process (gconstpointer in_buf, + gconstpointer aux_buf, + gpointer out_buf, + gint n, + GimpComponentMask mask, + guint8 alpha_value) + { + const guint32 *in; + guint32 *out; + guint32 in_mask = 0; + gint i; + gint c; + + if (((guintptr) in_buf | (guintptr) aux_buf | (guintptr) out_buf) % 4) + { + ProcessGeneric<guint8>::process (in_buf, aux_buf, out_buf, n, + mask, alpha_value); + + return; + } + + in = (const guint32 *) in_buf; + out = (guint32 *) out_buf; + + for (c = 0; c < 4; c++) + { + if (! (mask & (1 << c))) + in_mask |= 0xff << (8 * c); + } + + if (aux_buf) + { + const guint32 *aux = (const guint32 *) aux_buf; + guint32 aux_mask = ~in_mask; + + for (i = 0; i < n; i++) + { + *out = (*in & in_mask) | (*aux & aux_mask); + + in++; + aux++; + out++; + } + } + else + { + if (! (mask & GIMP_COMPONENT_MASK_ALPHA) || ! alpha_value) + { + for (i = 0; i < n; i++) + { + *out = *in & in_mask; + + in++; + out++; + } + } + else + { + guint32 alpha_mask = alpha_value << 24; + + for (i = 0; i < n; i++) + { + *out = (*in & in_mask) | alpha_mask; + + in++; + out++; + } + } + } + } +}; + +#endif /* G_BYTE_ORDER == G_LITTLE_ENDIAN */ + +template <class T> +static gboolean +gimp_operation_mask_components_process (GimpOperationMaskComponents *self, + void *in_buf, + void *aux_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + Process<T>::process (in_buf, aux_buf, out_buf, samples, + self->mask, self->alpha_value); + + return TRUE; +} + +static void +gimp_operation_mask_components_prepare (GeglOperation *operation) +{ + GimpOperationMaskComponents *self = GIMP_OPERATION_MASK_COMPONENTS (operation); + const Babl *format; + + format = gimp_operation_mask_components_get_format ( + gegl_operation_get_source_format (operation, "input")); + + gegl_operation_set_format (operation, "input", format); + gegl_operation_set_format (operation, "aux", format); + gegl_operation_set_format (operation, "output", format); + + if (format != self->format) + { + self->format = format; + + self->alpha_value = get_alpha_value (format, self->alpha); + + switch (babl_format_get_bytes_per_pixel (format)) + { + case 4: + self->process = (gpointer) + gimp_operation_mask_components_process<guint8>; + break; + + case 8: + self->process = (gpointer) + gimp_operation_mask_components_process<guint16>; + break; + + case 16: + self->process = (gpointer) + gimp_operation_mask_components_process<guint32>; + break; + + default: + g_return_if_reached (); + } + } +} + +static GeglRectangle +gimp_operation_mask_components_get_bounding_box (GeglOperation *operation) +{ + GimpOperationMaskComponents *self = GIMP_OPERATION_MASK_COMPONENTS (operation); + GeglRectangle *in_rect; + GeglRectangle *aux_rect; + GeglRectangle result = {}; + + in_rect = gegl_operation_source_get_bounding_box (operation, "input"); + aux_rect = gegl_operation_source_get_bounding_box (operation, "aux"); + + if (self->mask == 0) + { + if (in_rect) + return *in_rect; + } + else if (self->mask == GIMP_COMPONENT_MASK_ALL) + { + if (aux_rect) + return *aux_rect; + } + + if (in_rect) + gegl_rectangle_bounding_box (&result, &result, in_rect); + + if (aux_rect) + gegl_rectangle_bounding_box (&result, &result, aux_rect); + + return result; +} + +static gboolean +gimp_operation_mask_components_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level) +{ + GimpOperationMaskComponents *self = GIMP_OPERATION_MASK_COMPONENTS (operation); + + if (self->mask == 0) + { + GObject *input = gegl_operation_context_get_object (context, "input"); + + gegl_operation_context_set_object (context, "output", input); + + return TRUE; + } + else if (self->mask == GIMP_COMPONENT_MASK_ALL) + { + GObject *aux = gegl_operation_context_get_object (context, "aux"); + + /* when there's no aux and the alpha component is masked-in, we set the + * result's alpha component to the value of the "alpha" property; if it + * doesn't equal 0, we can't forward an empty aux. + */ + if (aux || ! self->alpha_value) + { + gegl_operation_context_set_object (context, "output", aux); + + return TRUE; + } + } + + return GEGL_OPERATION_CLASS (parent_class)->process (operation, context, + output_prop, result, + level); +} + +static gboolean +gimp_operation_mask_components_process (GeglOperation *operation, + void *in_buf, + void *aux_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + typedef gboolean (* ProcessFunc) (GimpOperationMaskComponents *self, + void *in_buf, + void *aux_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + GimpOperationMaskComponents *self = (GimpOperationMaskComponents *) operation; + + return ((ProcessFunc) self->process) (self, + in_buf, aux_buf, out_buf, samples, + roi, level); +} + +const Babl * +gimp_operation_mask_components_get_format (const Babl *input_format) +{ + const Babl *format = NULL; + + if (input_format) + { + const Babl *model = babl_format_get_model (input_format); + const gchar *model_name = babl_get_name (model); + const Babl *type = babl_format_get_type (input_format, 0); + const gchar *type_name = babl_get_name (type); + + if (! strcmp (model_name, "Y") || + ! strcmp (model_name, "YA") || + ! strcmp (model_name, "RGB") || + ! strcmp (model_name, "RGBA")) + { + if (! strcmp (type_name, "u8")) + format = babl_format ("RGBA u8"); + else if (! strcmp (type_name, "u16")) + format = babl_format ("RGBA u16"); + else if (! strcmp (type_name, "u32")) + format = babl_format ("RGBA u32"); + else if (! strcmp (type_name, "half")) + format = babl_format ("RGBA half"); + else if (! strcmp (type_name, "float")) + format = babl_format ("RGBA float"); + } + else if (! strcmp (model_name, "Y'") || + ! strcmp (model_name, "Y'A") || + ! strcmp (model_name, "R'G'B'") || + ! strcmp (model_name, "R'G'B'A") || + babl_format_is_palette (input_format)) + { + if (! strcmp (type_name, "u8")) + format = babl_format ("R'G'B'A u8"); + else if (! strcmp (type_name, "u16")) + format = babl_format ("R'G'B'A u16"); + else if (! strcmp (type_name, "u32")) + format = babl_format ("R'G'B'A u32"); + else if (! strcmp (type_name, "half")) + format = babl_format ("R'G'B'A half"); + else if (! strcmp (type_name, "float")) + format = babl_format ("R'G'B'A float"); + } + } + + if (! format) + format = babl_format ("RGBA float"); + + return format; +} + +void +gimp_operation_mask_components_process (const Babl *format, + gconstpointer in, + gconstpointer aux, + gpointer out, + gint n, + GimpComponentMask mask) +{ + g_return_if_fail (format != NULL); + g_return_if_fail (in != NULL); + g_return_if_fail (out != NULL); + g_return_if_fail (n >= 0); + + switch (babl_format_get_bytes_per_pixel (format)) + { + case 4: + Process<guint8>::process (in, aux, out, n, mask, 0); + break; + + case 8: + Process<guint16>::process (in, aux, out, n, mask, 0); + break; + + case 16: + Process<guint32>::process (in, aux, out, n, mask, 0); + break; + + default: + g_return_if_reached (); + } +} diff --git a/app/operations/gimpoperationmaskcomponents.h b/app/operations/gimpoperationmaskcomponents.h new file mode 100644 index 0000000..0919a38 --- /dev/null +++ b/app/operations/gimpoperationmaskcomponents.h @@ -0,0 +1,68 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationmaskcomponents.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_MASK_COMPONENTS_H__ +#define __GIMP_OPERATION_MASK_COMPONENTS_H__ + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_MASK_COMPONENTS (gimp_operation_mask_components_get_type ()) +#define GIMP_OPERATION_MASK_COMPONENTS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_MASK_COMPONENTS, GimpOperationMaskComponents)) +#define GIMP_OPERATION_MASK_COMPONENTS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_MASK_COMPONENTS, GimpOperationMaskComponentsClass)) +#define GIMP_IS_OPERATION_MASK_COMPONENTS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_MASK_COMPONENTS)) +#define GIMP_IS_OPERATION_MASK_COMPONENTS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_MASK_COMPONENTS)) +#define GIMP_OPERATION_MASK_COMPONENTS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_MASK_COMPONENTS, GimpOperationMaskComponentsClass)) + + +typedef struct _GimpOperationMaskComponents GimpOperationMaskComponents; +typedef struct _GimpOperationMaskComponentsClass GimpOperationMaskComponentsClass; + +struct _GimpOperationMaskComponents +{ + GeglOperationPointComposer parent_instance; + + GimpComponentMask mask; + gdouble alpha; + + guint32 alpha_value; + gpointer process; + const Babl *format; +}; + +struct _GimpOperationMaskComponentsClass +{ + GeglOperationPointComposerClass parent_class; +}; + + +GType gimp_operation_mask_components_get_type (void) G_GNUC_CONST; + +const Babl * gimp_operation_mask_components_get_format (const Babl *input_format); + +void gimp_operation_mask_components_process (const Babl *format, + gconstpointer in, + gconstpointer aux, + gpointer out, + gint n, + GimpComponentMask mask); + + +#endif /* __GIMP_OPERATION_MASK_COMPONENTS_H__ */ diff --git a/app/operations/gimpoperationoffset.c b/app/operations/gimpoperationoffset.c new file mode 100644 index 0000000..ee269ed --- /dev/null +++ b/app/operations/gimpoperationoffset.c @@ -0,0 +1,497 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationoffset.c + * Copyright (C) 2019 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl-plugin.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "operations-types.h" + +#include "gegl/gimp-gegl-loops.h" +#include "gegl/gimp-gegl-utils.h" + +#include "core/gimpcontext.h" + +#include "gimpoperationoffset.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_CONTEXT, + PROP_TYPE, + PROP_X, + PROP_Y +}; + + +static void gimp_operation_offset_dispose (GObject *object); +static void gimp_operation_offset_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_offset_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static GeglRectangle gimp_operation_offset_get_required_for_output (GeglOperation *operation, + const gchar *input_pad, + const GeglRectangle *output_roi); +static GeglRectangle gimp_operation_offset_get_invalidated_by_change (GeglOperation *operation, + const gchar *input_pad, + const GeglRectangle *input_roi); +static void gimp_operation_offset_prepare (GeglOperation *operation); +static gboolean gimp_operation_offset_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_pad, + const GeglRectangle *result, + gint level); + +static gboolean gimp_operation_offset_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level); + +static void gimp_operation_offset_get_offset (GimpOperationOffset *offset, + gboolean invert, + gint *x, + gint *y); +static void gimp_operation_offset_get_rect (GimpOperationOffset *offset, + gboolean invert, + const GeglRectangle *roi, + GeglRectangle *rect); + + +G_DEFINE_TYPE (GimpOperationOffset, gimp_operation_offset, + GEGL_TYPE_OPERATION_FILTER) + +#define parent_class gimp_operation_offset_parent_class + + +static void +gimp_operation_offset_class_init (GimpOperationOffsetClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass); + + object_class->dispose = gimp_operation_offset_dispose; + object_class->set_property = gimp_operation_offset_set_property; + object_class->get_property = gimp_operation_offset_get_property; + + operation_class->get_required_for_output = gimp_operation_offset_get_required_for_output; + operation_class->get_invalidated_by_change = gimp_operation_offset_get_invalidated_by_change; + operation_class->prepare = gimp_operation_offset_prepare; + operation_class->process = gimp_operation_offset_parent_process; + + operation_class->threaded = FALSE; + operation_class->cache_policy = GEGL_CACHE_POLICY_NEVER; + + filter_class->process = gimp_operation_offset_process; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:offset", + "categories", "transform", + "description", _("Shift the pixels, optionally wrapping them at the borders"), + NULL); + + g_object_class_install_property (object_class, PROP_CONTEXT, + g_param_spec_object ("context", + "Context", + "A GimpContext", + GIMP_TYPE_CONTEXT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_TYPE, + g_param_spec_enum ("type", + "Type", + "Offset type", + GIMP_TYPE_OFFSET_TYPE, + GIMP_OFFSET_WRAP_AROUND, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_X, + g_param_spec_int ("x", + "X Offset", + "X offset", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_Y, + g_param_spec_int ("y", + "Y Offset", + "Y offset", + G_MININT, G_MAXINT, 0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_offset_init (GimpOperationOffset *self) +{ +} + +static void +gimp_operation_offset_dispose (GObject *object) +{ + GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (object); + + g_clear_object (&offset->context); + + G_OBJECT_CLASS (parent_class)->dispose (object); +} + +static void +gimp_operation_offset_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (object); + + switch (property_id) + { + case PROP_CONTEXT: + g_value_set_object (value, offset->context); + break; + + case PROP_TYPE: + g_value_set_enum (value, offset->type); + break; + + case PROP_X: + g_value_set_int (value, offset->x); + break; + + case PROP_Y: + g_value_set_int (value, offset->y); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_offset_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (object); + + switch (property_id) + { + case PROP_CONTEXT: + g_set_object (&offset->context, g_value_get_object (value)); + break; + + case PROP_TYPE: + offset->type = g_value_get_enum (value); + break; + + case PROP_X: + offset->x = g_value_get_int (value); + break; + + case PROP_Y: + offset->y = g_value_get_int (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static GeglRectangle +gimp_operation_offset_get_required_for_output (GeglOperation *operation, + const gchar *input_pad, + const GeglRectangle *output_roi) +{ + GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (operation); + GeglRectangle rect; + + gimp_operation_offset_get_rect (offset, TRUE, output_roi, &rect); + + return rect; +} + +static GeglRectangle +gimp_operation_offset_get_invalidated_by_change (GeglOperation *operation, + const gchar *input_pad, + const GeglRectangle *input_roi) +{ + GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (operation); + GeglRectangle rect; + + gimp_operation_offset_get_rect (offset, FALSE, input_roi, &rect); + + return rect; +} + +static void +gimp_operation_offset_prepare (GeglOperation *operation) +{ + const Babl *format; + + format = gegl_operation_get_source_format (operation, "input"); + + if (! format) + format = babl_format ("RGBA float"); + + gegl_operation_set_format (operation, "input", format); + gegl_operation_set_format (operation, "output", format); +} + +static gboolean +gimp_operation_offset_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_pad, + const GeglRectangle *result, + gint level) +{ + GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (operation); + GObject *input; + gint x; + gint y; + + input = gegl_operation_context_get_object (context, "input"); + + gimp_operation_offset_get_offset (offset, FALSE, &x, &y); + + if (x == 0 && y == 0) + { + gegl_operation_context_set_object (context, "output", input); + + return TRUE; + } + else if (offset->type == GIMP_OFFSET_TRANSPARENT || + (offset->type == GIMP_OFFSET_BACKGROUND && + ! offset->context)) + { + GObject *output = NULL; + + if (input) + { + GeglRectangle bounds; + GeglRectangle extent; + + bounds = gegl_operation_get_bounding_box (GEGL_OPERATION (offset)); + + extent = *gegl_buffer_get_extent (GEGL_BUFFER (input)); + + extent.x += x; + extent.y += y; + + if (gegl_rectangle_intersect (&extent, &extent, &bounds)) + { + output = g_object_new (GEGL_TYPE_BUFFER, + "source", input, + "x", extent.x, + "y", extent.y, + "width", extent.width, + "height", extent.height, + "shift-x", -x, + "shift-y", -y, + NULL); + + if (gegl_object_get_has_forked (input)) + gegl_object_set_has_forked (output); + } + } + + gegl_operation_context_take_object (context, "output", output); + + return TRUE; + } + + return GEGL_OPERATION_CLASS (parent_class)->process (operation, context, + output_pad, result, + level); +} + +static gboolean +gimp_operation_offset_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level) +{ + GimpOperationOffset *offset = GIMP_OPERATION_OFFSET (operation); + GeglColor *color = NULL; + GeglRectangle bounds; + gint x; + gint y; + gint i; + + bounds = gegl_operation_get_bounding_box (GEGL_OPERATION (offset)); + + gimp_operation_offset_get_offset (offset, FALSE, &x, &y); + + if (offset->type == GIMP_OFFSET_BACKGROUND && offset->context) + { + GimpRGB bg; + + gimp_context_get_background (offset->context, &bg); + + color = gimp_gegl_color_new (&bg); + } + + for (i = 0; i < 4; i++) + { + GeglRectangle offset_bounds = bounds; + gint offset_x = x; + gint offset_y = y; + + if (i & 1) + offset_x += x < 0 ? bounds.width : -bounds.width; + if (i & 2) + offset_y += y < 0 ? bounds.height : -bounds.height; + + offset_bounds.x += offset_x; + offset_bounds.y += offset_y; + + if (gegl_rectangle_intersect (&offset_bounds, &offset_bounds, roi)) + { + if (i == 0 || offset->type == GIMP_OFFSET_WRAP_AROUND) + { + GeglRectangle offset_roi = offset_bounds; + + offset_roi.x -= offset_x; + offset_roi.y -= offset_y; + + gimp_gegl_buffer_copy (input, &offset_roi, GEGL_ABYSS_NONE, + output, &offset_bounds); + } + else if (color) + { + gegl_buffer_set_color (output, &offset_bounds, color); + } + } + } + + g_clear_object (&color); + + return TRUE; +} + +static void +gimp_operation_offset_get_offset (GimpOperationOffset *offset, + gboolean invert, + gint *x, + gint *y) +{ + GeglRectangle bounds; + + bounds = gegl_operation_get_bounding_box (GEGL_OPERATION (offset)); + + if (gegl_rectangle_is_empty (&bounds)) + { + *x = 0; + *y = 0; + + return; + } + + *x = offset->x; + *y = offset->y; + + if (invert) + { + *x = -*x; + *y = -*y; + } + + if (offset->type == GIMP_OFFSET_WRAP_AROUND) + { + *x %= bounds.width; + + if (*x < 0) + *x += bounds.width; + + *y %= bounds.height; + + if (*y < 0) + *y += bounds.height; + } + else + { + *x = CLAMP (*x, -bounds.width, +bounds.width); + *y = CLAMP (*y, -bounds.height, +bounds.height); + } +} + +static void +gimp_operation_offset_get_rect (GimpOperationOffset *offset, + gboolean invert, + const GeglRectangle *roi, + GeglRectangle *rect) +{ + GeglRectangle bounds; + gint x; + gint y; + + bounds = gegl_operation_get_bounding_box (GEGL_OPERATION (offset)); + + if (gegl_rectangle_is_empty (&bounds)) + { + rect->x = 0; + rect->y = 0; + rect->width = 0; + rect->height = 0; + + return; + } + + gimp_operation_offset_get_offset (offset, invert, &x, &y); + + *rect = *roi; + + rect->x += x; + rect->y += y; + + if (offset->type == GIMP_OFFSET_WRAP_AROUND) + { + if (rect->x + rect->width > bounds.x + bounds.width) + { + rect->x = bounds.x; + rect->width = bounds.width; + } + + if (rect->y + rect->height > bounds.y + bounds.height) + { + rect->y = bounds.y; + rect->height = bounds.height; + } + } + + gegl_rectangle_intersect (rect, rect, &bounds); +} diff --git a/app/operations/gimpoperationoffset.h b/app/operations/gimpoperationoffset.h new file mode 100644 index 0000000..dcd0e0b --- /dev/null +++ b/app/operations/gimpoperationoffset.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationoffset.h + * Copyright (C) 2019 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_OFFSET_H__ +#define __GIMP_OPERATION_OFFSET_H__ + + +#define GIMP_TYPE_OPERATION_OFFSET (gimp_operation_offset_get_type ()) +#define GIMP_OPERATION_OFFSET(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_OFFSET, GimpOperationOffset)) +#define GIMP_OPERATION_OFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_OFFSET, GimpOperationOffsetClass)) +#define GIMP_IS_OPERATION_OFFSET(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_OFFSET)) +#define GIMP_IS_OPERATION_OFFSET_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_OFFSET)) +#define GIMP_OPERATION_OFFSET_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_OFFSET, GimpOperationOffsetClass)) + + +typedef struct _GimpOperationOffset GimpOperationOffset; +typedef struct _GimpOperationOffsetClass GimpOperationOffsetClass; + +struct _GimpOperationOffset +{ + GeglOperationFilter parent_instance; + + GimpContext *context; + GimpOffsetType type; + gint x; + gint y; +}; + +struct _GimpOperationOffsetClass +{ + GeglOperationFilterClass parent_class; +}; + + +GType gimp_operation_offset_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_OFFSET_H__ */ diff --git a/app/operations/gimpoperationpointfilter.c b/app/operations/gimpoperationpointfilter.c new file mode 100644 index 0000000..b9bfa1d --- /dev/null +++ b/app/operations/gimpoperationpointfilter.c @@ -0,0 +1,131 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationpointfilter.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "operations-types.h" + +#include "gimpoperationpointfilter.h" + + +static void gimp_operation_point_filter_finalize (GObject *object); +static void gimp_operation_point_filter_prepare (GeglOperation *operation); + + +G_DEFINE_ABSTRACT_TYPE (GimpOperationPointFilter, gimp_operation_point_filter, + GEGL_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_point_filter_parent_class + + +static void +gimp_operation_point_filter_class_init (GimpOperationPointFilterClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + + object_class->finalize = gimp_operation_point_filter_finalize; + + operation_class->prepare = gimp_operation_point_filter_prepare; +} + +static void +gimp_operation_point_filter_init (GimpOperationPointFilter *self) +{ +} + +static void +gimp_operation_point_filter_finalize (GObject *object) +{ + GimpOperationPointFilter *self = GIMP_OPERATION_POINT_FILTER (object); + + g_clear_object (&self->config); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +void +gimp_operation_point_filter_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationPointFilter *self = GIMP_OPERATION_POINT_FILTER (object); + + switch (property_id) + { + case GIMP_OPERATION_POINT_FILTER_PROP_LINEAR: + g_value_set_boolean (value, self->linear); + break; + + case GIMP_OPERATION_POINT_FILTER_PROP_CONFIG: + g_value_set_object (value, self->config); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +void +gimp_operation_point_filter_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationPointFilter *self = GIMP_OPERATION_POINT_FILTER (object); + + switch (property_id) + { + case GIMP_OPERATION_POINT_FILTER_PROP_LINEAR: + self->linear = g_value_get_boolean (value); + break; + + case GIMP_OPERATION_POINT_FILTER_PROP_CONFIG: + if (self->config) + g_object_unref (self->config); + self->config = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_point_filter_prepare (GeglOperation *operation) +{ + GimpOperationPointFilter *self = GIMP_OPERATION_POINT_FILTER (operation); + const Babl *space = gegl_operation_get_source_space (operation, + "input"); + const Babl *format; + + if (self->linear) + format = babl_format_with_space ("RGBA float", space); + else + format = babl_format_with_space ("R'G'B'A float", space); + + gegl_operation_set_format (operation, "input", format); + gegl_operation_set_format (operation, "output", format); +} diff --git a/app/operations/gimpoperationpointfilter.h b/app/operations/gimpoperationpointfilter.h new file mode 100644 index 0000000..f039af7 --- /dev/null +++ b/app/operations/gimpoperationpointfilter.h @@ -0,0 +1,73 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationpointfilter.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_POINT_FILTER_H__ +#define __GIMP_OPERATION_POINT_FILTER_H__ + + +#include <gegl-plugin.h> +#include <operation/gegl-operation-point-filter.h> + + +enum +{ + GIMP_OPERATION_POINT_FILTER_PROP_0, + GIMP_OPERATION_POINT_FILTER_PROP_LINEAR, + GIMP_OPERATION_POINT_FILTER_PROP_CONFIG +}; + + +#define GIMP_TYPE_OPERATION_POINT_FILTER (gimp_operation_point_filter_get_type ()) +#define GIMP_OPERATION_POINT_FILTER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_POINT_FILTER, GimpOperationPointFilter)) +#define GIMP_OPERATION_POINT_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_POINT_FILTER, GimpOperationPointFilterClass)) +#define GIMP_IS_OPERATION_POINT_FILTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_POINT_FILTER)) +#define GIMP_IS_OPERATION_POINT_FILTER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_POINT_FILTER)) +#define GIMP_OPERATION_POINT_FILTER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_POINT_FILTER, GimpOperationPointFilterClass)) + + +typedef struct _GimpOperationPointFilterClass GimpOperationPointFilterClass; + +struct _GimpOperationPointFilter +{ + GeglOperationPointFilter parent_instance; + + gboolean linear; + GObject *config; +}; + +struct _GimpOperationPointFilterClass +{ + GeglOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_point_filter_get_type (void) G_GNUC_CONST; + +void gimp_operation_point_filter_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +void gimp_operation_point_filter_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + + +#endif /* __GIMP_OPERATION_POINT_FILTER_H__ */ diff --git a/app/operations/gimpoperationposterize.c b/app/operations/gimpoperationposterize.c new file mode 100644 index 0000000..88f5d26 --- /dev/null +++ b/app/operations/gimpoperationposterize.c @@ -0,0 +1,165 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationposterize.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpconfig/gimpconfig.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimpoperationposterize.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_LEVELS +}; + + +static void gimp_operation_posterize_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_posterize_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gboolean gimp_operation_posterize_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationPosterize, gimp_operation_posterize, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_posterize_parent_class + + +static void +gimp_operation_posterize_class_init (GimpOperationPosterizeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_posterize_set_property; + object_class->get_property = gimp_operation_posterize_get_property; + + point_class->process = gimp_operation_posterize_process; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:posterize", + "categories", "color", + "description", _("Reduce to a limited set of colors"), + NULL); + + GIMP_CONFIG_PROP_INT (object_class, PROP_LEVELS, + "levels", + _("Posterize levels"), + NULL, + 2, 256, 3, + GIMP_PARAM_STATIC_STRINGS); +} + +static void +gimp_operation_posterize_init (GimpOperationPosterize *self) +{ +} + +static void +gimp_operation_posterize_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationPosterize *posterize = GIMP_OPERATION_POSTERIZE (object); + + switch (property_id) + { + case PROP_LEVELS: + g_value_set_int (value, posterize->levels); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_posterize_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationPosterize *posterize = GIMP_OPERATION_POSTERIZE (object); + + switch (property_id) + { + case PROP_LEVELS: + posterize->levels = g_value_get_int (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gboolean +gimp_operation_posterize_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationPosterize *posterize = GIMP_OPERATION_POSTERIZE (operation); + gfloat *src = in_buf; + gfloat *dest = out_buf; + gfloat levels; + + levels = posterize->levels - 1.0; + + while (samples--) + { + dest[RED] = RINT (src[RED] * levels) / levels; + dest[GREEN] = RINT (src[GREEN] * levels) / levels; + dest[BLUE] = RINT (src[BLUE] * levels) / levels; + dest[ALPHA] = RINT (src[ALPHA] * levels) / levels; + + src += 4; + dest += 4; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationposterize.h b/app/operations/gimpoperationposterize.h new file mode 100644 index 0000000..06e5731 --- /dev/null +++ b/app/operations/gimpoperationposterize.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationposterize.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_POSTERIZE_H__ +#define __GIMP_OPERATION_POSTERIZE_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_POSTERIZE (gimp_operation_posterize_get_type ()) +#define GIMP_OPERATION_POSTERIZE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_POSTERIZE, GimpOperationPosterize)) +#define GIMP_OPERATION_POSTERIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_POSTERIZE, GimpOperationPosterizeClass)) +#define GIMP_IS_OPERATION_POSTERIZE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_POSTERIZE)) +#define GIMP_IS_OPERATION_POSTERIZE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_POSTERIZE)) +#define GIMP_OPERATION_POSTERIZE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_POSTERIZE, GimpOperationPosterizeClass)) + + +typedef struct _GimpOperationPosterize GimpOperationPosterize; +typedef struct _GimpOperationPosterizeClass GimpOperationPosterizeClass; + +struct _GimpOperationPosterize +{ + GimpOperationPointFilter parent_instance; + + gint levels; +}; + +struct _GimpOperationPosterizeClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_posterize_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_POSTERIZE_H__ */ diff --git a/app/operations/gimpoperationprofiletransform.c b/app/operations/gimpoperationprofiletransform.c new file mode 100644 index 0000000..2e42459 --- /dev/null +++ b/app/operations/gimpoperationprofiletransform.c @@ -0,0 +1,307 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationprofiletransform.c + * Copyright (C) 2016 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpconfig/gimpconfig.h" +#include "libgimpcolor/gimpcolor.h" + +#include "operations-types.h" + +#include "gimpoperationprofiletransform.h" + + +enum +{ + PROP_0, + PROP_SRC_PROFILE, + PROP_SRC_FORMAT, + PROP_DEST_PROFILE, + PROP_DEST_FORMAT, + PROP_RENDERING_INTENT, + PROP_BLACK_POINT_COMPENSATION +}; + + +static void gimp_operation_profile_transform_finalize (GObject *object); + +static void gimp_operation_profile_transform_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_profile_transform_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_profile_transform_prepare (GeglOperation *operation); +static gboolean gimp_operation_profile_transform_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationProfileTransform, gimp_operation_profile_transform, + GEGL_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_profile_transform_parent_class + + +static void +gimp_operation_profile_transform_class_init (GimpOperationProfileTransformClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->finalize = gimp_operation_profile_transform_finalize; + object_class->set_property = gimp_operation_profile_transform_set_property; + object_class->get_property = gimp_operation_profile_transform_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:profile-transform", + "categories", "color", + "description", + "Transform between two color profiles", + NULL); + + operation_class->prepare = gimp_operation_profile_transform_prepare; + + point_class->process = gimp_operation_profile_transform_process; + + g_object_class_install_property (object_class, PROP_SRC_PROFILE, + g_param_spec_object ("src-profile", + "Source Profile", + "Source Profile", + GIMP_TYPE_COLOR_PROFILE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_SRC_FORMAT, + g_param_spec_pointer ("src-format", + "Source Format", + "Source Format", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_DEST_PROFILE, + g_param_spec_object ("dest-profile", + "Destination Profile", + "Destination Profile", + GIMP_TYPE_COLOR_PROFILE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_DEST_FORMAT, + g_param_spec_pointer ("dest-format", + "Destination Format", + "Destination Format", + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_RENDERING_INTENT, + g_param_spec_enum ("rendering-intent", + "Rendering Intent", + "Rendering Intent", + GIMP_TYPE_COLOR_RENDERING_INTENT, + GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_BLACK_POINT_COMPENSATION, + g_param_spec_boolean ("black-point-compensation", + "Black Point Compensation", + "Black Point Compensation", + TRUE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_profile_transform_init (GimpOperationProfileTransform *self) +{ +} + +static void +gimp_operation_profile_transform_finalize (GObject *object) +{ + GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (object); + + g_clear_object (&self->src_profile); + g_clear_object (&self->dest_profile); + g_clear_object (&self->transform); + + G_OBJECT_CLASS (parent_class)->finalize (object); +} + +static void +gimp_operation_profile_transform_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (object); + + switch (property_id) + { + case PROP_SRC_PROFILE: + g_value_set_object (value, self->src_profile); + break; + + case PROP_SRC_FORMAT: + g_value_set_pointer (value, (gpointer) self->src_format); + break; + + case PROP_DEST_PROFILE: + g_value_set_object (value, self->dest_profile); + break; + + case PROP_DEST_FORMAT: + g_value_set_pointer (value, (gpointer) self->dest_format); + break; + + case PROP_RENDERING_INTENT: + g_value_set_enum (value, self->rendering_intent); + break; + + case PROP_BLACK_POINT_COMPENSATION: + g_value_set_boolean (value, self->black_point_compensation); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_profile_transform_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (object); + + switch (property_id) + { + case PROP_SRC_PROFILE: + if (self->src_profile) + g_object_unref (self->src_profile); + self->src_profile = g_value_dup_object (value); + break; + + case PROP_SRC_FORMAT: + self->src_format = g_value_get_pointer (value); + break; + + case PROP_DEST_PROFILE: + if (self->dest_profile) + g_object_unref (self->dest_profile); + self->dest_profile = g_value_dup_object (value); + break; + + case PROP_DEST_FORMAT: + self->dest_format = g_value_get_pointer (value); + break; + + case PROP_RENDERING_INTENT: + self->rendering_intent = g_value_get_enum (value); + break; + + case PROP_BLACK_POINT_COMPENSATION: + self->black_point_compensation = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_profile_transform_prepare (GeglOperation *operation) +{ + GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (operation); + + g_clear_object (&self->transform); + + if (! self->src_format) + self->src_format = babl_format ("RGBA float"); + + if (! self->dest_format) + self->dest_format = babl_format ("RGBA float"); + + if (self->src_profile && self->dest_profile) + { + GimpColorTransformFlags flags = 0; + + if (self->black_point_compensation) + flags |= GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION; + + flags |= GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE; + + self->transform = gimp_color_transform_new (self->src_profile, + self->src_format, + self->dest_profile, + self->dest_format, + self->rendering_intent, + flags); + } + + gegl_operation_set_format (operation, "input", self->src_format); + gegl_operation_set_format (operation, "output", self->dest_format); +} + +static gboolean +gimp_operation_profile_transform_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (operation); + gpointer *src = in_buf; + gpointer *dest = out_buf; + + if (self->transform) + { + gimp_color_transform_process_pixels (self->transform, + self->src_format, + src, + self->dest_format, + dest, + samples); + } + else + { + babl_process (babl_fish (self->src_format, + self->dest_format), + src, dest, samples); + } + + return TRUE; +} diff --git a/app/operations/gimpoperationprofiletransform.h b/app/operations/gimpoperationprofiletransform.h new file mode 100644 index 0000000..52aaf4a --- /dev/null +++ b/app/operations/gimpoperationprofiletransform.h @@ -0,0 +1,65 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationprofiletransform.h + * Copyright (C) 2016 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_PROFILE_TRANSFORM_H__ +#define __GIMP_OPERATION_PROFILE_TRANSFORM_H__ + + +#include <gegl-plugin.h> +#include <operation/gegl-operation-point-filter.h> + + +#define GIMP_TYPE_OPERATION_PROFILE_TRANSFORM (gimp_operation_profile_transform_get_type ()) +#define GIMP_OPERATION_PROFILE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_PROFILE_TRANSFORM, GimpOperationProfileTransform)) +#define GIMP_OPERATION_PROFILE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_PROFILE_TRANSFORM, GimpOperationProfileTransformClass)) +#define GIMP_IS_OPERATION_PROFILE_TRANSFORM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_PROFILE_TRANSFORM)) +#define GIMP_IS_OPERATION_PROFILE_TRANSFORM_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_PROFILE_TRANSFORM)) +#define GIMP_OPERATION_PROFILE_TRANSFORM_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_PROFILE_TRANSFORM, GimpOperationProfileTransformClass)) + + +typedef struct _GimpOperationProfileTransform GimpOperationProfileTransform; +typedef struct _GimpOperationProfileTransformClass GimpOperationProfileTransformClass; + +struct _GimpOperationProfileTransform +{ + GeglOperationPointFilter parent_instance; + + GimpColorProfile *src_profile; + const Babl *src_format; + + GimpColorProfile *dest_profile; + const Babl *dest_format; + + GimpColorRenderingIntent rendering_intent; + gboolean black_point_compensation; + + GimpColorTransform *transform; +}; + +struct _GimpOperationProfileTransformClass +{ + GeglOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_profile_transform_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_PROFILE_TRANSFORM_H__ */ diff --git a/app/operations/gimpoperationscalarmultiply.c b/app/operations/gimpoperationscalarmultiply.c new file mode 100644 index 0000000..6416300 --- /dev/null +++ b/app/operations/gimpoperationscalarmultiply.c @@ -0,0 +1,189 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationscalarmultiply.c + * Copyright (C) 2014 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "operations-types.h" + +#include "gimpoperationscalarmultiply.h" + + +enum +{ + PROP_0, + PROP_N_COMPONENTS, + PROP_FACTOR +}; + + +static void gimp_operation_scalar_multiply_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_scalar_multiply_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_scalar_multiply_prepare (GeglOperation *operation); +static gboolean gimp_operation_scalar_multiply_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationScalarMultiply, gimp_operation_scalar_multiply, + GEGL_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_scalar_multiply_parent_class + + +static void +gimp_operation_scalar_multiply_class_init (GimpOperationScalarMultiplyClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_scalar_multiply_set_property; + object_class->get_property = gimp_operation_scalar_multiply_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:scalar-multiply", + "categories", "gimp", + "description", "Multiply all floats in a buffer by a factor", + NULL); + + operation_class->prepare = gimp_operation_scalar_multiply_prepare; + + point_class->process = gimp_operation_scalar_multiply_process; + + g_object_class_install_property (object_class, PROP_N_COMPONENTS, + g_param_spec_int ("n-components", + "N Components", + "Number of components in the input/output vectors", + 1, 16, 2, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_FACTOR, + g_param_spec_double ("factor", + "Factor", + "The scalar factor", + G_MINFLOAT, G_MAXFLOAT, + 1.0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_scalar_multiply_init (GimpOperationScalarMultiply *self) +{ +} + +static void +gimp_operation_scalar_multiply_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationScalarMultiply *self = GIMP_OPERATION_SCALAR_MULTIPLY (object); + + switch (property_id) + { + case PROP_N_COMPONENTS: + g_value_set_int (value, self->n_components); + break; + + case PROP_FACTOR: + g_value_set_double (value, self->factor); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_scalar_multiply_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationScalarMultiply *self = GIMP_OPERATION_SCALAR_MULTIPLY (object); + + switch (property_id) + { + case PROP_N_COMPONENTS: + self->n_components = g_value_get_int (value); + break; + + case PROP_FACTOR: + self->factor = g_value_get_double (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_scalar_multiply_prepare (GeglOperation *operation) +{ + GimpOperationScalarMultiply *self = GIMP_OPERATION_SCALAR_MULTIPLY (operation); + const Babl *format; + + format = babl_format_n (babl_type ("float"), self->n_components); + + gegl_operation_set_format (operation, "input", format); + gegl_operation_set_format (operation, "output", format); +} + +static gboolean +gimp_operation_scalar_multiply_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationScalarMultiply *self = GIMP_OPERATION_SCALAR_MULTIPLY (operation); + gfloat *src = in_buf; + gfloat *dest = out_buf; + glong n_samples; + + n_samples = samples * self->n_components; + + while (n_samples--) + { + *dest = *src * self->factor; + + src++; + dest++; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationscalarmultiply.h b/app/operations/gimpoperationscalarmultiply.h new file mode 100644 index 0000000..61122b7 --- /dev/null +++ b/app/operations/gimpoperationscalarmultiply.h @@ -0,0 +1,56 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationscalarmultiply.h + * Copyright (C) 2014 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_SCALAR_MULTIPLY_H__ +#define __GIMP_OPERATION_SCALAR_MULTIPLY_H__ + + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_SCALAR_MULTIPLY (gimp_operation_scalar_multiply_get_type ()) +#define GIMP_OPERATION_SCALAR_MULTIPLY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SCALAR_MULTIPLY, GimpOperationScalarMultiply)) +#define GIMP_OPERATION_SCALAR_MULTIPLY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SCALAR_MULTIPLY, GimpOperationScalarMultiplyClass)) +#define GIMP_IS_OPERATION_SCALAR_MULTIPLY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SCALAR_MULTIPLY)) +#define GIMP_IS_OPERATION_SCALAR_MULTIPLY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SCALAR_MULTIPLY)) +#define GIMP_OPERATION_SCALAR_MULTIPLY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SCALAR_MULTIPLY, GimpOperationScalarMultiplyClass)) + + +typedef struct _GimpOperationScalarMultiply GimpOperationScalarMultiply; +typedef struct _GimpOperationScalarMultiplyClass GimpOperationScalarMultiplyClass; + +struct _GimpOperationScalarMultiply +{ + GeglOperationPointFilter parent_instance; + + gint n_components; + gdouble factor; +}; + +struct _GimpOperationScalarMultiplyClass +{ + GeglOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_scalar_multiply_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_SCALAR_MULTIPLY_H__ */ diff --git a/app/operations/gimpoperationsemiflatten.c b/app/operations/gimpoperationsemiflatten.c new file mode 100644 index 0000000..1352f02 --- /dev/null +++ b/app/operations/gimpoperationsemiflatten.c @@ -0,0 +1,191 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsemiflatten.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Ported from the semi-flatten plug-in + * by Adam D. Moss, adam@foxbox.org. 1998/01/27 + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" + +#include "operations-types.h" + +#include "gimpoperationsemiflatten.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_COLOR +}; + + +static void gimp_operation_semi_flatten_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_semi_flatten_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_semi_flatten_prepare (GeglOperation *operation); +static gboolean gimp_operation_semi_flatten_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationSemiFlatten, gimp_operation_semi_flatten, + GEGL_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_semi_flatten_parent_class + + +static void +gimp_operation_semi_flatten_class_init (GimpOperationSemiFlattenClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + GimpRGB white; + + object_class->set_property = gimp_operation_semi_flatten_set_property; + object_class->get_property = gimp_operation_semi_flatten_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:semi-flatten", + "categories", "color", + "description", _("Replace partial transparency with a color"), + NULL); + + operation_class->prepare = gimp_operation_semi_flatten_prepare; + + point_class->process = gimp_operation_semi_flatten_process; + + gimp_rgba_set (&white, 1.0, 1.0, 1.0, 1.0); + + g_object_class_install_property (object_class, PROP_COLOR, + gimp_param_spec_rgb ("color", + _("Color"), + _("The color"), + FALSE, &white, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_semi_flatten_init (GimpOperationSemiFlatten *self) +{ +} + +static void +gimp_operation_semi_flatten_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationSemiFlatten *self = GIMP_OPERATION_SEMI_FLATTEN (object); + + switch (property_id) + { + case PROP_COLOR: + gimp_value_set_rgb (value, &self->color); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_semi_flatten_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationSemiFlatten *self = GIMP_OPERATION_SEMI_FLATTEN (object); + + switch (property_id) + { + case PROP_COLOR: + gimp_value_get_rgb (value, &self->color); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_semi_flatten_prepare (GeglOperation *operation) +{ + const Babl *space = gegl_operation_get_source_space (operation, "input"); + gegl_operation_set_format (operation, "input", babl_format_with_space ("RGBA float", space)); + gegl_operation_set_format (operation, "output", babl_format_with_space ("RGBA float", space)); +} + +static gboolean +gimp_operation_semi_flatten_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationSemiFlatten *self = GIMP_OPERATION_SEMI_FLATTEN (operation); + gfloat *src = in_buf; + gfloat *dest = out_buf; + + while (samples--) + { + gfloat alpha = src[ALPHA]; + + if (alpha <= 0.0 || alpha >= 1.0) + { + dest[RED] = src[RED]; + dest[GREEN] = src[GREEN]; + dest[BLUE] = src[BLUE]; + dest[ALPHA] = alpha; + } + else + { + dest[RED] = src[RED] * alpha + self->color.r * (1.0 - alpha); + dest[GREEN] = src[GREEN] * alpha + self->color.g * (1.0 - alpha); + dest[BLUE] = src[BLUE] * alpha + self->color.b * (1.0 - alpha); + dest[ALPHA] = 1.0; + } + + src += 4; + dest += 4; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationsemiflatten.h b/app/operations/gimpoperationsemiflatten.h new file mode 100644 index 0000000..be6311e --- /dev/null +++ b/app/operations/gimpoperationsemiflatten.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsemiflatten.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_SEMI_FLATTEN_H__ +#define __GIMP_OPERATION_SEMI_FLATTEN_H__ + + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_SEMI_FLATTEN (gimp_operation_semi_flatten_get_type ()) +#define GIMP_OPERATION_SEMI_FLATTEN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SEMI_FLATTEN, GimpOperationSemiFlatten)) +#define GIMP_OPERATION_SEMI_FLATTEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SEMI_FLATTEN, GimpOperationSemiFlattenClass)) +#define GIMP_IS_OPERATION_SEMI_FLATTEN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SEMI_FLATTEN)) +#define GIMP_IS_OPERATION_SEMI_FLATTEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SEMI_FLATTEN)) +#define GIMP_OPERATION_SEMI_FLATTEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SEMI_FLATTEN, GimpOperationSemiFlattenClass)) + + +typedef struct _GimpOperationSemiFlatten GimpOperationSemiFlatten; +typedef struct _GimpOperationSemiFlattenClass GimpOperationSemiFlattenClass; + +struct _GimpOperationSemiFlatten +{ + GeglOperationPointFilter parent_instance; + + GimpRGB color; +}; + +struct _GimpOperationSemiFlattenClass +{ + GeglOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_semi_flatten_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_SEMI_FLATTEN_H__ */ diff --git a/app/operations/gimpoperationsetalpha.c b/app/operations/gimpoperationsetalpha.c new file mode 100644 index 0000000..b41af3c --- /dev/null +++ b/app/operations/gimpoperationsetalpha.c @@ -0,0 +1,188 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsetalpha.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl.h> + +#include "operations-types.h" + +#include "gimpoperationsetalpha.h" + + +enum +{ + PROP_0, + PROP_VALUE +}; + + +static void gimp_operation_set_alpha_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_set_alpha_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_set_alpha_prepare (GeglOperation *operation); +static gboolean gimp_operation_set_alpha_process (GeglOperation *operation, + void *in_buf, + void *aux_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationSetAlpha, gimp_operation_set_alpha, + GEGL_TYPE_OPERATION_POINT_COMPOSER) + +#define parent_class gimp_operation_set_alpha_parent_class + + +static void +gimp_operation_set_alpha_class_init (GimpOperationSetAlphaClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointComposerClass *point_class = GEGL_OPERATION_POINT_COMPOSER_CLASS (klass); + + object_class->set_property = gimp_operation_set_alpha_set_property; + object_class->get_property = gimp_operation_set_alpha_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:set-alpha", + "categories", "color", + "description", "Set a buffer's alpha channel to a value", + NULL); + + operation_class->prepare = gimp_operation_set_alpha_prepare; + + point_class->process = gimp_operation_set_alpha_process; + + g_object_class_install_property (object_class, PROP_VALUE, + g_param_spec_double ("value", + "Value", + "The alpha value", + 0.0, 1.0, 1.0, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_set_alpha_init (GimpOperationSetAlpha *self) +{ +} + +static void +gimp_operation_set_alpha_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationSetAlpha *self = GIMP_OPERATION_SET_ALPHA (object); + + switch (property_id) + { + case PROP_VALUE: + g_value_set_double (value, self->value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_set_alpha_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationSetAlpha *self = GIMP_OPERATION_SET_ALPHA (object); + + switch (property_id) + { + case PROP_VALUE: + self->value = g_value_get_double (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_set_alpha_prepare (GeglOperation *operation) +{ + const Babl *space = gegl_operation_get_source_space (operation, "input"); + gegl_operation_set_format (operation, "input", babl_format_with_space ("RGBA float", space)); + gegl_operation_set_format (operation, "aux", babl_format_with_space ("Y float", space)); + gegl_operation_set_format (operation, "output", babl_format_with_space ("RGBA float", space)); +} + +static gboolean +gimp_operation_set_alpha_process (GeglOperation *operation, + void *in_buf, + void *aux_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationSetAlpha *self = GIMP_OPERATION_SET_ALPHA (operation); + gfloat *src = in_buf; + gfloat *aux = aux_buf; + gfloat *dest = out_buf; + + if (aux) + { + while (samples--) + { + dest[RED] = src[RED]; + dest[GREEN] = src[GREEN]; + dest[BLUE] = src[BLUE]; + dest[ALPHA] = self->value * *aux; + + src += 4; + aux += 1; + dest += 4; + } + } + else + { + while (samples--) + { + dest[RED] = src[RED]; + dest[GREEN] = src[GREEN]; + dest[BLUE] = src[BLUE]; + dest[ALPHA] = self->value; + + src += 4; + dest += 4; + } + } + + return TRUE; +} diff --git a/app/operations/gimpoperationsetalpha.h b/app/operations/gimpoperationsetalpha.h new file mode 100644 index 0000000..741ae1e --- /dev/null +++ b/app/operations/gimpoperationsetalpha.h @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsetalpha.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_SET_ALPHA_H__ +#define __GIMP_OPERATION_SET_ALPHA_H__ + + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_SET_ALPHA (gimp_operation_set_alpha_get_type ()) +#define GIMP_OPERATION_SET_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SET_ALPHA, GimpOperationSetAlpha)) +#define GIMP_OPERATION_SET_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SET_ALPHA, GimpOperationSetAlphaClass)) +#define GIMP_IS_OPERATION_SET_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SET_ALPHA)) +#define GIMP_IS_OPERATION_SET_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SET_ALPHA)) +#define GIMP_OPERATION_SET_ALPHA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SET_ALPHA, GimpOperationSetAlphaClass)) + + +typedef struct _GimpOperationSetAlpha GimpOperationSetAlpha; +typedef struct _GimpOperationSetAlphaClass GimpOperationSetAlphaClass; + +struct _GimpOperationSetAlpha +{ + GeglOperationPointComposer parent_instance; + + gdouble value; +}; + +struct _GimpOperationSetAlphaClass +{ + GeglOperationPointComposerClass parent_class; +}; + + +GType gimp_operation_set_alpha_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_SET_ALPHA_H__ */ diff --git a/app/operations/gimpoperationsettings.c b/app/operations/gimpoperationsettings.c new file mode 100644 index 0000000..88a6ace --- /dev/null +++ b/app/operations/gimpoperationsettings.c @@ -0,0 +1,320 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsettings.c + * Copyright (C) 2020 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "gegl/gimp-gegl-utils.h" + +#include "core/gimpdrawable.h" +#include "core/gimpdrawablefilter.h" + +#include "gimpoperationsettings.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_CLIP, + PROP_REGION, + PROP_MODE, + PROP_OPACITY, + PROP_COLOR_MANAGED, + PROP_GAMMA_HACK +}; + + +static void gimp_operation_settings_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_settings_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + + +G_DEFINE_TYPE (GimpOperationSettings, gimp_operation_settings, + GIMP_TYPE_SETTINGS) + +#define parent_class gimp_operation_settings_parent_class + + +static void +gimp_operation_settings_class_init (GimpOperationSettingsClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = gimp_operation_settings_set_property; + object_class->get_property = gimp_operation_settings_get_property; + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_CLIP, + "gimp-clip", + _("Clipping"), + _("How to clip"), + GIMP_TYPE_TRANSFORM_RESIZE, + GIMP_TRANSFORM_RESIZE_ADJUST, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_REGION, + "gimp-region", + NULL, NULL, + GIMP_TYPE_FILTER_REGION, + GIMP_FILTER_REGION_SELECTION, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_MODE, + "gimp-mode", + _("Mode"), + NULL, + GIMP_TYPE_LAYER_MODE, + GIMP_LAYER_MODE_REPLACE, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_OPACITY, + "gimp-opacity", + _("Opacity"), + NULL, + 0.0, 1.0, 1.0, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_COLOR_MANAGED, + "gimp-color-managed", + _("Color _managed"), + NULL, + FALSE, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); + + GIMP_CONFIG_PROP_BOOLEAN (object_class, PROP_GAMMA_HACK, + "gimp-gamma-hack", + "Gamma hack (temp hack, please ignore)", + NULL, + FALSE, + GIMP_PARAM_STATIC_STRINGS | + GIMP_CONFIG_PARAM_DEFAULTS); +} + +static void +gimp_operation_settings_init (GimpOperationSettings *settings) +{ +} + +static void +gimp_operation_settings_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationSettings *settings = GIMP_OPERATION_SETTINGS (object); + + switch (property_id) + { + case PROP_CLIP: + g_value_set_enum (value, settings->clip); + break; + + case PROP_REGION: + g_value_set_enum (value, settings->region); + break; + + case PROP_MODE: + g_value_set_enum (value, settings->mode); + break; + + case PROP_OPACITY: + g_value_set_double (value, settings->opacity); + break; + + case PROP_COLOR_MANAGED: + g_value_set_boolean (value, settings->color_managed); + break; + + case PROP_GAMMA_HACK: + g_value_set_boolean (value, settings->gamma_hack); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_settings_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationSettings *settings = GIMP_OPERATION_SETTINGS (object); + + switch (property_id) + { + case PROP_CLIP: + settings->clip = g_value_get_enum (value); + break; + + case PROP_REGION: + settings->region = g_value_get_enum (value); + break; + + case PROP_MODE: + settings->mode = g_value_get_enum (value); + break; + + case PROP_OPACITY: + settings->opacity = g_value_get_double (value); + break; + + case PROP_COLOR_MANAGED: + settings->color_managed = g_value_get_boolean (value); + break; + + case PROP_GAMMA_HACK: + settings->gamma_hack = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + +/* public functions */ + +void +gimp_operation_settings_sync_drawable_filter (GimpOperationSettings *settings, + GimpDrawableFilter *filter) +{ + gboolean clip; + + g_return_if_fail (GIMP_IS_OPERATION_SETTINGS (settings)); + g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter)); + + clip = settings->clip == GIMP_TRANSFORM_RESIZE_CLIP || + ! babl_format_has_alpha (gimp_drawable_filter_get_format (filter)); + + gimp_drawable_filter_set_region (filter, settings->region); + gimp_drawable_filter_set_clip (filter, clip); + gimp_drawable_filter_set_mode (filter, + settings->mode, + GIMP_LAYER_COLOR_SPACE_AUTO, + GIMP_LAYER_COLOR_SPACE_AUTO, + GIMP_LAYER_COMPOSITE_AUTO); + gimp_drawable_filter_set_opacity (filter, settings->opacity); + gimp_drawable_filter_set_color_managed (filter, settings->color_managed); + gimp_drawable_filter_set_gamma_hack (filter, settings->gamma_hack); +} + + +/* protected functions */ + +static const gchar * const base_properties[] = +{ + "time", + "gimp-clip", + "gimp-region", + "gimp-mode", + "gimp-opacity", + "gimp-color-managed", + "gimp-gamma-hack" +}; + +gboolean +gimp_operation_settings_config_serialize_base (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data) +{ + gint i; + + for (i = 0; i < G_N_ELEMENTS (base_properties); i++) + { + if (! gimp_config_serialize_property_by_name (config, + base_properties[i], + writer)) + { + return FALSE; + } + } + + return TRUE; +} + +gboolean +gimp_operation_settings_config_equal_base (GimpConfig *a, + GimpConfig *b) +{ + GimpOperationSettings *settings_a = GIMP_OPERATION_SETTINGS (a); + GimpOperationSettings *settings_b = GIMP_OPERATION_SETTINGS (b); + + return settings_a->clip == settings_b->clip && + settings_a->region == settings_b->region && + settings_a->mode == settings_b->mode && + settings_a->opacity == settings_b->opacity && + settings_a->color_managed == settings_b->color_managed && + settings_a->gamma_hack == settings_b->gamma_hack; +} + +void +gimp_operation_settings_config_reset_base (GimpConfig *config) +{ + gint i; + + g_object_freeze_notify (G_OBJECT (config)); + + for (i = 0; i < G_N_ELEMENTS (base_properties); i++) + gimp_config_reset_property (G_OBJECT (config), base_properties[i]); + + g_object_thaw_notify (G_OBJECT (config)); +} + +gboolean +gimp_operation_settings_config_copy_base (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags) +{ + gint i; + + g_object_freeze_notify (G_OBJECT (dest)); + + for (i = 0; i < G_N_ELEMENTS (base_properties); i++) + { + g_object_unref (g_object_bind_property (src, base_properties[i], + dest, base_properties[i], + G_BINDING_SYNC_CREATE)); + } + + g_object_thaw_notify (G_OBJECT (dest)); + + return TRUE; +} diff --git a/app/operations/gimpoperationsettings.h b/app/operations/gimpoperationsettings.h new file mode 100644 index 0000000..a081fce --- /dev/null +++ b/app/operations/gimpoperationsettings.h @@ -0,0 +1,75 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsettings.h + * Copyright (C) 2020 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_SETTINGS_H__ +#define __GIMP_OPERATION_SETTINGS_H__ + + +#include "core/gimpsettings.h" + + +#define GIMP_TYPE_OPERATION_SETTINGS (gimp_operation_settings_get_type ()) +#define GIMP_OPERATION_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SETTINGS, GimpOperationSettings)) +#define GIMP_OPERATION_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SETTINGS, GimpOperationSettingsClass)) +#define GIMP_IS_OPERATION_SETTINGS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SETTINGS)) +#define GIMP_IS_OPERATION_SETTINGS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SETTINGS)) +#define GIMP_OPERATION_SETTINGS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SETTINGS, GimpOperationSettingsClass)) + + +typedef struct _GimpOperationSettingsClass GimpOperationSettingsClass; + +struct _GimpOperationSettings +{ + GimpSettings parent_instance; + + GimpTransformResize clip; + GimpFilterRegion region; + GimpLayerMode mode; + gdouble opacity; + gboolean color_managed; + gboolean gamma_hack; +}; + +struct _GimpOperationSettingsClass +{ + GimpSettingsClass parent_class; +}; + + +GType gimp_operation_settings_get_type (void) G_GNUC_CONST; + +void gimp_operation_settings_sync_drawable_filter (GimpOperationSettings *settings, + GimpDrawableFilter *filter); + + +/* protected */ + +gboolean gimp_operation_settings_config_serialize_base (GimpConfig *config, + GimpConfigWriter *writer, + gpointer data); +gboolean gimp_operation_settings_config_equal_base (GimpConfig *a, + GimpConfig *b); +void gimp_operation_settings_config_reset_base (GimpConfig *config); +gboolean gimp_operation_settings_config_copy_base (GimpConfig *src, + GimpConfig *dest, + GParamFlags flags); + + +#endif /* __GIMP_OPERATION_SETTINGS_H__ */ diff --git a/app/operations/gimpoperationshrink.c b/app/operations/gimpoperationshrink.c new file mode 100644 index 0000000..c862edb --- /dev/null +++ b/app/operations/gimpoperationshrink.c @@ -0,0 +1,443 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationshrink.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpmath/gimpmath.h" + +#include "operations-types.h" + +#include "gimpoperationshrink.h" + + +enum +{ + PROP_0, + PROP_RADIUS_X, + PROP_RADIUS_Y, + PROP_EDGE_LOCK +}; + + +static void gimp_operation_shrink_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_shrink_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_shrink_prepare (GeglOperation *operation); +static GeglRectangle + gimp_operation_shrink_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi); +static GeglRectangle + gimp_operation_shrink_get_cached_region (GeglOperation *self, + const GeglRectangle *roi); + +static gboolean gimp_operation_shrink_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationShrink, gimp_operation_shrink, + GEGL_TYPE_OPERATION_FILTER) + +#define parent_class gimp_operation_shrink_parent_class + + +static void +gimp_operation_shrink_class_init (GimpOperationShrinkClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationFilterClass *filter_class = GEGL_OPERATION_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_shrink_set_property; + object_class->get_property = gimp_operation_shrink_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:shrink", + "categories", "gimp", + "description", "GIMP Shrink operation", + NULL); + + operation_class->prepare = gimp_operation_shrink_prepare; + operation_class->get_required_for_output = gimp_operation_shrink_get_required_for_output; + operation_class->get_cached_region = gimp_operation_shrink_get_cached_region; + operation_class->threaded = FALSE; + + filter_class->process = gimp_operation_shrink_process; + + g_object_class_install_property (object_class, PROP_RADIUS_X, + g_param_spec_int ("radius-x", + "Radius X", + "Shrink radius in X diection", + 1, 2342, 1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_RADIUS_Y, + g_param_spec_int ("radius-y", + "Radius Y", + "Shrink radius in Y diection", + 1, 2342, 1, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_EDGE_LOCK, + g_param_spec_boolean ("edge-lock", + "Edge Lock", + "Shrink from border", + FALSE, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_shrink_init (GimpOperationShrink *self) +{ +} + +static void +gimp_operation_shrink_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationShrink *self = GIMP_OPERATION_SHRINK (object); + + switch (property_id) + { + case PROP_RADIUS_X: + g_value_set_int (value, self->radius_x); + break; + + case PROP_RADIUS_Y: + g_value_set_int (value, self->radius_y); + break; + + case PROP_EDGE_LOCK: + g_value_set_boolean (value, self->edge_lock); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_shrink_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationShrink *self = GIMP_OPERATION_SHRINK (object); + + switch (property_id) + { + case PROP_RADIUS_X: + self->radius_x = g_value_get_int (value); + break; + + case PROP_RADIUS_Y: + self->radius_y = g_value_get_int (value); + break; + + case PROP_EDGE_LOCK: + self->edge_lock = g_value_get_boolean (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_shrink_prepare (GeglOperation *operation) +{ + const Babl *space = gegl_operation_get_source_space (operation, "input"); + gegl_operation_set_format (operation, "input", babl_format_with_space ("Y float", space)); + gegl_operation_set_format (operation, "output", babl_format_with_space ("Y float", space)); +} + +static GeglRectangle +gimp_operation_shrink_get_required_for_output (GeglOperation *self, + const gchar *input_pad, + const GeglRectangle *roi) +{ + return *gegl_operation_source_get_bounding_box (self, "input"); +} + +static GeglRectangle +gimp_operation_shrink_get_cached_region (GeglOperation *self, + const GeglRectangle *roi) +{ + return *gegl_operation_source_get_bounding_box (self, "input"); +} + +static void +compute_border (gint16 *circ, + guint16 xradius, + guint16 yradius) +{ + gint32 i; + gint32 diameter = xradius * 2 + 1; + gdouble tmp; + + for (i = 0; i < diameter; i++) + { + if (i > xradius) + tmp = (i - xradius) - 0.5; + else if (i < xradius) + tmp = (xradius - i) - 0.5; + else + tmp = 0.0; + + circ[i] = RINT (yradius / + (gdouble) xradius * sqrt (SQR (xradius) - SQR (tmp))); + } +} + +static inline void +rotate_pointers (gfloat **p, + guint32 n) +{ + guint32 i; + gfloat *tmp; + + tmp = p[0]; + + for (i = 0; i < n - 1; i++) + p[i] = p[i + 1]; + + p[i] = tmp; +} + +static gboolean +gimp_operation_shrink_process (GeglOperation *operation, + GeglBuffer *input, + GeglBuffer *output, + const GeglRectangle *roi, + gint level) +{ + /* Pretty much the same as fatten_region only different. + * Blame all bugs in this function on jaycox@gimp.org + * + * If edge_lock is true we assume that pixels outside the region we + * are passed are identical to the edge pixels. If edge_lock is + * false, we assume that pixels outside the region are 0 + */ + GimpOperationShrink *self = GIMP_OPERATION_SHRINK (operation); + const Babl *input_format = babl_format ("Y float"); + const Babl *output_format = babl_format ("Y float"); + gint32 i, j, x, y; + gfloat **buf; /* caches the the region's pixels */ + gfloat *out; /* holds the new scan line we are computing */ + gfloat **max; /* caches the smallest values for each column */ + gint16 *circ; /* holds the y coords of the filter's mask */ + gfloat last_max; + gint16 last_index; + gfloat *buffer; + gint buffer_size; + + max = g_new (gfloat *, roi->width + 2 * self->radius_x); + buf = g_new (gfloat *, self->radius_y + 1); + + for (i = 0; i < self->radius_y + 1; i++) + buf[i] = g_new (gfloat, roi->width); + + buffer_size = (roi->width+ 2 * self->radius_x + 1) * (self->radius_y + 1); + buffer = g_new (gfloat, buffer_size); + + if (self->edge_lock) + { + for (i = 0; i < buffer_size; i++) + buffer[i] = 1.0; + } + else + { + memset (buffer, 0, buffer_size * sizeof (gfloat)); + } + + for (i = 0; i < roi->width + 2 * self->radius_x; i++) + { + if (i < self->radius_x) + { + if (self->edge_lock) + max[i] = buffer; + else + max[i] = &buffer[(self->radius_y + 1) * (roi->width + self->radius_x)]; + } + else if (i < roi->width + self->radius_x) + { + max[i] = &buffer[(self->radius_y + 1) * (i - self->radius_x)]; + } + else + { + if (self->edge_lock) + max[i] = &buffer[(self->radius_y + 1) * (roi->width + self->radius_x - 1)]; + else + max[i] = &buffer[(self->radius_y + 1) * (roi->width + self->radius_x)]; + } + } + + if (! self->edge_lock) + for (j = 0 ; j < self->radius_y + 1; j++) + max[0][j] = 0.0; + + /* offset the max pointer by self->radius_x so the range of the + * array is [-self->radius_x] to [roi->width + self->radius_x] + */ + max += self->radius_x; + + out = g_new (gfloat, roi->width); + + circ = g_new (gint16, 2 * self->radius_x + 1); + compute_border (circ, self->radius_x, self->radius_y); + + /* offset the circ pointer by self->radius_x so the range of the + * array is [-self->radius_x] to [self->radius_x] + */ + circ += self->radius_x; + + for (i = 0; i < self->radius_y && i < roi->height; i++) /* load top of image */ + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + i, + roi->width, 1), + 1.0, input_format, buf[i + 1], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + + if (self->edge_lock) + memcpy (buf[0], buf[1], roi->width * sizeof (gfloat)); + else + memset (buf[0], 0, roi->width * sizeof (gfloat)); + + for (x = 0; x < roi->width; x++) /* set up max for top of image */ + { + max[x][0] = buf[0][x]; + + for (j = 1; j < self->radius_y + 1; j++) + max[x][j] = MIN (buf[j][x], max[x][j - 1]); + } + + for (y = 0; y < roi->height; y++) + { + rotate_pointers (buf, self->radius_y + 1); + + if (y < roi->height - self->radius_y) + gegl_buffer_get (input, + GEGL_RECTANGLE (roi->x, roi->y + y + self->radius_y, + roi->width, 1), + 1.0, input_format, buf[self->radius_y], + GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE); + + else if (self->edge_lock) + memcpy (buf[self->radius_y], buf[self->radius_y - 1], + roi->width * sizeof (gfloat)); + else + memset (buf[self->radius_y], 0, roi->width * sizeof (gfloat)); + + for (x = 0 ; x < roi->width; x++) /* update max array */ + { + for (i = self->radius_y; i > 0; i--) + max[x][i] = MIN (MIN (max[x][i - 1], buf[i - 1][x]), buf[i][x]); + + max[x][0] = buf[0][x]; + } + + last_max = max[0][circ[-1]]; + last_index = 0; + + for (x = 0 ; x < roi->width; x++) /* render scan line */ + { + last_index--; + + if (last_index >= 0) + { + if (last_max <= 0.0) + { + out[x] = 0.0; + } + else + { + last_max = 1.0; + + for (i = self->radius_x; i >= 0; i--) + if (last_max > max[x + i][circ[i]]) + { + last_max = max[x + i][circ[i]]; + last_index = i; + } + + out[x] = last_max; + } + } + else + { + last_index = self->radius_x; + last_max = max[x + self->radius_x][circ[self->radius_x]]; + + for (i = self->radius_x - 1; i >= -self->radius_x; i--) + if (last_max > max[x + i][circ[i]]) + { + last_max = max[x + i][circ[i]]; + last_index = i; + } + + out[x] = last_max; + } + } + + gegl_buffer_set (output, + GEGL_RECTANGLE (roi->x, roi->y + y, + roi->width, 1), + 0, output_format, out, + GEGL_AUTO_ROWSTRIDE); + } + + /* undo the offsets to the pointers so we can free the malloced memory */ + circ -= self->radius_x; + max -= self->radius_x; + + /* free the memory */ + g_free (circ); + g_free (buffer); + g_free (max); + + for (i = 0; i < self->radius_y + 1; i++) + g_free (buf[i]); + + g_free (buf); + g_free (out); + + return TRUE; +} diff --git a/app/operations/gimpoperationshrink.h b/app/operations/gimpoperationshrink.h new file mode 100644 index 0000000..1ba58e6 --- /dev/null +++ b/app/operations/gimpoperationshrink.h @@ -0,0 +1,57 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationshrink.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_SHRINK_H__ +#define __GIMP_OPERATION_SHRINK_H__ + + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_SHRINK (gimp_operation_shrink_get_type ()) +#define GIMP_OPERATION_SHRINK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SHRINK, GimpOperationShrink)) +#define GIMP_OPERATION_SHRINK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SHRINK, GimpOperationShrinkClass)) +#define GIMP_IS_OPERATION_SHRINK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SHRINK)) +#define GIMP_IS_OPERATION_SHRINK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SHRINK)) +#define GIMP_OPERATION_SHRINK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SHRINK, GimpOperationShrinkClass)) + + +typedef struct _GimpOperationShrink GimpOperationShrink; +typedef struct _GimpOperationShrinkClass GimpOperationShrinkClass; + +struct _GimpOperationShrink +{ + GeglOperationFilter parent_instance; + + gint radius_x; + gint radius_y; + gboolean edge_lock; +}; + +struct _GimpOperationShrinkClass +{ + GeglOperationFilterClass parent_class; +}; + + +GType gimp_operation_shrink_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_SHRINK_H__ */ diff --git a/app/operations/gimpoperationthreshold.c b/app/operations/gimpoperationthreshold.c new file mode 100644 index 0000000..e33a9ec --- /dev/null +++ b/app/operations/gimpoperationthreshold.c @@ -0,0 +1,232 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationthreshold.c + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> +#include <gegl.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpconfig/gimpconfig.h" + +#include "operations-types.h" + +#include "gimpoperationthreshold.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_CHANNEL, + PROP_LOW, + PROP_HIGH +}; + + +static void gimp_operation_threshold_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_threshold_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static gboolean gimp_operation_threshold_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationThreshold, gimp_operation_threshold, + GIMP_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_threshold_parent_class + + +static void +gimp_operation_threshold_class_init (GimpOperationThresholdClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_threshold_set_property; + object_class->get_property = gimp_operation_threshold_get_property; + + point_class->process = gimp_operation_threshold_process; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:threshold", + "categories", "color", + "description", _("Reduce image to two colors using a threshold"), + NULL); + + GIMP_CONFIG_PROP_ENUM (object_class, PROP_CHANNEL, + "channel", + _("Channel"), + NULL, + GIMP_TYPE_HISTOGRAM_CHANNEL, + GIMP_HISTOGRAM_VALUE, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_LOW, + "low", + _("Low threshold"), + NULL, + 0.0, 1.0, 0.5, + GIMP_PARAM_STATIC_STRINGS); + + GIMP_CONFIG_PROP_DOUBLE (object_class, PROP_HIGH, + "high", + _("High threshold"), + NULL, + 0.0, 1.0, 1.0, + GIMP_PARAM_STATIC_STRINGS); +} + +static void +gimp_operation_threshold_init (GimpOperationThreshold *self) +{ +} + +static void +gimp_operation_threshold_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationThreshold *self = GIMP_OPERATION_THRESHOLD (object); + + switch (property_id) + { + case PROP_CHANNEL: + g_value_set_enum (value, self->channel); + break; + + case PROP_LOW: + g_value_set_double (value, self->low); + break; + + case PROP_HIGH: + g_value_set_double (value, self->high); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_threshold_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationThreshold *self = GIMP_OPERATION_THRESHOLD (object); + + switch (property_id) + { + case PROP_CHANNEL: + self->channel = g_value_get_enum (value); + break; + + case PROP_LOW: + self->low = g_value_get_double (value); + break; + + case PROP_HIGH: + self->high = g_value_get_double (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + + static gboolean +gimp_operation_threshold_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationThreshold *threshold = GIMP_OPERATION_THRESHOLD (operation); + gfloat *src = in_buf; + gfloat *dest = out_buf; + + while (samples--) + { + gfloat value = 0.0; + + switch (threshold->channel) + { + case GIMP_HISTOGRAM_VALUE: + value = MAX (src[RED], src[GREEN]); + value = MAX (value, src[BLUE]); + break; + + case GIMP_HISTOGRAM_RED: + value = src[RED]; + break; + + case GIMP_HISTOGRAM_GREEN: + value = src[GREEN]; + break; + + case GIMP_HISTOGRAM_BLUE: + value = src[BLUE]; + break; + + case GIMP_HISTOGRAM_ALPHA: + value = src[ALPHA]; + break; + + case GIMP_HISTOGRAM_RGB: + value = MIN (src[RED], src[GREEN]); + value = MIN (value, src[BLUE]); + break; + + case GIMP_HISTOGRAM_LUMINANCE: + value = GIMP_RGB_LUMINANCE (src[RED], src[GREEN], src[BLUE]); + break; + } + + value = (value >= threshold->low && value <= threshold->high) ? 1.0 : 0.0; + + dest[RED] = value; + dest[GREEN] = value; + dest[BLUE] = value; + dest[ALPHA] = src[ALPHA]; + + src += 4; + dest += 4; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationthreshold.h b/app/operations/gimpoperationthreshold.h new file mode 100644 index 0000000..dcdf52b --- /dev/null +++ b/app/operations/gimpoperationthreshold.h @@ -0,0 +1,57 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationthreshold.h + * Copyright (C) 2007 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_THRESHOLD_H__ +#define __GIMP_OPERATION_THRESHOLD_H__ + + +#include "gimpoperationpointfilter.h" + + +#define GIMP_TYPE_OPERATION_THRESHOLD (gimp_operation_threshold_get_type ()) +#define GIMP_OPERATION_THRESHOLD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_THRESHOLD, GimpOperationThreshold)) +#define GIMP_OPERATION_THRESHOLD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_THRESHOLD, GimpOperationThresholdClass)) +#define GIMP_IS_OPERATION_THRESHOLD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_THRESHOLD)) +#define GIMP_IS_OPERATION_THRESHOLD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_THRESHOLD)) +#define GIMP_OPERATION_THRESHOLD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_THRESHOLD, GimpOperationThresholdClass)) + + +typedef struct _GimpOperationThreshold GimpOperationThreshold; +typedef struct _GimpOperationThresholdClass GimpOperationThresholdClass; + +struct _GimpOperationThreshold +{ + GimpOperationPointFilter parent_instance; + + GimpHistogramChannel channel; + gdouble low; + gdouble high; +}; + +struct _GimpOperationThresholdClass +{ + GimpOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_threshold_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_THRESHOLD_H__ */ diff --git a/app/operations/gimpoperationthresholdalpha.c b/app/operations/gimpoperationthresholdalpha.c new file mode 100644 index 0000000..94cbaf5 --- /dev/null +++ b/app/operations/gimpoperationthresholdalpha.c @@ -0,0 +1,178 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationthresholdalpha.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + * + * Ported from the threshold-alpha plug-in + * Copyright (C) 1997 Shuji Narazaki <narazaki@InetQ.or.jp> + */ + +#include "config.h" + +#include <gegl.h> + +#include "operations-types.h" + +#include "gimpoperationthresholdalpha.h" + +#include "gimp-intl.h" + + +enum +{ + PROP_0, + PROP_VALUE +}; + + +static void gimp_operation_threshold_alpha_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); +static void gimp_operation_threshold_alpha_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); + +static void gimp_operation_threshold_alpha_prepare (GeglOperation *operation); +static gboolean gimp_operation_threshold_alpha_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationThresholdAlpha, gimp_operation_threshold_alpha, + GEGL_TYPE_OPERATION_POINT_FILTER) + +#define parent_class gimp_operation_threshold_alpha_parent_class + + +static void +gimp_operation_threshold_alpha_class_init (GimpOperationThresholdAlphaClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass); + + object_class->set_property = gimp_operation_threshold_alpha_set_property; + object_class->get_property = gimp_operation_threshold_alpha_get_property; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:threshold-alpha", + "categories", "color", + "description", + _("Make transparency all-or-nothing, by " + "thresholding the alpha channel to a value"), + NULL); + + operation_class->prepare = gimp_operation_threshold_alpha_prepare; + + point_class->process = gimp_operation_threshold_alpha_process; + + g_object_class_install_property (object_class, PROP_VALUE, + g_param_spec_double ("value", + _("Value"), + _("The alpha value"), + 0.0, 1.0, 0.5, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); +} + +static void +gimp_operation_threshold_alpha_init (GimpOperationThresholdAlpha *self) +{ +} + +static void +gimp_operation_threshold_alpha_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationThresholdAlpha *self = GIMP_OPERATION_THRESHOLD_ALPHA (object); + + switch (property_id) + { + case PROP_VALUE: + g_value_set_double (value, self->value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_threshold_alpha_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationThresholdAlpha *self = GIMP_OPERATION_THRESHOLD_ALPHA (object); + + switch (property_id) + { + case PROP_VALUE: + self->value = g_value_get_double (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_threshold_alpha_prepare (GeglOperation *operation) +{ + const Babl *space = gegl_operation_get_source_space (operation, "input"); + gegl_operation_set_format (operation, "input", babl_format_with_space ("RGBA float", space)); + gegl_operation_set_format (operation, "output", babl_format_with_space ("RGBA float", space)); +} + +static gboolean +gimp_operation_threshold_alpha_process (GeglOperation *operation, + void *in_buf, + void *out_buf, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationThresholdAlpha *self = GIMP_OPERATION_THRESHOLD_ALPHA (operation); + gfloat *src = in_buf; + gfloat *dest = out_buf; + + while (samples--) + { + dest[RED] = src[RED]; + dest[GREEN] = src[GREEN]; + dest[BLUE] = src[BLUE]; + + if (src[ALPHA] > self->value) + dest[ALPHA] = 1.0; + else + dest[ALPHA] = 0.0; + + src += 4; + dest += 4; + } + + return TRUE; +} diff --git a/app/operations/gimpoperationthresholdalpha.h b/app/operations/gimpoperationthresholdalpha.h new file mode 100644 index 0000000..0339289 --- /dev/null +++ b/app/operations/gimpoperationthresholdalpha.h @@ -0,0 +1,56 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationthresholdalpha.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_THRESHOLD_ALPHA_H__ +#define __GIMP_OPERATION_THRESHOLD_ALPHA_H__ + + +#include <gegl-plugin.h> +#include <operation/gegl-operation-point-filter.h> + + +#define GIMP_TYPE_OPERATION_THRESHOLD_ALPHA (gimp_operation_threshold_alpha_get_type ()) +#define GIMP_OPERATION_THRESHOLD_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_THRESHOLD_ALPHA, GimpOperationThresholdAlpha)) +#define GIMP_OPERATION_THRESHOLD_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_THRESHOLD_ALPHA, GimpOperationThresholdAlphaClass)) +#define GIMP_IS_OPERATION_THRESHOLD_ALPHA(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_THRESHOLD_ALPHA)) +#define GIMP_IS_OPERATION_THRESHOLD_ALPHA_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_THRESHOLD_ALPHA)) +#define GIMP_OPERATION_THRESHOLD_ALPHA_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_THRESHOLD_ALPHA, GimpOperationThresholdAlphaClass)) + + +typedef struct _GimpOperationThresholdAlpha GimpOperationThresholdAlpha; +typedef struct _GimpOperationThresholdAlphaClass GimpOperationThresholdAlphaClass; + +struct _GimpOperationThresholdAlpha +{ + GeglOperationPointFilter parent_instance; + + gdouble value; +}; + +struct _GimpOperationThresholdAlphaClass +{ + GeglOperationPointFilterClass parent_class; +}; + + +GType gimp_operation_threshold_alpha_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_THRESHOLD_ALPHA_H__ */ diff --git a/app/operations/layer-modes-legacy/Makefile.am b/app/operations/layer-modes-legacy/Makefile.am new file mode 100644 index 0000000..b8241da --- /dev/null +++ b/app/operations/layer-modes-legacy/Makefile.am @@ -0,0 +1,54 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Layer-Modes-Legacy\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = \ + libapplayermodeslegacy.a + +libapplayermodeslegacy_a_SOURCES = \ + gimpoperationadditionlegacy.c \ + gimpoperationadditionlegacy.h \ + gimpoperationburnlegacy.c \ + gimpoperationburnlegacy.h \ + gimpoperationdarkenonlylegacy.c \ + gimpoperationdarkenonlylegacy.h \ + gimpoperationdifferencelegacy.c \ + gimpoperationdifferencelegacy.h \ + gimpoperationdividelegacy.c \ + gimpoperationdividelegacy.h \ + gimpoperationdodgelegacy.c \ + gimpoperationdodgelegacy.h \ + gimpoperationgrainextractlegacy.c \ + gimpoperationgrainextractlegacy.h \ + gimpoperationgrainmergelegacy.c \ + gimpoperationgrainmergelegacy.h \ + gimpoperationhardlightlegacy.c \ + gimpoperationhardlightlegacy.h \ + gimpoperationhslcolorlegacy.c \ + gimpoperationhslcolorlegacy.h \ + gimpoperationhsvhuelegacy.c \ + gimpoperationhsvhuelegacy.h \ + gimpoperationhsvsaturationlegacy.c \ + gimpoperationhsvsaturationlegacy.h \ + gimpoperationhsvvaluelegacy.c \ + gimpoperationhsvvaluelegacy.h \ + gimpoperationlightenonlylegacy.c \ + gimpoperationlightenonlylegacy.h \ + gimpoperationmultiplylegacy.c \ + gimpoperationmultiplylegacy.h \ + gimpoperationscreenlegacy.c \ + gimpoperationscreenlegacy.h \ + gimpoperationsoftlightlegacy.c \ + gimpoperationsoftlightlegacy.h \ + gimpoperationsubtractlegacy.c \ + gimpoperationsubtractlegacy.h + diff --git a/app/operations/layer-modes-legacy/Makefile.in b/app/operations/layer-modes-legacy/Makefile.in new file mode 100644 index 0000000..f51eeed --- /dev/null +++ b/app/operations/layer-modes-legacy/Makefile.in @@ -0,0 +1,1038 @@ +# 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@ +subdir = app/operations/layer-modes-legacy +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 $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libapplayermodeslegacy_a_AR = $(AR) $(ARFLAGS) +libapplayermodeslegacy_a_LIBADD = +am_libapplayermodeslegacy_a_OBJECTS = \ + gimpoperationadditionlegacy.$(OBJEXT) \ + gimpoperationburnlegacy.$(OBJEXT) \ + gimpoperationdarkenonlylegacy.$(OBJEXT) \ + gimpoperationdifferencelegacy.$(OBJEXT) \ + gimpoperationdividelegacy.$(OBJEXT) \ + gimpoperationdodgelegacy.$(OBJEXT) \ + gimpoperationgrainextractlegacy.$(OBJEXT) \ + gimpoperationgrainmergelegacy.$(OBJEXT) \ + gimpoperationhardlightlegacy.$(OBJEXT) \ + gimpoperationhslcolorlegacy.$(OBJEXT) \ + gimpoperationhsvhuelegacy.$(OBJEXT) \ + gimpoperationhsvsaturationlegacy.$(OBJEXT) \ + gimpoperationhsvvaluelegacy.$(OBJEXT) \ + gimpoperationlightenonlylegacy.$(OBJEXT) \ + gimpoperationmultiplylegacy.$(OBJEXT) \ + gimpoperationscreenlegacy.$(OBJEXT) \ + gimpoperationsoftlightlegacy.$(OBJEXT) \ + gimpoperationsubtractlegacy.$(OBJEXT) +libapplayermodeslegacy_a_OBJECTS = \ + $(am_libapplayermodeslegacy_a_OBJECTS) +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)/gimpoperationadditionlegacy.Po \ + ./$(DEPDIR)/gimpoperationburnlegacy.Po \ + ./$(DEPDIR)/gimpoperationdarkenonlylegacy.Po \ + ./$(DEPDIR)/gimpoperationdifferencelegacy.Po \ + ./$(DEPDIR)/gimpoperationdividelegacy.Po \ + ./$(DEPDIR)/gimpoperationdodgelegacy.Po \ + ./$(DEPDIR)/gimpoperationgrainextractlegacy.Po \ + ./$(DEPDIR)/gimpoperationgrainmergelegacy.Po \ + ./$(DEPDIR)/gimpoperationhardlightlegacy.Po \ + ./$(DEPDIR)/gimpoperationhslcolorlegacy.Po \ + ./$(DEPDIR)/gimpoperationhsvhuelegacy.Po \ + ./$(DEPDIR)/gimpoperationhsvsaturationlegacy.Po \ + ./$(DEPDIR)/gimpoperationhsvvaluelegacy.Po \ + ./$(DEPDIR)/gimpoperationlightenonlylegacy.Po \ + ./$(DEPDIR)/gimpoperationmultiplylegacy.Po \ + ./$(DEPDIR)/gimpoperationscreenlegacy.Po \ + ./$(DEPDIR)/gimpoperationsoftlightlegacy.Po \ + ./$(DEPDIR)/gimpoperationsubtractlegacy.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +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 = +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 = $(libapplayermodeslegacy_a_SOURCES) +DIST_SOURCES = $(libapplayermodeslegacy_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +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@ +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Layer-Modes-Legacy\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = \ + libapplayermodeslegacy.a + +libapplayermodeslegacy_a_SOURCES = \ + gimpoperationadditionlegacy.c \ + gimpoperationadditionlegacy.h \ + gimpoperationburnlegacy.c \ + gimpoperationburnlegacy.h \ + gimpoperationdarkenonlylegacy.c \ + gimpoperationdarkenonlylegacy.h \ + gimpoperationdifferencelegacy.c \ + gimpoperationdifferencelegacy.h \ + gimpoperationdividelegacy.c \ + gimpoperationdividelegacy.h \ + gimpoperationdodgelegacy.c \ + gimpoperationdodgelegacy.h \ + gimpoperationgrainextractlegacy.c \ + gimpoperationgrainextractlegacy.h \ + gimpoperationgrainmergelegacy.c \ + gimpoperationgrainmergelegacy.h \ + gimpoperationhardlightlegacy.c \ + gimpoperationhardlightlegacy.h \ + gimpoperationhslcolorlegacy.c \ + gimpoperationhslcolorlegacy.h \ + gimpoperationhsvhuelegacy.c \ + gimpoperationhsvhuelegacy.h \ + gimpoperationhsvsaturationlegacy.c \ + gimpoperationhsvsaturationlegacy.h \ + gimpoperationhsvvaluelegacy.c \ + gimpoperationhsvvaluelegacy.h \ + gimpoperationlightenonlylegacy.c \ + gimpoperationlightenonlylegacy.h \ + gimpoperationmultiplylegacy.c \ + gimpoperationmultiplylegacy.h \ + gimpoperationscreenlegacy.c \ + gimpoperationscreenlegacy.h \ + gimpoperationsoftlightlegacy.c \ + gimpoperationsoftlightlegacy.h \ + gimpoperationsubtractlegacy.c \ + gimpoperationsubtractlegacy.h + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(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 app/operations/layer-modes-legacy/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu app/operations/layer-modes-legacy/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): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libapplayermodeslegacy.a: $(libapplayermodeslegacy_a_OBJECTS) $(libapplayermodeslegacy_a_DEPENDENCIES) $(EXTRA_libapplayermodeslegacy_a_DEPENDENCIES) + $(AM_V_at)-rm -f libapplayermodeslegacy.a + $(AM_V_AR)$(libapplayermodeslegacy_a_AR) libapplayermodeslegacy.a $(libapplayermodeslegacy_a_OBJECTS) $(libapplayermodeslegacy_a_LIBADD) + $(AM_V_at)$(RANLIB) libapplayermodeslegacy.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationadditionlegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationburnlegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationdarkenonlylegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationdifferencelegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationdividelegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationdodgelegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationgrainextractlegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationgrainmergelegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationhardlightlegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationhslcolorlegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationhsvhuelegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationhsvsaturationlegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationhsvvaluelegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationlightenonlylegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationmultiplylegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationscreenlegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationsoftlightlegacy.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationsubtractlegacy.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 + +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 + +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 +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +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: + +clean-generic: + +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-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/gimpoperationadditionlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationburnlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationdarkenonlylegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationdifferencelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationdividelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationdodgelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationgrainextractlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationgrainmergelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhardlightlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhslcolorlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhsvhuelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhsvsaturationlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhsvvaluelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationlightenonlylegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationmultiplylegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationscreenlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationsoftlightlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationsubtractlegacy.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-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +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)/gimpoperationadditionlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationburnlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationdarkenonlylegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationdifferencelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationdividelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationdodgelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationgrainextractlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationgrainmergelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhardlightlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhslcolorlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhsvhuelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhsvsaturationlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationhsvvaluelegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationlightenonlylegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationmultiplylegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationscreenlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationsoftlightlegacy.Po + -rm -f ./$(DEPDIR)/gimpoperationsubtractlegacy.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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + 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-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am 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 \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +# 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/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.c b/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.c new file mode 100644 index 0000000..02992f2 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.c @@ -0,0 +1,126 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationadditionmode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationadditionlegacy.h" + + +static gboolean gimp_operation_addition_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationAdditionLegacy, gimp_operation_addition_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_addition_legacy_class_init (GimpOperationAdditionLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:addition-legacy", + "description", "GIMP addition mode operation", + NULL); + + layer_mode_class->process = gimp_operation_addition_legacy_process; +} + +static void +gimp_operation_addition_legacy_init (GimpOperationAdditionLegacy *self) +{ +} + +static gboolean +gimp_operation_addition_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + const gboolean has_mask = mask != NULL; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (has_mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = in[b] + layer[b]; + comp = CLAMP (comp, 0.0f, 1.0f); + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.h b/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.h new file mode 100644 index 0000000..7f9df60 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationadditionlegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationadditionlegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_ADDITION_LEGACY_H__ +#define __GIMP_OPERATION_ADDITION_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_ADDITION_LEGACY (gimp_operation_addition_legacy_get_type ()) +#define GIMP_OPERATION_ADDITION_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_ADDITION_LEGACY, GimpOperationAdditionLegacy)) +#define GIMP_OPERATION_ADDITION_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_ADDITION_LEGACY, GimpOperationAdditionLegacyClass)) +#define GIMP_IS_OPERATION_ADDITION_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_ADDITION_LEGACY)) +#define GIMP_IS_OPERATION_ADDITION_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_ADDITION_LEGACY)) +#define GIMP_OPERATION_ADDITION_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_ADDITION_LEGACY, GimpOperationAdditionLegacyClass)) + + +typedef struct _GimpOperationAdditionLegacy GimpOperationAdditionLegacy; +typedef struct _GimpOperationAdditionLegacyClass GimpOperationAdditionLegacyClass; + +struct _GimpOperationAdditionLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationAdditionLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_addition_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_ADDITION_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationburnlegacy.c b/app/operations/layer-modes-legacy/gimpoperationburnlegacy.c new file mode 100644 index 0000000..5511b69 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationburnlegacy.c @@ -0,0 +1,128 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationburnmode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationburnlegacy.h" + + +static gboolean gimp_operation_burn_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationBurnLegacy, gimp_operation_burn_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_burn_legacy_class_init (GimpOperationBurnLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:burn-legacy", + "description", "GIMP burn mode operation", + NULL); + + layer_mode_class->process = gimp_operation_burn_legacy_process; +} + +static void +gimp_operation_burn_legacy_init (GimpOperationBurnLegacy *self) +{ +} + +static gboolean +gimp_operation_burn_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = 1.0f - (1.0f - in[b]) / layer[b]; + /* The CLAMP macro is deliberately inlined and + * written to map comp == NAN (0 / 0) -> 1 + */ + comp = comp < 0.0f ? 0.0f : comp < 1.0f ? comp : 1.0f; + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationburnlegacy.h b/app/operations/layer-modes-legacy/gimpoperationburnlegacy.h new file mode 100644 index 0000000..dc13e3f --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationburnlegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationburnlegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_BURN_LEGACY_H__ +#define __GIMP_OPERATION_BURN_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_BURN_LEGACY (gimp_operation_burn_legacy_get_type ()) +#define GIMP_OPERATION_BURN_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_BURN_LEGACY, GimpOperationBurnLegacy)) +#define GIMP_OPERATION_BURN_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_BURN_LEGACY, GimpOperationBurnLegacyClass)) +#define GIMP_IS_OPERATION_BURN_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_BURN_LEGACY)) +#define GIMP_IS_OPERATION_BURN_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_BURN_LEGACY)) +#define GIMP_OPERATION_BURN_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_BURN_LEGACY, GimpOperationBurnLegacyClass)) + + +typedef struct _GimpOperationBurnLegacy GimpOperationBurnLegacy; +typedef struct _GimpOperationBurnLegacyClass GimpOperationBurnLegacyClass; + +struct _GimpOperationBurnLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationBurnLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_burn_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_BURN_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.c b/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.c new file mode 100644 index 0000000..1a3ebdf --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.c @@ -0,0 +1,124 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdarkenonlymode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationdarkenonlylegacy.h" + + +static gboolean gimp_operation_darken_only_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationDarkenOnlyLegacy, gimp_operation_darken_only_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_darken_only_legacy_class_init (GimpOperationDarkenOnlyLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:darken-only-legacy", + "description", "GIMP darken only mode operation", + NULL); + + layer_mode_class->process = gimp_operation_darken_only_legacy_process; +} + +static void +gimp_operation_darken_only_legacy_init (GimpOperationDarkenOnlyLegacy *self) +{ +} + +static gboolean +gimp_operation_darken_only_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (new_alpha && comp_alpha) + { + gint b; + gfloat ratio = comp_alpha / new_alpha; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = MIN (in[b], layer[b]); + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.h b/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.h new file mode 100644 index 0000000..c0406a1 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationdarkenonlylegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdarkenonlylegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_DARKEN_ONLY_LEGACY_H__ +#define __GIMP_OPERATION_DARKEN_ONLY_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_DARKEN_ONLY_LEGACY (gimp_operation_darken_only_legacy_get_type ()) +#define GIMP_OPERATION_DARKEN_ONLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_DARKEN_ONLY_MODE, GimpOperationDarkenOnlyLegacy)) +#define GIMP_OPERATION_DARKEN_ONLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_DARKEN_ONLY_MODE, GimpOperationDarkenOnlyLegacyClass)) +#define GIMP_IS_OPERATION_DARKEN_ONLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_DARKEN_ONLY_MODE)) +#define GIMP_IS_OPERATION_DARKEN_ONLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_DARKEN_ONLY_MODE)) +#define GIMP_OPERATION_DARKEN_ONLY_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_DARKEN_ONLY_MODE, GimpOperationDarkenOnlyLegacyClass)) + + +typedef struct _GimpOperationDarkenOnlyLegacy GimpOperationDarkenOnlyLegacy; +typedef struct _GimpOperationDarkenOnlyLegacyClass GimpOperationDarkenOnlyLegacyClass; + +struct _GimpOperationDarkenOnlyLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationDarkenOnlyLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_darken_only_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_DARKEN_ONLY_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.c b/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.c new file mode 100644 index 0000000..55f3328 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.c @@ -0,0 +1,126 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdifferencemode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationdifferencelegacy.h" + + +static gboolean gimp_operation_difference_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationDifferenceLegacy, gimp_operation_difference_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_difference_legacy_class_init (GimpOperationDifferenceLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:difference-legacy", + "description", "GIMP difference mode operation", + NULL); + + layer_mode_class->process = gimp_operation_difference_legacy_process; +} + +static void +gimp_operation_difference_legacy_init (GimpOperationDifferenceLegacy *self) +{ +} + + +static gboolean +gimp_operation_difference_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = in[b] - layer[b]; + comp = (comp < 0.0f) ? -comp : comp; + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.h b/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.h new file mode 100644 index 0000000..145b9c2 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationdifferencelegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdifferencelegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_DIFFERENCE_LEGACY_H__ +#define __GIMP_OPERATION_DIFFERENCE_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_DIFFERENCE_LEGACY (gimp_operation_difference_legacy_get_type ()) +#define GIMP_OPERATION_DIFFERENCE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_DIFFERENCE_LEGACY, GimpOperationDifferenceLegacy)) +#define GIMP_OPERATION_DIFFERENCE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_DIFFERENCE_LEGACY, GimpOperationDifferenceLegacyClass)) +#define GIMP_IS_OPERATION_DIFFERENCE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_DIFFERENCE_LEGACY)) +#define GIMP_IS_OPERATION_DIFFERENCE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_DIFFERENCE_LEGACY)) +#define GIMP_OPERATION_DIFFERENCE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_DIFFERENCE_LEGACY, GimpOperationDifferenceLegacyClass)) + + +typedef struct _GimpOperationDifferenceLegacy GimpOperationDifferenceLegacy; +typedef struct _GimpOperationDifferenceLegacyClass GimpOperationDifferenceLegacyClass; + +struct _GimpOperationDifferenceLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationDifferenceLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_difference_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_DIFFERENCE_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationdividelegacy.c b/app/operations/layer-modes-legacy/gimpoperationdividelegacy.c new file mode 100644 index 0000000..8fe8dd8 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationdividelegacy.c @@ -0,0 +1,127 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdividemode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "libgimpmath/gimpmath.h" + +#include "../operations-types.h" + +#include "gimpoperationdividelegacy.h" + + +static gboolean gimp_operation_divide_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationDivideLegacy, gimp_operation_divide_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_divide_legacy_class_init (GimpOperationDivideLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:divide-legacy", + "description", "GIMP divide mode operation", + NULL); + + layer_mode_class->process = gimp_operation_divide_legacy_process; +} + +static void +gimp_operation_divide_legacy_init (GimpOperationDivideLegacy *self) +{ +} + +static gboolean +gimp_operation_divide_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gint b; + gfloat ratio = comp_alpha / new_alpha; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = in[b] / layer[b]; + comp = SAFE_CLAMP (comp, 0.0f, 1.0f); + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationdividelegacy.h b/app/operations/layer-modes-legacy/gimpoperationdividelegacy.h new file mode 100644 index 0000000..fa5de12 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationdividelegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdividelegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_DIVIDE_LEGACY_H__ +#define __GIMP_OPERATION_DIVIDE_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_DIVIDE_LEGACY (gimp_operation_divide_legacy_get_type ()) +#define GIMP_OPERATION_DIVIDE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_DIVIDE_LEGACY, GimpOperationDivideLegacy)) +#define GIMP_OPERATION_DIVIDE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_DIVIDE_LEGACY, GimpOperationDivideLegacyClass)) +#define GIMP_IS_OPERATION_DIVIDE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_DIVIDE_LEGACY)) +#define GIMP_IS_OPERATION_DIVIDE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_DIVIDE_LEGACY)) +#define GIMP_OPERATION_DIVIDE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_DIVIDE_LEGACY, GimpOperationDivideLegacyClass)) + + +typedef struct _GimpOperationDivideLegacy GimpOperationDivideLegacy; +typedef struct _GimpOperationDivideLegacyClass GimpOperationDivideLegacyClass; + +struct _GimpOperationDivideLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationDivideLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_divide_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_DIVIDE_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.c b/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.c new file mode 100644 index 0000000..65adaef --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.c @@ -0,0 +1,127 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdodgelegacy.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "libgimpmath/gimpmath.h" + +#include "../operations-types.h" + +#include "gimpoperationdodgelegacy.h" + + +static gboolean gimp_operation_dodge_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationDodgeLegacy, gimp_operation_dodge_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_dodge_legacy_class_init (GimpOperationDodgeLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:dodge-legacy", + "description", "GIMP dodge mode operation", + NULL); + + layer_mode_class->process = gimp_operation_dodge_legacy_process; +} + +static void +gimp_operation_dodge_legacy_init (GimpOperationDodgeLegacy *self) +{ +} + +static gboolean +gimp_operation_dodge_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gint b; + gfloat ratio = comp_alpha / new_alpha; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = in[b] / (1.0f - layer[b]); + comp = SAFE_CLAMP (comp, 0.0f, 1.0f); + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.h b/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.h new file mode 100644 index 0000000..b640fed --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationdodgelegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdodgelegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_DODGE_LEGACY_H__ +#define __GIMP_OPERATION_DODGE_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_DODGE_LEGACY (gimp_operation_dodge_legacy_get_type ()) +#define GIMP_OPERATION_DODGE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_DODGE_LEGACY, GimpOperationDodgeLegacy)) +#define GIMP_OPERATION_DODGE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_DODGE_LEGACY, GimpOperationDodgeLegacyClass)) +#define GIMP_IS_OPERATION_DODGE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_DODGE_LEGACY)) +#define GIMP_IS_OPERATION_DODGE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_DODGE_LEGACY)) +#define GIMP_OPERATION_DODGE_LEGACY_GET_CLASS(obj)(G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_DODGE_LEGACY, GimpOperationDodgeLegacyClass)) + + +typedef struct _GimpOperationDodgeLegacy GimpOperationDodgeLegacy; +typedef struct _GimpOperationDodgeLegacyClass GimpOperationDodgeLegacyClass; + +struct _GimpOperationDodgeLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationDodgeLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_dodge_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_DODGE_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.c b/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.c new file mode 100644 index 0000000..77338c4 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.c @@ -0,0 +1,125 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationgrainextractmode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationgrainextractlegacy.h" + + +static gboolean gimp_operation_grain_extract_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationGrainExtractLegacy, gimp_operation_grain_extract_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_grain_extract_legacy_class_init (GimpOperationGrainExtractLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:grain-extract-legacy", + "description", "GIMP grain extract mode operation", + NULL); + + layer_mode_class->process = gimp_operation_grain_extract_legacy_process; +} + +static void +gimp_operation_grain_extract_legacy_init (GimpOperationGrainExtractLegacy *self) +{ +} + +static gboolean +gimp_operation_grain_extract_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = in[b] - layer[b] + 128.0f / 255.0f; + comp = CLAMP (comp, 0.0f, 1.0f); + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.h b/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.h new file mode 100644 index 0000000..149ee09 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationgrainextractlegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationgrainextractlegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_GRAIN_EXTRACT_LEGACY_H__ +#define __GIMP_OPERATION_GRAIN_EXTRACT_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY (gimp_operation_grain_extract_legacy_get_type ()) +#define GIMP_OPERATION_GRAIN_EXTRACT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY, GimpOperationGrainExtractLegacy)) +#define GIMP_OPERATION_GRAIN_EXTRACT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY, GimpOperationGrainExtractLegacyClass)) +#define GIMP_IS_OPERATION_GRAIN_EXTRACT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY)) +#define GIMP_IS_OPERATION_GRAIN_EXTRACT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY)) +#define GIMP_OPERATION_GRAIN_EXTRACT_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_GRAIN_EXTRACT_LEGACY, GimpOperationGrainExtractLegacyClass)) + + +typedef struct _GimpOperationGrainExtractLegacy GimpOperationGrainExtractLegacy; +typedef struct _GimpOperationGrainExtractLegacyClass GimpOperationGrainExtractLegacyClass; + +struct _GimpOperationGrainExtractLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationGrainExtractLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_grain_extract_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_GRAIN_EXTRACT_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.c b/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.c new file mode 100644 index 0000000..c12a995 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.c @@ -0,0 +1,125 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationgrainmergemode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationgrainmergelegacy.h" + + +static gboolean gimp_operation_grain_merge_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationGrainMergeLegacy, gimp_operation_grain_merge_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_grain_merge_legacy_class_init (GimpOperationGrainMergeLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:grain-merge-legacy", + "description", "GIMP grain merge mode operation", + NULL); + + layer_mode_class->process = gimp_operation_grain_merge_legacy_process; +} + +static void +gimp_operation_grain_merge_legacy_init (GimpOperationGrainMergeLegacy *self) +{ +} + +static gboolean +gimp_operation_grain_merge_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = in[b] + layer[b] - 128.0f / 255.0f; + comp = CLAMP (comp, 0.0f, 1.0f); + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask ++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.h b/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.h new file mode 100644 index 0000000..344e895 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationgrainmergelegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationgrainmergelegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_GRAIN_MERGE_LEGACY_H__ +#define __GIMP_OPERATION_GRAIN_MERGE_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_GRAIN_MERGE_LEGACY (gimp_operation_grain_merge_legacy_get_type ()) +#define GIMP_OPERATION_GRAIN_MERGE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_GRAIN_MERGE_LEGACY, GimpOperationGrainMergeLegacy)) +#define GIMP_OPERATION_GRAIN_MERGE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_GRAIN_MERGE_LEGACY, GimpOperationGrainMergeLegacyClass)) +#define GIMP_IS_OPERATION_GRAIN_MERGE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_GRAIN_MERGE_LEGACY)) +#define GIMP_IS_OPERATION_GRAIN_MERGE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_GRAIN_MERGE_LEGACY)) +#define GIMP_OPERATION_GRAIN_MERGE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_GRAIN_MERGE_LEGACY, GimpOperationGrainMergeLegacyClass)) + + +typedef struct _GimpOperationGrainMergeLegacy GimpOperationGrainMergeLegacy; +typedef struct _GimpOperationGrainMergeLegacyClass GimpOperationGrainMergeLegacyClass; + +struct _GimpOperationGrainMergeLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationGrainMergeLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_grain_merge_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_GRAIN_MERGE_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.c b/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.c new file mode 100644 index 0000000..68f8eda --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.c @@ -0,0 +1,135 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhardlightmode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationhardlightlegacy.h" + + +static gboolean gimp_operation_hardlight_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationHardlightLegacy, gimp_operation_hardlight_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_hardlight_legacy_class_init (GimpOperationHardlightLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:hardlight-legacy", + "description", "GIMP hardlight mode operation", + NULL); + + layer_mode_class->process = gimp_operation_hardlight_legacy_process; +} + +static void +gimp_operation_hardlight_legacy_init (GimpOperationHardlightLegacy *self) +{ +} + +static gboolean +gimp_operation_hardlight_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp; + + if (layer[b] > 128.0f / 255.0f) + { + comp = (1.0 - in[b]) * (1.0 - (layer[b] - 128.0f / 255.0f) * 2.0f); + comp = MIN (1.0f - comp, 1.0f); + } + else + { + comp = in[b] * (layer[b] * 2.0f); + comp = MIN (comp, 1.0f); + } + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask ++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.h b/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.h new file mode 100644 index 0000000..38791be --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhardlightlegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhardlightlegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_HARDLIGHT_LEGACY_H__ +#define __GIMP_OPERATION_HARDLIGHT_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_HARDLIGHT_LEGACY (gimp_operation_hardlight_legacy_get_type ()) +#define GIMP_OPERATION_HARDLIGHT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_HARDLIGHT_LEGACY, GimpOperationHardlightLegacy)) +#define GIMP_OPERATION_HARDLIGHT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_HARDLIGHT_LEGACY, GimpOperationHardlightLegacyClass)) +#define GIMP_IS_OPERATION_HARDLIGHT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_HARDLIGHT_LEGACY)) +#define GIMP_IS_OPERATION_HARDLIGHT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_HARDLIGHT_LEGACY)) +#define GIMP_OPERATION_HARDLIGHT_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_HARDLIGHT_LEGACY, GimpOperationHardlightLegacyClass)) + + +typedef struct _GimpOperationHardlightLegacy GimpOperationHardlightLegacy; +typedef struct _GimpOperationHardlightLegacyClass GimpOperationHardlightLegacyClass; + +struct _GimpOperationHardlightLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationHardlightLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_hardlight_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_HARDLIGHT_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.c b/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.c new file mode 100644 index 0000000..6fd7a95 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.c @@ -0,0 +1,141 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationcolormode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" + +#include "../operations-types.h" + +#include "gimpoperationhslcolorlegacy.h" + + +static gboolean gimp_operation_hsl_color_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationHslColorLegacy, gimp_operation_hsl_color_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_hsl_color_legacy_class_init (GimpOperationHslColorLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:hsl-color-legacy", + "description", "GIMP color mode operation", + NULL); + + layer_mode_class->process = gimp_operation_hsl_color_legacy_process; +} + +static void +gimp_operation_hsl_color_legacy_init (GimpOperationHslColorLegacy *self) +{ +} + +static gboolean +gimp_operation_hsl_color_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + GimpHSL layer_hsl, out_hsl; + GimpRGB layer_rgb = {layer[0], layer[1], layer[2]}; + GimpRGB out_rgb = {in[0], in[1], in[2]}; + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gint b; + gfloat out_tmp[3]; + gfloat ratio = comp_alpha / new_alpha; + + gimp_rgb_to_hsl (&layer_rgb, &layer_hsl); + gimp_rgb_to_hsl (&out_rgb, &out_hsl); + + out_hsl.h = layer_hsl.h; + out_hsl.s = layer_hsl.s; + gimp_hsl_to_rgb (&out_hsl, &out_rgb); + + out_tmp[0] = out_rgb.r; + out_tmp[1] = out_rgb.g; + out_tmp[2] = out_rgb.b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = out_tmp[b] * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.h b/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.h new file mode 100644 index 0000000..add2933 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhslcolorlegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhslcolorlegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_HSL_COLOR_LEGACY_H__ +#define __GIMP_OPERATION_HSL_COLOR_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_HSL_COLOR_LEGACY (gimp_operation_hsl_color_legacy_get_type ()) +#define GIMP_OPERATION_HSL_COLOR_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_HSL_COLOR_LEGACY, GimpOperationHslColorLegacy)) +#define GIMP_OPERATION_HSL_COLOR_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_HSL_COLOR_LEGACY, GimpOperationHslColorLegacyClass)) +#define GIMP_IS_OPERATION_HSL_COLOR_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_HSL_COLOR_LEGACY)) +#define GIMP_IS_OPERATION_HSL_COLOR_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_HSL_COLOR_LEGACY)) +#define GIMP_OPERATION_HSL_COLOR_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_HSL_COLOR_LEGACY, GimpOperationHslColorLegacyClass)) + + +typedef struct _GimpOperationHslColorLegacy GimpOperationHslColorLegacy; +typedef struct _GimpOperationHslColorLegacyClass GimpOperationHslColorLegacyClass; + +struct _GimpOperationHslColorLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationHslColorLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_hsl_color_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_HSL_COLOR_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.c b/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.c new file mode 100644 index 0000000..eb9c040 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.c @@ -0,0 +1,146 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhuemode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <cairo.h> +#include <gegl-plugin.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" + +#include "../operations-types.h" + +#include "gimpoperationhsvhuelegacy.h" + + +static gboolean gimp_operation_hsv_hue_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationHsvHueLegacy, gimp_operation_hsv_hue_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_hsv_hue_legacy_class_init (GimpOperationHsvHueLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:hsv-hue-legacy", + "description", "GIMP hue mode operation", + NULL); + + layer_mode_class->process = gimp_operation_hsv_hue_legacy_process; +} + +static void +gimp_operation_hsv_hue_legacy_init (GimpOperationHsvHueLegacy *self) +{ +} + +static gboolean +gimp_operation_hsv_hue_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + GimpHSV layer_hsv, out_hsv; + GimpRGB layer_rgb = {layer[0], layer[1], layer[2]}; + GimpRGB out_rgb = {in[0], in[1], in[2]}; + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gint b; + gfloat out_tmp[3]; + gfloat ratio = comp_alpha / new_alpha; + + gimp_rgb_to_hsv (&layer_rgb, &layer_hsv); + gimp_rgb_to_hsv (&out_rgb, &out_hsv); + + /* Composition should have no effect if saturation is zero. + * otherwise, black would be painted red (see bug #123296). + */ + if (layer_hsv.s) + { + out_hsv.h = layer_hsv.h; + } + gimp_hsv_to_rgb (&out_hsv, &out_rgb); + + out_tmp[0] = out_rgb.r; + out_tmp[1] = out_rgb.g; + out_tmp[2] = out_rgb.b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = out_tmp[b] * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.h b/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.h new file mode 100644 index 0000000..59ef125 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhsvhuelegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhsvhuelegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_HSV_HUE_LEGACY_H__ +#define __GIMP_OPERATION_HSV_HUE_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_HSV_HUE_LEGACY (gimp_operation_hsv_hue_legacy_get_type ()) +#define GIMP_OPERATION_HSV_HUE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_HSV_HUE_LEGACY, GimpOperationHsvHueLegacy)) +#define GIMP_OPERATION_HSV_HUE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_HSV_HUE_LEGACY, GimpOperationHsvHueLegacyClass)) +#define GIMP_IS_OPERATION_HSV_HUE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_HSV_HUE_LEGACY)) +#define GIMP_IS_OPERATION_HSV_HUE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_HSV_HUE_LEGACY)) +#define GIMP_OPERATION_HSV_HUE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_HSV_HUE_LEGACY, GimpOperationHsvHueLegacyClass)) + + +typedef struct _GimpOperationHsvHueLegacy GimpOperationHsvHueLegacy; +typedef struct _GimpOperationHsvHueLegacyClass GimpOperationHsvHueLegacyClass; + +struct _GimpOperationHsvHueLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationHsvHueLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_hsv_hue_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_HSV_HUE_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.c b/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.c new file mode 100644 index 0000000..d150aa1 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.c @@ -0,0 +1,140 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsaturationmode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" + +#include "../operations-types.h" + +#include "gimpoperationhsvsaturationlegacy.h" + + +static gboolean gimp_operation_hsv_saturation_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationHsvSaturationLegacy, gimp_operation_hsv_saturation_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_hsv_saturation_legacy_class_init (GimpOperationHsvSaturationLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:hsv-saturation-legacy", + "description", "GIMP saturation mode operation", + NULL); + + layer_mode_class->process = gimp_operation_hsv_saturation_legacy_process; +} + +static void +gimp_operation_hsv_saturation_legacy_init (GimpOperationHsvSaturationLegacy *self) +{ +} + +static gboolean +gimp_operation_hsv_saturation_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + GimpHSV layer_hsv, out_hsv; + GimpRGB layer_rgb = {layer[0], layer[1], layer[2]}; + GimpRGB out_rgb = {in[0], in[1], in[2]}; + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gint b; + gfloat out_tmp[3]; + gfloat ratio = comp_alpha / new_alpha; + + gimp_rgb_to_hsv (&layer_rgb, &layer_hsv); + gimp_rgb_to_hsv (&out_rgb, &out_hsv); + + out_hsv.s = layer_hsv.s; + gimp_hsv_to_rgb (&out_hsv, &out_rgb); + + out_tmp[0] = out_rgb.r; + out_tmp[1] = out_rgb.g; + out_tmp[2] = out_rgb.b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = out_tmp[b] * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.h b/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.h new file mode 100644 index 0000000..ecb5589 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhsvsaturationlegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhsvsaturationlegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_HSV_SATURATION_LEGACY_H__ +#define __GIMP_OPERATION_HSV_SATURATION_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_HSV_SATURATION_LEGACY (gimp_operation_hsv_saturation_legacy_get_type ()) +#define GIMP_OPERATION_HSV_SATURATION_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_HSV_SATURATION_LEGACY, GimpOperationHsvSaturationLegacy)) +#define GIMP_OPERATION_HSV_SATURATION_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_HSV_SATURATION_LEGACY, GimpOperationHsvSaturationLegacyClass)) +#define GIMP_IS_OPERATION_HSV_SATURATION_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_HSV_SATURATION_LEGACY)) +#define GIMP_IS_OPERATION_HSV_SATURATION_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_HSV_SATURATION_LEGACY)) +#define GIMP_OPERATION_HSV_SATURATION_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_HSV_SATURATION_LEGACY, GimpOperationHsvSaturationLegacyClass)) + + +typedef struct _GimpOperationHsvSaturationLegacy GimpOperationHsvSaturationLegacy; +typedef struct _GimpOperationHsvSaturationLegacyClass GimpOperationHsvSaturationLegacyClass; + +struct _GimpOperationHsvSaturationLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationHsvSaturationLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_hsv_saturation_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_HSV_SATURATION_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.c b/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.c new file mode 100644 index 0000000..b873325 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.c @@ -0,0 +1,140 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationvaluemode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" + +#include "../operations-types.h" + +#include "gimpoperationhsvvaluelegacy.h" + + +static gboolean gimp_operation_hsv_value_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationHsvValueLegacy, gimp_operation_hsv_value_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_hsv_value_legacy_class_init (GimpOperationHsvValueLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:hsv-value-legacy", + "description", "GIMP value mode operation", + NULL); + + layer_mode_class->process = gimp_operation_hsv_value_legacy_process; +} + +static void +gimp_operation_hsv_value_legacy_init (GimpOperationHsvValueLegacy *self) +{ +} + +static gboolean +gimp_operation_hsv_value_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + GimpHSV layer_hsv, out_hsv; + GimpRGB layer_rgb = {layer[0], layer[1], layer[2]}; + GimpRGB out_rgb = {in[0], in[1], in[2]}; + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gint b; + gfloat out_tmp[3]; + gfloat ratio = comp_alpha / new_alpha; + + gimp_rgb_to_hsv (&layer_rgb, &layer_hsv); + gimp_rgb_to_hsv (&out_rgb, &out_hsv); + + out_hsv.v = layer_hsv.v; + gimp_hsv_to_rgb (&out_hsv, &out_rgb); + + out_tmp[0] = out_rgb.r; + out_tmp[1] = out_rgb.g; + out_tmp[2] = out_rgb.b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = out_tmp[b] * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.h b/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.h new file mode 100644 index 0000000..7701ffd --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationhsvvaluelegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationhsvvaluelegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_HSV_VALUE_LEGACY_H__ +#define __GIMP_OPERATION_HSV_VALUE_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_HSV_VALUE_LEGACY (gimp_operation_hsv_value_legacy_get_type ()) +#define GIMP_OPERATION_HSV_VALUE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_HSV_VALUE_LEGACY, GimpOperationHsvValueLegacy)) +#define GIMP_OPERATION_HSV_VALUE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_HSV_VALUE_LEGACY, GimpOperationHsvValueLegacyClass)) +#define GIMP_IS_OPERATION_HSV_VALUE_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_HSV_VALUE_LEGACY)) +#define GIMP_IS_OPERATION_HSV_VALUE_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_HSV_VALUE_LEGACY)) +#define GIMP_OPERATION_HSV_VALUE_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_HSV_VALUE_LEGACY, GimpOperationHsvValueLegacyClass)) + + +typedef struct _GimpOperationHsvValueLegacy GimpOperationHsvValueLegacy; +typedef struct _GimpOperationHsvValueLegacyClass GimpOperationHsvValueLegacyClass; + +struct _GimpOperationHsvValueLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationHsvValueLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_hsv_value_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_HSV_VALUE_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.c b/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.c new file mode 100644 index 0000000..0e54a0c --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.c @@ -0,0 +1,124 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlightenonlylegacy.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationlightenonlylegacy.h" + + +static gboolean gimp_operation_lighten_only_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationLightenOnlyLegacy, gimp_operation_lighten_only_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_lighten_only_legacy_class_init (GimpOperationLightenOnlyLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:lighten-only-legacy", + "description", "GIMP lighten only legacy operation", + NULL); + + layer_mode_class->process = gimp_operation_lighten_only_legacy_process; +} + +static void +gimp_operation_lighten_only_legacy_init (GimpOperationLightenOnlyLegacy *self) +{ +} + +static gboolean +gimp_operation_lighten_only_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gint b; + gfloat ratio = comp_alpha / new_alpha; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = MAX (layer[b], in[b]); + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.h b/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.h new file mode 100644 index 0000000..2417d57 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationlightenonlylegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlightenonlylegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_LIGHTEN_ONLY_LEGACY_H__ +#define __GIMP_OPERATION_LIGHTEN_ONLY_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY (gimp_operation_lighten_only_legacy_get_type ()) +#define GIMP_OPERATION_LIGHTEN_ONLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY, GimpOperationLightenOnlyLegacy)) +#define GIMP_OPERATION_LIGHTEN_ONLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY, GimpOperationLightenOnlyLegacyClass)) +#define GIMP_IS_OPERATION_LIGHTEN_ONLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY)) +#define GIMP_IS_OPERATION_LIGHTEN_ONLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY)) +#define GIMP_OPERATION_LIGHTEN_ONLY_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_LIGHTEN_ONLY_LEGACY, GimpOperationLightenOnlyLegacyClass)) + + +typedef struct _GimpOperationLightenOnlyLegacy GimpOperationLightenOnlyLegacy; +typedef struct _GimpOperationLightenOnlyLegacyClass GimpOperationLightenOnlyLegacyClass; + +struct _GimpOperationLightenOnlyLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationLightenOnlyLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_lighten_only_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_LIGHTEN_ONLY_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.c b/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.c new file mode 100644 index 0000000..69c63c4 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.c @@ -0,0 +1,124 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationmultiplylegacy.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "operations/operations-types.h" + +#include "gimpoperationmultiplylegacy.h" + + +static gboolean gimp_operation_multiply_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationMultiplyLegacy, gimp_operation_multiply_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_multiply_legacy_class_init (GimpOperationMultiplyLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:multiply-legacy", + "description", "GIMP multiply legacy operation", + NULL); + + layer_mode_class->process = gimp_operation_multiply_legacy_process; +} + +static void +gimp_operation_multiply_legacy_init (GimpOperationMultiplyLegacy *self) +{ +} + +static gboolean +gimp_operation_multiply_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = layer[b] * in[b]; + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.h b/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.h new file mode 100644 index 0000000..f099ebd --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationmultiplylegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationmultiplylegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_MULTIPLY_LEGACY_H__ +#define __GIMP_OPERATION_MULTIPLY_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_MULTIPLY_LEGACY (gimp_operation_multiply_legacy_get_type ()) +#define GIMP_OPERATION_MULTIPLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_MULTIPLY_LEGACY, GimpOperationMultiplyLegacy)) +#define GIMP_OPERATION_MULTIPLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_MULTIPLY_LEGACY, GimpOperationMultiplyLegacyClass)) +#define GIMP_IS_OPERATION_MULTIPLY_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_MULTIPLY_LEGACY)) +#define GIMP_IS_OPERATION_MULTIPLY_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_MULTIPLY_LEGACY)) +#define GIMP_OPERATION_MULTIPLY_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_MULTIPLY_LEGACY, GimpOperationMultiplyLegacyClass)) + + +typedef struct _GimpOperationMultiplyLegacy GimpOperationMultiplyLegacy; +typedef struct _GimpOperationMultiplyLegacyClass GimpOperationMultiplyLegacyClass; + +struct _GimpOperationMultiplyLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationMultiplyLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_multiply_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_MULTIPLY_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.c b/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.c new file mode 100644 index 0000000..f2ff2fc --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.c @@ -0,0 +1,124 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationscreenlegacy.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationscreenlegacy.h" + + +static gboolean gimp_operation_screen_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationScreenLegacy, gimp_operation_screen_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_screen_legacy_class_init (GimpOperationScreenLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:screen-legacy", + "description", "GIMP screen mode operation", + NULL); + + layer_mode_class->process = gimp_operation_screen_legacy_process; +} + +static void +gimp_operation_screen_legacy_init (GimpOperationScreenLegacy *self) +{ +} + +static gboolean +gimp_operation_screen_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = 1.0f - (1.0f - in[b]) * (1.0f - layer[b]); + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.h b/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.h new file mode 100644 index 0000000..5d0dc9e --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationscreenlegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationscreenlegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_SCREEN_LEGACY_H__ +#define __GIMP_OPERATION_SCREEN_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_SCREEN_LEGACY (gimp_operation_screen_legacy_get_type ()) +#define GIMP_OPERATION_SCREEN_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SCREEN_LEGACY, GimpOperationScreenLegacy)) +#define GIMP_OPERATION_SCREEN_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SCREEN_LEGACY, GimpOperationScreenLegacyClass)) +#define GIMP_IS_OPERATION_SCREEN_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SCREEN_LEGACY)) +#define GIMP_IS_OPERATION_SCREEN_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SCREEN_LEGACY)) +#define GIMP_OPERATION_SCREEN_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SCREEN_LEGACY, GimpOperationScreenLegacyClass)) + + +typedef struct _GimpOperationScreenLegacy GimpOperationScreenLegacy; +typedef struct _GimpOperationScreenLegacyClass GimpOperationScreenLegacyClass; + +struct _GimpOperationScreenLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationScreenLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_screen_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_SCREEN_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.c b/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.c new file mode 100644 index 0000000..1736e00 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.c @@ -0,0 +1,157 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsoftlightmode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationsoftlightlegacy.h" + + +static gboolean gimp_operation_softlight_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationSoftlightLegacy, gimp_operation_softlight_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>" +"<gegl>" +"<node operation='gimp:softlight-legacy'>" +" <node operation='gegl:load'>" +" <params>" +" <param name='path'>B.png</param>" +" </params>" +" </node>" +"</node>" +"<node operation='gegl:load'>" +" <params>" +" <param name='path'>A.png</param>" +" </params>" +"</node>" +"</gegl>"; + + +static void +gimp_operation_softlight_legacy_class_init (GimpOperationSoftlightLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:softlight-legacy", + "description", "GIMP softlight mode operation", + "reference-image", "soft-light-mode.png", + "reference-composition", reference_xml, + NULL); + + layer_mode_class->process = gimp_operation_softlight_legacy_process; +} + +static void +gimp_operation_softlight_legacy_init (GimpOperationSoftlightLegacy *self) +{ +} + +static gboolean +gimp_operation_softlight_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + { +#if 0 + /* softlight is now used for what GIMP formerly called + * OVERLAY. We fixed OVERLAY to use the right math + * (under the name NEW_OVERLAY), and redirect uses of + * the old OVERLAY blend mode here. This math was + * formerly used for OVERLAY and is exactly the same as + * the multiply, screen, comp math used below. + * See bug #673501. + */ + gfloat comp = in[b] * (in[b] + (2.0f * layer[b]) * (1.0f - in[b])); +#endif + + gfloat multiply = in[b] * layer[b]; + gfloat screen = 1.0f - (1.0f - in[b]) * (1.0f - layer[b]); + gfloat comp = (1.0f - in[b]) * multiply + in[b] * screen; + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask ++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.h b/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.h new file mode 100644 index 0000000..aa8930e --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationsoftlightlegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsoftlightlegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_SOFTLIGHT_LEGACY_H__ +#define __GIMP_OPERATION_SOFTLIGHT_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_SOFTLIGHT_LEGACY (gimp_operation_softlight_legacy_get_type ()) +#define GIMP_OPERATION_SOFTLIGHT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SOFTLIGHT_LEGACY, GimpOperationSoftlightLegacy)) +#define GIMP_OPERATION_SOFTLIGHT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SOFTLIGHT_LEGACY, GimpOperationSoftlightLegacyClass)) +#define GIMP_IS_OPERATION_SOFTLIGHT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SOFTLIGHT_LEGACY)) +#define GIMP_IS_OPERATION_SOFTLIGHT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SOFTLIGHT_LEGACY)) +#define GIMP_OPERATION_SOFTLIGHT_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SOFTLIGHT_LEGACY, GimpOperationSoftlightLegacyClass)) + + +typedef struct _GimpOperationSoftlightLegacy GimpOperationSoftlightLegacy; +typedef struct _GimpOperationSoftlightLegacyClass GimpOperationSoftlightLegacyClass; + +struct _GimpOperationSoftlightLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationSoftlightLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_softlight_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_SOFTLIGHT_LEGACY_H__ */ diff --git a/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.c b/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.c new file mode 100644 index 0000000..0bf3b5e --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.c @@ -0,0 +1,125 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsubtractmode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationsubtractlegacy.h" + + +static gboolean gimp_operation_subtract_legacy_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationSubtractLegacy, gimp_operation_subtract_legacy, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_subtract_legacy_class_init (GimpOperationSubtractLegacyClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:subtract-legacy", + "description", "GIMP subtract mode operation", + NULL); + + layer_mode_class->process = gimp_operation_subtract_legacy_process; +} + +static void +gimp_operation_subtract_legacy_init (GimpOperationSubtractLegacy *self) +{ +} + +static gboolean +gimp_operation_subtract_legacy_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + + while (samples--) + { + gfloat comp_alpha, new_alpha; + + comp_alpha = MIN (in[ALPHA], layer[ALPHA]) * opacity; + if (mask) + comp_alpha *= *mask; + + new_alpha = in[ALPHA] + (1.0f - in[ALPHA]) * comp_alpha; + + if (comp_alpha && new_alpha) + { + gint b; + gfloat ratio = comp_alpha / new_alpha; + + for (b = RED; b < ALPHA; b++) + { + gfloat comp = in[b] - layer[b]; + comp = CLAMP (comp, 0.0f, 1.0f); + + out[b] = comp * ratio + in[b] * (1.0f - ratio); + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + layer += 4; + out += 4; + + if (mask) + mask++; + } + + return TRUE; +} diff --git a/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.h b/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.h new file mode 100644 index 0000000..34a55d5 --- /dev/null +++ b/app/operations/layer-modes-legacy/gimpoperationsubtractlegacy.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsubtractlegacy.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_SUBTRACT_LEGACY_H__ +#define __GIMP_OPERATION_SUBTRACT_LEGACY_H__ + + +#include "operations/layer-modes/gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_SUBTRACT_LEGACY (gimp_operation_subtract_legacy_get_type ()) +#define GIMP_OPERATION_SUBTRACT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SUBTRACT_LEGACY, GimpOperationSubtractLegacy)) +#define GIMP_OPERATION_SUBTRACT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SUBTRACT_LEGACY, GimpOperationSubtractLegacyClass)) +#define GIMP_IS_OPERATION_SUBTRACT_LEGACY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SUBTRACT_LEGACY)) +#define GIMP_IS_OPERATION_SUBTRACT_LEGACY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SUBTRACT_LEGACY)) +#define GIMP_OPERATION_SUBTRACT_LEGACY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SUBTRACT_LEGACY, GimpOperationSubtractLegacyClass)) + + +typedef struct _GimpOperationSubtractLegacy GimpOperationSubtractLegacy; +typedef struct _GimpOperationSubtractLegacyClass GimpOperationSubtractLegacyClass; + +struct _GimpOperationSubtractLegacy +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationSubtractLegacyClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_subtract_legacy_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_SUBTRACT_LEGACY_H__ */ diff --git a/app/operations/layer-modes/Makefile.am b/app/operations/layer-modes/Makefile.am new file mode 100644 index 0000000..24af8fe --- /dev/null +++ b/app/operations/layer-modes/Makefile.am @@ -0,0 +1,79 @@ +## Process this file with automake to produce Makefile.in + +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Layer-Modes\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = \ + libapplayermodes-generic.a \ + libapplayermodes-sse2.a \ + libapplayermodes-sse4.a \ + libapplayermodes.a + +libapplayermodes_generic_a_sources = \ + gimp-layer-modes.c \ + gimp-layer-modes.h \ + \ + gimpoperationlayermode.c \ + gimpoperationlayermode.h \ + gimpoperationlayermode-blend.c \ + gimpoperationlayermode-blend.h \ + gimpoperationlayermode-composite.c \ + gimpoperationlayermode-composite.h \ + \ + gimpoperationantierase.c \ + gimpoperationantierase.h \ + gimpoperationbehind.c \ + gimpoperationbehind.h \ + gimpoperationdissolve.c \ + gimpoperationdissolve.h \ + gimpoperationerase.c \ + gimpoperationerase.h \ + gimpoperationmerge.c \ + gimpoperationmerge.h \ + gimpoperationnormal.c \ + gimpoperationnormal.h \ + gimpoperationpassthrough.c \ + gimpoperationpassthrough.h \ + gimpoperationreplace.c \ + gimpoperationreplace.h \ + gimpoperationsplit.c \ + gimpoperationsplit.h + +libapplayermodes_sse2_a_sources = \ + gimpoperationlayermode-composite-sse2.c \ + \ + gimpoperationnormal-sse2.c + +libapplayermodes_sse4_a_sources = \ + gimpoperationnormal-sse4.c + + +libapplayermodes_generic_a_SOURCES = $(libapplayermodes_generic_a_sources) + +libapplayermodes_sse2_a_SOURCES = $(libapplayermodes_sse2_a_sources) + +libapplayermodes_sse2_a_CFLAGS = $(SSE2_EXTRA_CFLAGS) + +libapplayermodes_sse4_a_SOURCES = $(libapplayermodes_sse4_a_sources) + +libapplayermodes_sse4_a_CFLAGS = $(SSE4_1_EXTRA_CFLAGS) + +libapplayermodes_a_SOURCES = + + +libapplayermodes.a: libapplayermodes-generic.a \ + libapplayermodes-sse2.a \ + libapplayermodes-sse4.a + $(AR) $(ARFLAGS) libapplayermodes.a \ + $(libapplayermodes_generic_a_OBJECTS) \ + $(libapplayermodes_sse2_a_OBJECTS) \ + $(libapplayermodes_sse4_a_OBJECTS) + $(RANLIB) libapplayermodes.a diff --git a/app/operations/layer-modes/Makefile.in b/app/operations/layer-modes/Makefile.in new file mode 100644 index 0000000..ad8d4c1 --- /dev/null +++ b/app/operations/layer-modes/Makefile.in @@ -0,0 +1,1115 @@ +# 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@ +subdir = app/operations/layer-modes +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 $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +LIBRARIES = $(noinst_LIBRARIES) +ARFLAGS = cru +AM_V_AR = $(am__v_AR_@AM_V@) +am__v_AR_ = $(am__v_AR_@AM_DEFAULT_V@) +am__v_AR_0 = @echo " AR " $@; +am__v_AR_1 = +libapplayermodes_generic_a_AR = $(AR) $(ARFLAGS) +libapplayermodes_generic_a_LIBADD = +am__objects_1 = gimp-layer-modes.$(OBJEXT) \ + gimpoperationlayermode.$(OBJEXT) \ + gimpoperationlayermode-blend.$(OBJEXT) \ + gimpoperationlayermode-composite.$(OBJEXT) \ + gimpoperationantierase.$(OBJEXT) gimpoperationbehind.$(OBJEXT) \ + gimpoperationdissolve.$(OBJEXT) gimpoperationerase.$(OBJEXT) \ + gimpoperationmerge.$(OBJEXT) gimpoperationnormal.$(OBJEXT) \ + gimpoperationpassthrough.$(OBJEXT) \ + gimpoperationreplace.$(OBJEXT) gimpoperationsplit.$(OBJEXT) +am_libapplayermodes_generic_a_OBJECTS = $(am__objects_1) +libapplayermodes_generic_a_OBJECTS = \ + $(am_libapplayermodes_generic_a_OBJECTS) +libapplayermodes_sse2_a_AR = $(AR) $(ARFLAGS) +libapplayermodes_sse2_a_LIBADD = +am__objects_2 = libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.$(OBJEXT) \ + libapplayermodes_sse2_a-gimpoperationnormal-sse2.$(OBJEXT) +am_libapplayermodes_sse2_a_OBJECTS = $(am__objects_2) +libapplayermodes_sse2_a_OBJECTS = \ + $(am_libapplayermodes_sse2_a_OBJECTS) +libapplayermodes_sse4_a_AR = $(AR) $(ARFLAGS) +libapplayermodes_sse4_a_LIBADD = +am__objects_3 = \ + libapplayermodes_sse4_a-gimpoperationnormal-sse4.$(OBJEXT) +am_libapplayermodes_sse4_a_OBJECTS = $(am__objects_3) +libapplayermodes_sse4_a_OBJECTS = \ + $(am_libapplayermodes_sse4_a_OBJECTS) +libapplayermodes_a_AR = $(AR) $(ARFLAGS) +libapplayermodes_a_LIBADD = +am_libapplayermodes_a_OBJECTS = +libapplayermodes_a_OBJECTS = $(am_libapplayermodes_a_OBJECTS) +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)/gimp-layer-modes.Po \ + ./$(DEPDIR)/gimpoperationantierase.Po \ + ./$(DEPDIR)/gimpoperationbehind.Po \ + ./$(DEPDIR)/gimpoperationdissolve.Po \ + ./$(DEPDIR)/gimpoperationerase.Po \ + ./$(DEPDIR)/gimpoperationlayermode-blend.Po \ + ./$(DEPDIR)/gimpoperationlayermode-composite.Po \ + ./$(DEPDIR)/gimpoperationlayermode.Po \ + ./$(DEPDIR)/gimpoperationmerge.Po \ + ./$(DEPDIR)/gimpoperationnormal.Po \ + ./$(DEPDIR)/gimpoperationpassthrough.Po \ + ./$(DEPDIR)/gimpoperationreplace.Po \ + ./$(DEPDIR)/gimpoperationsplit.Po \ + ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po \ + ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po \ + ./$(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Po +am__mv = mv -f +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 = +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 = $(libapplayermodes_generic_a_SOURCES) \ + $(libapplayermodes_sse2_a_SOURCES) \ + $(libapplayermodes_sse4_a_SOURCES) \ + $(libapplayermodes_a_SOURCES) +DIST_SOURCES = $(libapplayermodes_generic_a_SOURCES) \ + $(libapplayermodes_sse2_a_SOURCES) \ + $(libapplayermodes_sse4_a_SOURCES) \ + $(libapplayermodes_a_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +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__DIST_COMMON = $(srcdir)/Makefile.in $(top_srcdir)/depcomp +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@ +AM_CPPFLAGS = \ + -DG_LOG_DOMAIN=\"Gimp-Layer-Modes\" \ + -I$(top_builddir) \ + -I$(top_srcdir) \ + -I$(top_builddir)/app \ + -I$(top_srcdir)/app \ + $(CAIRO_CFLAGS) \ + $(GEGL_CFLAGS) \ + $(GDK_PIXBUF_CFLAGS) \ + -I$(includedir) + +noinst_LIBRARIES = \ + libapplayermodes-generic.a \ + libapplayermodes-sse2.a \ + libapplayermodes-sse4.a \ + libapplayermodes.a + +libapplayermodes_generic_a_sources = \ + gimp-layer-modes.c \ + gimp-layer-modes.h \ + \ + gimpoperationlayermode.c \ + gimpoperationlayermode.h \ + gimpoperationlayermode-blend.c \ + gimpoperationlayermode-blend.h \ + gimpoperationlayermode-composite.c \ + gimpoperationlayermode-composite.h \ + \ + gimpoperationantierase.c \ + gimpoperationantierase.h \ + gimpoperationbehind.c \ + gimpoperationbehind.h \ + gimpoperationdissolve.c \ + gimpoperationdissolve.h \ + gimpoperationerase.c \ + gimpoperationerase.h \ + gimpoperationmerge.c \ + gimpoperationmerge.h \ + gimpoperationnormal.c \ + gimpoperationnormal.h \ + gimpoperationpassthrough.c \ + gimpoperationpassthrough.h \ + gimpoperationreplace.c \ + gimpoperationreplace.h \ + gimpoperationsplit.c \ + gimpoperationsplit.h + +libapplayermodes_sse2_a_sources = \ + gimpoperationlayermode-composite-sse2.c \ + \ + gimpoperationnormal-sse2.c + +libapplayermodes_sse4_a_sources = \ + gimpoperationnormal-sse4.c + +libapplayermodes_generic_a_SOURCES = $(libapplayermodes_generic_a_sources) +libapplayermodes_sse2_a_SOURCES = $(libapplayermodes_sse2_a_sources) +libapplayermodes_sse2_a_CFLAGS = $(SSE2_EXTRA_CFLAGS) +libapplayermodes_sse4_a_SOURCES = $(libapplayermodes_sse4_a_sources) +libapplayermodes_sse4_a_CFLAGS = $(SSE4_1_EXTRA_CFLAGS) +libapplayermodes_a_SOURCES = +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(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 app/operations/layer-modes/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu app/operations/layer-modes/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): + +clean-noinstLIBRARIES: + -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES) + +libapplayermodes-generic.a: $(libapplayermodes_generic_a_OBJECTS) $(libapplayermodes_generic_a_DEPENDENCIES) $(EXTRA_libapplayermodes_generic_a_DEPENDENCIES) + $(AM_V_at)-rm -f libapplayermodes-generic.a + $(AM_V_AR)$(libapplayermodes_generic_a_AR) libapplayermodes-generic.a $(libapplayermodes_generic_a_OBJECTS) $(libapplayermodes_generic_a_LIBADD) + $(AM_V_at)$(RANLIB) libapplayermodes-generic.a + +libapplayermodes-sse2.a: $(libapplayermodes_sse2_a_OBJECTS) $(libapplayermodes_sse2_a_DEPENDENCIES) $(EXTRA_libapplayermodes_sse2_a_DEPENDENCIES) + $(AM_V_at)-rm -f libapplayermodes-sse2.a + $(AM_V_AR)$(libapplayermodes_sse2_a_AR) libapplayermodes-sse2.a $(libapplayermodes_sse2_a_OBJECTS) $(libapplayermodes_sse2_a_LIBADD) + $(AM_V_at)$(RANLIB) libapplayermodes-sse2.a + +libapplayermodes-sse4.a: $(libapplayermodes_sse4_a_OBJECTS) $(libapplayermodes_sse4_a_DEPENDENCIES) $(EXTRA_libapplayermodes_sse4_a_DEPENDENCIES) + $(AM_V_at)-rm -f libapplayermodes-sse4.a + $(AM_V_AR)$(libapplayermodes_sse4_a_AR) libapplayermodes-sse4.a $(libapplayermodes_sse4_a_OBJECTS) $(libapplayermodes_sse4_a_LIBADD) + $(AM_V_at)$(RANLIB) libapplayermodes-sse4.a + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimp-layer-modes.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationantierase.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationbehind.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationdissolve.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationerase.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationlayermode-blend.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationlayermode-composite.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationlayermode.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationmerge.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationnormal.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationpassthrough.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationreplace.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gimpoperationsplit.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.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 $@ $< + +libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.o: gimpoperationlayermode-composite-sse2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.o -MD -MP -MF $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Tpo -c -o libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.o `test -f 'gimpoperationlayermode-composite-sse2.c' || echo '$(srcdir)/'`gimpoperationlayermode-composite-sse2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Tpo $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationlayermode-composite-sse2.c' object='libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.o `test -f 'gimpoperationlayermode-composite-sse2.c' || echo '$(srcdir)/'`gimpoperationlayermode-composite-sse2.c + +libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.obj: gimpoperationlayermode-composite-sse2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.obj -MD -MP -MF $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Tpo -c -o libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.obj `if test -f 'gimpoperationlayermode-composite-sse2.c'; then $(CYGPATH_W) 'gimpoperationlayermode-composite-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationlayermode-composite-sse2.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Tpo $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationlayermode-composite-sse2.c' object='libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.obj `if test -f 'gimpoperationlayermode-composite-sse2.c'; then $(CYGPATH_W) 'gimpoperationlayermode-composite-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationlayermode-composite-sse2.c'; fi` + +libapplayermodes_sse2_a-gimpoperationnormal-sse2.o: gimpoperationnormal-sse2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse2_a-gimpoperationnormal-sse2.o -MD -MP -MF $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Tpo -c -o libapplayermodes_sse2_a-gimpoperationnormal-sse2.o `test -f 'gimpoperationnormal-sse2.c' || echo '$(srcdir)/'`gimpoperationnormal-sse2.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Tpo $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationnormal-sse2.c' object='libapplayermodes_sse2_a-gimpoperationnormal-sse2.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse2_a-gimpoperationnormal-sse2.o `test -f 'gimpoperationnormal-sse2.c' || echo '$(srcdir)/'`gimpoperationnormal-sse2.c + +libapplayermodes_sse2_a-gimpoperationnormal-sse2.obj: gimpoperationnormal-sse2.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse2_a-gimpoperationnormal-sse2.obj -MD -MP -MF $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Tpo -c -o libapplayermodes_sse2_a-gimpoperationnormal-sse2.obj `if test -f 'gimpoperationnormal-sse2.c'; then $(CYGPATH_W) 'gimpoperationnormal-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationnormal-sse2.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Tpo $(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationnormal-sse2.c' object='libapplayermodes_sse2_a-gimpoperationnormal-sse2.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse2_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse2_a-gimpoperationnormal-sse2.obj `if test -f 'gimpoperationnormal-sse2.c'; then $(CYGPATH_W) 'gimpoperationnormal-sse2.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationnormal-sse2.c'; fi` + +libapplayermodes_sse4_a-gimpoperationnormal-sse4.o: gimpoperationnormal-sse4.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse4_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse4_a-gimpoperationnormal-sse4.o -MD -MP -MF $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Tpo -c -o libapplayermodes_sse4_a-gimpoperationnormal-sse4.o `test -f 'gimpoperationnormal-sse4.c' || echo '$(srcdir)/'`gimpoperationnormal-sse4.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Tpo $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationnormal-sse4.c' object='libapplayermodes_sse4_a-gimpoperationnormal-sse4.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse4_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse4_a-gimpoperationnormal-sse4.o `test -f 'gimpoperationnormal-sse4.c' || echo '$(srcdir)/'`gimpoperationnormal-sse4.c + +libapplayermodes_sse4_a-gimpoperationnormal-sse4.obj: gimpoperationnormal-sse4.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse4_a_CFLAGS) $(CFLAGS) -MT libapplayermodes_sse4_a-gimpoperationnormal-sse4.obj -MD -MP -MF $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Tpo -c -o libapplayermodes_sse4_a-gimpoperationnormal-sse4.obj `if test -f 'gimpoperationnormal-sse4.c'; then $(CYGPATH_W) 'gimpoperationnormal-sse4.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationnormal-sse4.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Tpo $(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimpoperationnormal-sse4.c' object='libapplayermodes_sse4_a-gimpoperationnormal-sse4.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libapplayermodes_sse4_a_CFLAGS) $(CFLAGS) -c -o libapplayermodes_sse4_a-gimpoperationnormal-sse4.obj `if test -f 'gimpoperationnormal-sse4.c'; then $(CYGPATH_W) 'gimpoperationnormal-sse4.c'; else $(CYGPATH_W) '$(srcdir)/gimpoperationnormal-sse4.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +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 + +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 +check: check-am +all-am: Makefile $(LIBRARIES) +installdirs: +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: + +clean-generic: + +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-libtool clean-noinstLIBRARIES \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/gimp-layer-modes.Po + -rm -f ./$(DEPDIR)/gimpoperationantierase.Po + -rm -f ./$(DEPDIR)/gimpoperationbehind.Po + -rm -f ./$(DEPDIR)/gimpoperationdissolve.Po + -rm -f ./$(DEPDIR)/gimpoperationerase.Po + -rm -f ./$(DEPDIR)/gimpoperationlayermode-blend.Po + -rm -f ./$(DEPDIR)/gimpoperationlayermode-composite.Po + -rm -f ./$(DEPDIR)/gimpoperationlayermode.Po + -rm -f ./$(DEPDIR)/gimpoperationmerge.Po + -rm -f ./$(DEPDIR)/gimpoperationnormal.Po + -rm -f ./$(DEPDIR)/gimpoperationpassthrough.Po + -rm -f ./$(DEPDIR)/gimpoperationreplace.Po + -rm -f ./$(DEPDIR)/gimpoperationsplit.Po + -rm -f ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po + -rm -f ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po + -rm -f ./$(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.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-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +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)/gimp-layer-modes.Po + -rm -f ./$(DEPDIR)/gimpoperationantierase.Po + -rm -f ./$(DEPDIR)/gimpoperationbehind.Po + -rm -f ./$(DEPDIR)/gimpoperationdissolve.Po + -rm -f ./$(DEPDIR)/gimpoperationerase.Po + -rm -f ./$(DEPDIR)/gimpoperationlayermode-blend.Po + -rm -f ./$(DEPDIR)/gimpoperationlayermode-composite.Po + -rm -f ./$(DEPDIR)/gimpoperationlayermode.Po + -rm -f ./$(DEPDIR)/gimpoperationmerge.Po + -rm -f ./$(DEPDIR)/gimpoperationnormal.Po + -rm -f ./$(DEPDIR)/gimpoperationpassthrough.Po + -rm -f ./$(DEPDIR)/gimpoperationreplace.Po + -rm -f ./$(DEPDIR)/gimpoperationsplit.Po + -rm -f ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationlayermode-composite-sse2.Po + -rm -f ./$(DEPDIR)/libapplayermodes_sse2_a-gimpoperationnormal-sse2.Po + -rm -f ./$(DEPDIR)/libapplayermodes_sse4_a-gimpoperationnormal-sse4.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: + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-am clean \ + clean-generic clean-libtool clean-noinstLIBRARIES \ + 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-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am 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 \ + tags tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +libapplayermodes.a: libapplayermodes-generic.a \ + libapplayermodes-sse2.a \ + libapplayermodes-sse4.a + $(AR) $(ARFLAGS) libapplayermodes.a \ + $(libapplayermodes_generic_a_OBJECTS) \ + $(libapplayermodes_sse2_a_OBJECTS) \ + $(libapplayermodes_sse4_a_OBJECTS) + $(RANLIB) libapplayermodes.a + +# 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/app/operations/layer-modes/gimp-layer-modes.c b/app/operations/layer-modes/gimp-layer-modes.c new file mode 100644 index 0000000..deb1f3d --- /dev/null +++ b/app/operations/layer-modes/gimp-layer-modes.c @@ -0,0 +1,1522 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-layer-modes.c + * Copyright (C) 2017 Michael Natterer <mitch@gimp.org> + * Øyvind Kolås <pippin@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <glib-object.h> +#include <gegl.h> + +#include "../operations-types.h" + +#include "gegl/gimp-babl.h" + +#include "gimpoperationlayermode.h" +#include "gimpoperationlayermode-blend.h" + +#include "gimp-layer-modes.h" + + +typedef struct _GimpLayerModeInfo GimpLayerModeInfo; + +struct _GimpLayerModeInfo +{ + GimpLayerMode layer_mode; + const gchar *op_name; + GimpLayerModeBlendFunc blend_function; + GimpLayerModeFlags flags; + GimpLayerModeContext context; + GimpLayerCompositeMode paint_composite_mode; + GimpLayerCompositeMode composite_mode; + GimpLayerColorSpace composite_space; + GimpLayerColorSpace blend_space; +}; + + +/* static variables */ + +static const GimpLayerModeInfo layer_mode_infos[] = +{ + { GIMP_LAYER_MODE_NORMAL_LEGACY, + + .op_name = "gimp:normal", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_TRIVIAL, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_DISSOLVE, + + .op_name = "gimp:dissolve", + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_TRIVIAL, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_UNION + }, + + { GIMP_LAYER_MODE_BEHIND_LEGACY, + + .op_name = "gimp:behind", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_PAINT | + GIMP_LAYER_MODE_CONTEXT_FILTER, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_MULTIPLY_LEGACY, + + .op_name = "gimp:multiply-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_SCREEN_LEGACY, + + .op_name = "gimp:screen-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_OVERLAY_LEGACY, + + .op_name = "gimp:softlight-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_DIFFERENCE_LEGACY, + + .op_name = "gimp:difference-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_ADDITION_LEGACY, + + .op_name = "gimp:addition-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_SUBTRACT_LEGACY, + + .op_name = "gimp:subtract-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY, + + .op_name = "gimp:darken-only-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY, + + .op_name = "gimp:lighten-only-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HSV_HUE_LEGACY, + + .op_name = "gimp:hsv-hue-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HSV_SATURATION_LEGACY, + + .op_name = "gimp:hsv-saturation-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HSL_COLOR_LEGACY, + + .op_name = "gimp:hsl-color-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HSV_VALUE_LEGACY, + + .op_name = "gimp:hsv-value-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_DIVIDE_LEGACY, + + .op_name = "gimp:divide-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_DODGE_LEGACY, + + .op_name = "gimp:dodge-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_BURN_LEGACY, + + .op_name = "gimp:burn-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HARDLIGHT_LEGACY, + + .op_name = "gimp:hardlight-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_SOFTLIGHT_LEGACY, + + .op_name = "gimp:softlight-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY, + + .op_name = "gimp:grain-extract-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY, + + .op_name = "gimp:grain-merge-legacy", + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_COLOR_ERASE_LEGACY, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_color_erase, + .flags = GIMP_LAYER_MODE_FLAG_LEGACY | + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_SUBTRACTIVE, + .context = GIMP_LAYER_MODE_CONTEXT_PAINT | + GIMP_LAYER_MODE_CONTEXT_FILTER, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_OVERLAY, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_overlay, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_LCH_HUE, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_lch_hue, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_LAB + }, + + { GIMP_LAYER_MODE_LCH_CHROMA, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_lch_chroma, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_LAB + }, + + { GIMP_LAYER_MODE_LCH_COLOR, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_lch_color, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_LAB + }, + + { GIMP_LAYER_MODE_LCH_LIGHTNESS, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_lch_lightness, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_LAB + }, + + { GIMP_LAYER_MODE_NORMAL, + + .op_name = "gimp:normal", + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_TRIVIAL, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_BEHIND, + + .op_name = "gimp:behind", + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_PAINT | + GIMP_LAYER_MODE_CONTEXT_FILTER, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_MULTIPLY, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_multiply, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_SCREEN, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_screen, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_DIFFERENCE, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_difference, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_ADDITION, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_addition, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_SUBTRACT, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_subtract, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_DARKEN_ONLY, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_darken_only, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + /* no blend_space: reuse composite space, no conversion thus fewer copies */ + }, + + { GIMP_LAYER_MODE_LIGHTEN_ONLY, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_lighten_only, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + /* no blend_space: reuse composite space, no conversion thus fewer copies */ + }, + + { GIMP_LAYER_MODE_HSV_HUE, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_hsv_hue, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HSV_SATURATION, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_hsv_saturation, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HSL_COLOR, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_hsl_color, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HSV_VALUE, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_hsv_value, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_DIVIDE, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_divide, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_DODGE, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_dodge, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_BURN, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_burn, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HARDLIGHT, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_hardlight, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_SOFTLIGHT, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_softlight, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_GRAIN_EXTRACT, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_grain_extract, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_GRAIN_MERGE, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_grain_merge, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_VIVID_LIGHT, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_vivid_light, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_PIN_LIGHT, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_pin_light, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_LINEAR_LIGHT, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_linear_light, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_HARD_MIX, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_hard_mix, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_EXCLUSION, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_exclusion, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_LINEAR_BURN, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_linear_burn, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_LUMA_DARKEN_ONLY, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_luma_darken_only, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_luma_lighten_only, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL + }, + + { GIMP_LAYER_MODE_LUMINANCE, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_luminance, + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_COLOR_ERASE, + + .op_name = "gimp:layer-mode", + .blend_function = gimp_operation_layer_mode_blend_color_erase, + .flags = GIMP_LAYER_MODE_FLAG_SUBTRACTIVE, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + .blend_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_ERASE, + + .op_name = "gimp:erase", + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_SUBTRACTIVE | + GIMP_LAYER_MODE_FLAG_ALPHA_ONLY | + GIMP_LAYER_MODE_FLAG_TRIVIAL, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_MERGE, + + .op_name = "gimp:merge", + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_TRIVIAL, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_SPLIT, + + .op_name = "gimp:split", + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_SUBTRACTIVE | + GIMP_LAYER_MODE_FLAG_ALPHA_ONLY | + GIMP_LAYER_MODE_FLAG_TRIVIAL, + .context = GIMP_LAYER_MODE_CONTEXT_ALL, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, + .composite_mode = GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP + }, + + { GIMP_LAYER_MODE_PASS_THROUGH, + + .op_name = "gimp:pass-through", + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_TRIVIAL, + .context = GIMP_LAYER_MODE_CONTEXT_GROUP, + .composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_REPLACE, + + .op_name = "gimp:replace", + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_TRIVIAL, + .context = GIMP_LAYER_MODE_CONTEXT_FILTER, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_space = GIMP_LAYER_COLOR_SPACE_RGB_LINEAR + }, + + { GIMP_LAYER_MODE_ANTI_ERASE, + + .op_name = "gimp:anti-erase", + .flags = GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE | + GIMP_LAYER_MODE_FLAG_ALPHA_ONLY, + .paint_composite_mode = GIMP_LAYER_COMPOSITE_UNION, + .composite_mode = GIMP_LAYER_COMPOSITE_UNION + } +}; + +static const GimpLayerMode layer_mode_group_default[] = +{ + GIMP_LAYER_MODE_PASS_THROUGH, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_REPLACE, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_NORMAL, + GIMP_LAYER_MODE_DISSOLVE, + GIMP_LAYER_MODE_BEHIND, + GIMP_LAYER_MODE_COLOR_ERASE, + GIMP_LAYER_MODE_ERASE, + GIMP_LAYER_MODE_ANTI_ERASE, + GIMP_LAYER_MODE_MERGE, + GIMP_LAYER_MODE_SPLIT, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_LIGHTEN_ONLY, + GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY, + GIMP_LAYER_MODE_SCREEN, + GIMP_LAYER_MODE_DODGE, + GIMP_LAYER_MODE_ADDITION, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_DARKEN_ONLY, + GIMP_LAYER_MODE_LUMA_DARKEN_ONLY, + GIMP_LAYER_MODE_MULTIPLY, + GIMP_LAYER_MODE_BURN, + GIMP_LAYER_MODE_LINEAR_BURN, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_OVERLAY, + GIMP_LAYER_MODE_SOFTLIGHT, + GIMP_LAYER_MODE_HARDLIGHT, + GIMP_LAYER_MODE_VIVID_LIGHT, + GIMP_LAYER_MODE_PIN_LIGHT, + GIMP_LAYER_MODE_LINEAR_LIGHT, + GIMP_LAYER_MODE_HARD_MIX, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_DIFFERENCE, + GIMP_LAYER_MODE_EXCLUSION, + GIMP_LAYER_MODE_SUBTRACT, + GIMP_LAYER_MODE_GRAIN_EXTRACT, + GIMP_LAYER_MODE_GRAIN_MERGE, + GIMP_LAYER_MODE_DIVIDE, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_HSV_HUE, + GIMP_LAYER_MODE_HSV_SATURATION, + GIMP_LAYER_MODE_HSL_COLOR, + GIMP_LAYER_MODE_HSV_VALUE, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_LCH_HUE, + GIMP_LAYER_MODE_LCH_CHROMA, + GIMP_LAYER_MODE_LCH_COLOR, + GIMP_LAYER_MODE_LCH_LIGHTNESS, + GIMP_LAYER_MODE_LUMINANCE +}; + +static const GimpLayerMode layer_mode_group_legacy[] = +{ + GIMP_LAYER_MODE_NORMAL_LEGACY, + GIMP_LAYER_MODE_DISSOLVE, + GIMP_LAYER_MODE_BEHIND_LEGACY, + GIMP_LAYER_MODE_COLOR_ERASE_LEGACY, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY, + GIMP_LAYER_MODE_SCREEN_LEGACY, + GIMP_LAYER_MODE_DODGE_LEGACY, + GIMP_LAYER_MODE_ADDITION_LEGACY, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY, + GIMP_LAYER_MODE_MULTIPLY_LEGACY, + GIMP_LAYER_MODE_BURN_LEGACY, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_OVERLAY, + GIMP_LAYER_MODE_SOFTLIGHT_LEGACY, + GIMP_LAYER_MODE_HARDLIGHT_LEGACY, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_DIFFERENCE_LEGACY, + GIMP_LAYER_MODE_SUBTRACT_LEGACY, + GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY, + GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY, + GIMP_LAYER_MODE_DIVIDE_LEGACY, + + GIMP_LAYER_MODE_SEPARATOR, + + GIMP_LAYER_MODE_HSV_HUE_LEGACY, + GIMP_LAYER_MODE_HSV_SATURATION_LEGACY, + GIMP_LAYER_MODE_HSL_COLOR_LEGACY, + GIMP_LAYER_MODE_HSV_VALUE_LEGACY +}; + +static const GimpLayerMode layer_mode_groups[][2] = +{ + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_NORMAL, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_NORMAL_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DISSOLVE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DISSOLVE + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_BEHIND, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_BEHIND_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_MULTIPLY, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_MULTIPLY_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_SCREEN, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_SCREEN_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_OVERLAY, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DIFFERENCE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DIFFERENCE_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_ADDITION, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_ADDITION_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_SUBTRACT, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_SUBTRACT_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DARKEN_ONLY, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LIGHTEN_ONLY, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HSV_HUE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HSV_HUE_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HSV_SATURATION, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HSV_SATURATION_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HSL_COLOR, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HSL_COLOR_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HSV_VALUE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HSV_VALUE_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DIVIDE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DIVIDE_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_DODGE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_DODGE_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_BURN, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_BURN_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HARDLIGHT, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_HARDLIGHT_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_SOFTLIGHT, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_SOFTLIGHT_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_GRAIN_EXTRACT, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_GRAIN_MERGE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_COLOR_ERASE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = GIMP_LAYER_MODE_COLOR_ERASE_LEGACY, + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_VIVID_LIGHT, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_PIN_LIGHT, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LINEAR_LIGHT, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_HARD_MIX, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_EXCLUSION, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LINEAR_BURN, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LUMA_DARKEN_ONLY, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_LUMINANCE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_ERASE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_MERGE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_SPLIT, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_PASS_THROUGH, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1, + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_REPLACE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + }, + + { [GIMP_LAYER_MODE_GROUP_DEFAULT] = GIMP_LAYER_MODE_ANTI_ERASE, + [GIMP_LAYER_MODE_GROUP_LEGACY ] = -1 + } +}; + + +/* public functions */ + +void +gimp_layer_modes_init (void) +{ + gint i; + + for (i = 0; i < G_N_ELEMENTS (layer_mode_infos); i++) + { + gimp_assert ((GimpLayerMode) i == layer_mode_infos[i].layer_mode); + } +} + +static const GimpLayerModeInfo * +gimp_layer_mode_info (GimpLayerMode mode) +{ + g_return_val_if_fail (mode >= 0 && mode < G_N_ELEMENTS (layer_mode_infos), + &layer_mode_infos[0]); + + return &layer_mode_infos[mode]; +} + +gboolean +gimp_layer_mode_is_legacy (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return FALSE; + + return (info->flags & GIMP_LAYER_MODE_FLAG_LEGACY) != 0; +} + +gboolean +gimp_layer_mode_is_blend_space_mutable (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return FALSE; + + return (info->flags & GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE) == 0; +} + +gboolean +gimp_layer_mode_is_composite_space_mutable (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return FALSE; + + return (info->flags & GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE) == 0; +} + +gboolean +gimp_layer_mode_is_composite_mode_mutable (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return FALSE; + + return (info->flags & GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE) == 0; +} + +gboolean +gimp_layer_mode_is_subtractive (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return FALSE; + + return (info->flags & GIMP_LAYER_MODE_FLAG_SUBTRACTIVE) != 0; +} + +gboolean +gimp_layer_mode_is_alpha_only (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return FALSE; + + return (info->flags & GIMP_LAYER_MODE_FLAG_ALPHA_ONLY) != 0; +} + +gboolean +gimp_layer_mode_is_trivial (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return FALSE; + + return (info->flags & GIMP_LAYER_MODE_FLAG_TRIVIAL) != 0; +} + +GimpLayerColorSpace +gimp_layer_mode_get_blend_space (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return GIMP_LAYER_COLOR_SPACE_RGB_LINEAR; + + return info->blend_space; +} + +GimpLayerColorSpace +gimp_layer_mode_get_composite_space (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return GIMP_LAYER_COLOR_SPACE_RGB_LINEAR; + + return info->composite_space; +} + +GimpLayerCompositeMode +gimp_layer_mode_get_composite_mode (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return GIMP_LAYER_COMPOSITE_UNION; + + return info->composite_mode; +} + +GimpLayerCompositeMode +gimp_layer_mode_get_paint_composite_mode (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return GIMP_LAYER_COMPOSITE_UNION; + + return info->paint_composite_mode; +} + +const gchar * +gimp_layer_mode_get_operation (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return "gimp:layer-mode"; + + return info->op_name; +} + +GimpLayerModeFunc +gimp_layer_mode_get_function (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + static GimpLayerModeFunc funcs[G_N_ELEMENTS (layer_mode_infos)]; + + if (! info) + info = layer_mode_infos; + + mode = info - layer_mode_infos; + + if (! funcs[mode]) + { + GeglNode *node; + GeglOperation *operation; + + node = gegl_node_new_child (NULL, + "operation", info->op_name, + NULL); + + operation = gegl_node_get_gegl_operation (node); + + funcs[mode] = GIMP_OPERATION_LAYER_MODE_GET_CLASS (operation)->process; + + g_object_unref (node); + } + + return funcs[mode]; +} + +GimpLayerModeBlendFunc +gimp_layer_mode_get_blend_function (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return NULL; + + return info->blend_function; +} + +GimpLayerModeContext +gimp_layer_mode_get_context (GimpLayerMode mode) +{ + const GimpLayerModeInfo *info = gimp_layer_mode_info (mode); + + if (! info) + return 0; + + return info->context; +} + +GimpLayerMode * +gimp_layer_mode_get_context_array (GimpLayerMode mode, + GimpLayerModeContext context, + gint *n_modes) +{ + GimpLayerModeGroup group; + const GimpLayerMode *group_modes; + gint n_group_modes; + GimpLayerMode *array; + gint i; + + group = gimp_layer_mode_get_group (mode); + + group_modes = gimp_layer_mode_get_group_array (group, &n_group_modes); + + array = g_new0 (GimpLayerMode, n_group_modes); + *n_modes = 0; + + for (i = 0; i < n_group_modes; i++) + { + if (group_modes[i] != GIMP_LAYER_MODE_SEPARATOR && + (gimp_layer_mode_get_context (group_modes[i]) & context)) + { + array[*n_modes] = group_modes[i]; + (*n_modes)++; + } + } + + return array; +} + +static gboolean +is_mode_in_array (const GimpLayerMode *modes, + gint n_modes, + GimpLayerMode mode) +{ + gint i; + + for (i = 0; i < n_modes; i++) + { + if (modes[i] == mode) + return TRUE; + } + + return FALSE; +} + +GimpLayerModeGroup +gimp_layer_mode_get_group (GimpLayerMode mode) +{ + if (is_mode_in_array (layer_mode_group_default, + G_N_ELEMENTS (layer_mode_group_default), mode)) + { + return GIMP_LAYER_MODE_GROUP_DEFAULT; + } + else if (is_mode_in_array (layer_mode_group_legacy, + G_N_ELEMENTS (layer_mode_group_legacy), mode)) + { + return GIMP_LAYER_MODE_GROUP_LEGACY; + } + + return GIMP_LAYER_MODE_GROUP_DEFAULT; +} + +const GimpLayerMode * +gimp_layer_mode_get_group_array (GimpLayerModeGroup group, + gint *n_modes) +{ + g_return_val_if_fail (n_modes != NULL, NULL); + + switch (group) + { + case GIMP_LAYER_MODE_GROUP_DEFAULT: + *n_modes = G_N_ELEMENTS (layer_mode_group_default); + return layer_mode_group_default; + + case GIMP_LAYER_MODE_GROUP_LEGACY: + *n_modes = G_N_ELEMENTS (layer_mode_group_legacy); + return layer_mode_group_legacy; + + default: + g_return_val_if_reached (NULL); + } +} + +gboolean +gimp_layer_mode_get_for_group (GimpLayerMode old_mode, + GimpLayerModeGroup new_group, + GimpLayerMode *new_mode) +{ + gint i; + + g_return_val_if_fail (new_mode != NULL, FALSE); + + for (i = 0; i < G_N_ELEMENTS (layer_mode_groups); i++) + { + if (is_mode_in_array (layer_mode_groups[i], 2, old_mode)) + { + *new_mode = layer_mode_groups[i][new_group]; + + if (*new_mode != -1) + return TRUE; + + return FALSE; + } + } + + *new_mode = -1; + + return FALSE; +} + +const Babl * +gimp_layer_mode_get_format (GimpLayerMode mode, + GimpLayerColorSpace blend_space, + GimpLayerColorSpace composite_space, + GimpLayerCompositeMode composite_mode, + const Babl *preferred_format) +{ + GimpLayerCompositeRegion composite_region; + + /* for now, all modes perform i/o in the composite space. */ + (void) mode; + (void) blend_space; + + if (composite_space == GIMP_LAYER_COLOR_SPACE_AUTO) + composite_space = gimp_layer_mode_get_composite_space (mode); + + if (composite_mode == GIMP_LAYER_COMPOSITE_AUTO) + composite_mode = gimp_layer_mode_get_composite_mode (mode); + + composite_region = gimp_layer_mode_get_included_region (mode, composite_mode); + + if (gimp_layer_mode_is_alpha_only (mode)) + { + if (composite_region != GIMP_LAYER_COMPOSITE_REGION_UNION) + { + /* alpha-only layer modes don't combine colors in non-union composite + * modes, hence we can disregard the composite space. + */ + composite_space = GIMP_LAYER_COLOR_SPACE_AUTO; + } + } + else if (gimp_layer_mode_is_trivial (mode)) + { + if (! (composite_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION)) + { + /* trivial layer modes don't combine colors when only the source + * region is included, hence we can disregard the composite space. + */ + composite_space = GIMP_LAYER_COLOR_SPACE_AUTO; + } + } + + switch (composite_space) + { + case GIMP_LAYER_COLOR_SPACE_AUTO: + /* compositing is color-space agnostic. return a format that has a fast + * conversion path to/from the preferred format. + */ + if (! preferred_format || gimp_babl_format_get_linear (preferred_format)) + return babl_format ("RGBA float"); + else + return babl_format ("R'G'B'A float"); + + case GIMP_LAYER_COLOR_SPACE_RGB_LINEAR: + return babl_format ("RGBA float"); + + case GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL: + return babl_format ("R'G'B'A float"); + + case GIMP_LAYER_COLOR_SPACE_LAB: + return babl_format ("CIE Lab alpha float"); + } + + g_return_val_if_reached (babl_format ("RGBA float")); +} + +GimpLayerCompositeRegion +gimp_layer_mode_get_included_region (GimpLayerMode mode, + GimpLayerCompositeMode composite_mode) +{ + if (composite_mode == GIMP_LAYER_COMPOSITE_AUTO) + composite_mode = gimp_layer_mode_get_composite_mode (mode); + + switch (composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + return GIMP_LAYER_COMPOSITE_REGION_UNION; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + return GIMP_LAYER_COMPOSITE_REGION_DESTINATION; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + return GIMP_LAYER_COMPOSITE_REGION_SOURCE; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + return GIMP_LAYER_COMPOSITE_REGION_INTERSECTION; + + default: + g_return_val_if_reached (GIMP_LAYER_COMPOSITE_REGION_INTERSECTION); + } +} diff --git a/app/operations/layer-modes/gimp-layer-modes.h b/app/operations/layer-modes/gimp-layer-modes.h new file mode 100644 index 0000000..30c5e15 --- /dev/null +++ b/app/operations/layer-modes/gimp-layer-modes.h @@ -0,0 +1,73 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimp-layer-modes.h + * Copyright (C) 2017 Michael Natterer <mitch@gimp.org> + * Øyvind Kolås <pippin@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_LAYER_MODES_H__ +#define __GIMP_LAYER_MODES_H__ + + +void gimp_layer_modes_init (void); + +gboolean gimp_layer_mode_is_legacy (GimpLayerMode mode); + +gboolean gimp_layer_mode_is_blend_space_mutable (GimpLayerMode mode); +gboolean gimp_layer_mode_is_composite_space_mutable (GimpLayerMode mode); +gboolean gimp_layer_mode_is_composite_mode_mutable (GimpLayerMode mode); + +gboolean gimp_layer_mode_is_subtractive (GimpLayerMode mode); +gboolean gimp_layer_mode_is_alpha_only (GimpLayerMode mode); +gboolean gimp_layer_mode_is_trivial (GimpLayerMode mode); + +GimpLayerColorSpace gimp_layer_mode_get_blend_space (GimpLayerMode mode); +GimpLayerColorSpace gimp_layer_mode_get_composite_space (GimpLayerMode mode); +GimpLayerCompositeMode gimp_layer_mode_get_composite_mode (GimpLayerMode mode); +GimpLayerCompositeMode gimp_layer_mode_get_paint_composite_mode (GimpLayerMode mode); + +const gchar * gimp_layer_mode_get_operation (GimpLayerMode mode); + +GimpLayerModeFunc gimp_layer_mode_get_function (GimpLayerMode mode); +GimpLayerModeBlendFunc gimp_layer_mode_get_blend_function (GimpLayerMode mode); + +GimpLayerModeContext gimp_layer_mode_get_context (GimpLayerMode mode); + +GimpLayerMode * gimp_layer_mode_get_context_array (GimpLayerMode mode, + GimpLayerModeContext context, + gint *n_modes); + +GimpLayerModeGroup gimp_layer_mode_get_group (GimpLayerMode mode); + +const GimpLayerMode * gimp_layer_mode_get_group_array (GimpLayerModeGroup group, + gint *n_modes); + +gboolean gimp_layer_mode_get_for_group (GimpLayerMode old_mode, + GimpLayerModeGroup new_group, + GimpLayerMode *new_mode); + +const Babl * gimp_layer_mode_get_format (GimpLayerMode mode, + GimpLayerColorSpace blend_space, + GimpLayerColorSpace composite_space, + GimpLayerCompositeMode composite_mode, + const Babl *preferred_format); + +GimpLayerCompositeRegion gimp_layer_mode_get_included_region (GimpLayerMode mode, + GimpLayerCompositeMode composite_mode); + + +#endif /* __GIMP_LAYER_MODES_H__ */ diff --git a/app/operations/layer-modes/gimpoperationantierase.c b/app/operations/layer-modes/gimpoperationantierase.c new file mode 100644 index 0000000..3fb2947 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationantierase.c @@ -0,0 +1,188 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationantierase.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationantierase.h" + + + +static gboolean gimp_operation_anti_erase_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); +static GimpLayerCompositeRegion gimp_operation_anti_erase_get_affected_region (GimpOperationLayerMode *layer_mode); + + +G_DEFINE_TYPE (GimpOperationAntiErase, gimp_operation_anti_erase, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_anti_erase_class_init (GimpOperationAntiEraseClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:anti-erase", + "description", "GIMP anti erase mode operation", + NULL); + + layer_mode_class->process = gimp_operation_anti_erase_process; + layer_mode_class->get_affected_region = gimp_operation_anti_erase_get_affected_region; +} + +static void +gimp_operation_anti_erase_init (GimpOperationAntiErase *self) +{ +} + +static gboolean +gimp_operation_anti_erase_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + const gboolean has_mask = mask != NULL; + + switch (layer_mode->composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) + { + gfloat value = opacity; + gint b; + + if (has_mask) + value *= *mask; + + out[ALPHA] = in[ALPHA] + (1.0 - in[ALPHA]) * layer[ALPHA] * value; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + while (samples--) + { + gint b; + + out[ALPHA] = in[ALPHA]; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + + in += 4; + out += 4; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + while (samples--) + { + gfloat value = opacity; + gint b; + + if (has_mask) + value *= *mask; + + out[ALPHA] = layer[ALPHA] * value; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + while (samples--) + { + gfloat value = opacity; + gint b; + + if (has_mask) + value *= *mask; + + out[ALPHA] = in[ALPHA] * layer[ALPHA] * value; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + } + + return TRUE; +} + +static GimpLayerCompositeRegion +gimp_operation_anti_erase_get_affected_region (GimpOperationLayerMode *layer_mode) +{ + return GIMP_LAYER_COMPOSITE_REGION_SOURCE; +} diff --git a/app/operations/layer-modes/gimpoperationantierase.h b/app/operations/layer-modes/gimpoperationantierase.h new file mode 100644 index 0000000..0c5ddf8 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationantierase.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationantierase.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_ANTI_ERASE_H__ +#define __GIMP_OPERATION_ANTI_ERASE_H__ + + +#include "gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_ANTI_ERASE (gimp_operation_anti_erase_get_type ()) +#define GIMP_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_ANTI_ERASE, GimpOperationAntiErase)) +#define GIMP_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_ANTI_ERASE, GimpOperationAntiEraseClass)) +#define GIMP_IS_OPERATION_ANTI_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_ANTI_ERASE)) +#define GIMP_IS_OPERATION_ANTI_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_ANTI_ERASE)) +#define GIMP_OPERATION_ANTI_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_ANTI_ERASE, GimpOperationAntiEraseClass)) + + +typedef struct _GimpOperationAntiErase GimpOperationAntiErase; +typedef struct _GimpOperationAntiEraseClass GimpOperationAntiEraseClass; + +struct _GimpOperationAntiErase +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationAntiEraseClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_anti_erase_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_ANTI_ERASE_H__ */ diff --git a/app/operations/layer-modes/gimpoperationbehind.c b/app/operations/layer-modes/gimpoperationbehind.c new file mode 100644 index 0000000..1dc2630 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationbehind.c @@ -0,0 +1,236 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationbehind.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationbehind.h" + + + +static gboolean gimp_operation_behind_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationBehind, gimp_operation_behind, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_behind_class_init (GimpOperationBehindClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:behind", + "description", "GIMP behind mode operation", + NULL); + + layer_mode_class->process = gimp_operation_behind_process; +} + +static void +gimp_operation_behind_init (GimpOperationBehind *self) +{ +} + +static gboolean +gimp_operation_behind_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + const gboolean has_mask = mask != NULL; + + switch (layer_mode->composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) + { + gfloat src1_alpha = in[ALPHA]; + gfloat src2_alpha = layer[ALPHA] * opacity; + gfloat new_alpha; + gint b; + + if (has_mask) + src2_alpha *= *mask; + + new_alpha = src2_alpha + (1.0 - src2_alpha) * src1_alpha; + + if (new_alpha) + { + gfloat ratio = in[ALPHA] / new_alpha; + gfloat compl_ratio = 1.0f - ratio; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b] * ratio + layer[b] * compl_ratio; + } + } + else + { + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + while (samples--) + { + gfloat src1_alpha = in[ALPHA]; + gfloat new_alpha; + gint b; + + new_alpha = src1_alpha; + + if (new_alpha) + { + for (b = RED; b < ALPHA; b++) + out[b] = in[b]; + } + else + { + for (b = RED; b < ALPHA; b++) + out[b] = layer[b]; + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + while (samples--) + { + gfloat src1_alpha = in[ALPHA]; + gfloat src2_alpha = layer[ALPHA] * opacity; + gfloat new_alpha; + gint b; + + if (has_mask) + src2_alpha *= *mask; + + new_alpha = src2_alpha; + + if (new_alpha) + { + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b] + (in[b] - layer[b]) * src1_alpha; + } + } + else + { + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + while (samples--) + { + gfloat src1_alpha = in[ALPHA]; + gfloat src2_alpha = layer[ALPHA] * opacity; + gfloat new_alpha; + gint b; + + if (has_mask) + src2_alpha *= *mask; + + new_alpha = src1_alpha * src2_alpha; + + if (new_alpha) + { + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + else + { + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + } + + return TRUE; +} diff --git a/app/operations/layer-modes/gimpoperationbehind.h b/app/operations/layer-modes/gimpoperationbehind.h new file mode 100644 index 0000000..46b9ac4 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationbehind.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationbehind.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_BEHIND_H__ +#define __GIMP_OPERATION_BEHIND_H__ + + +#include "gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_BEHIND (gimp_operation_behind_get_type ()) +#define GIMP_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_BEHIND, GimpOperationBehind)) +#define GIMP_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_BEHIND, GimpOperationBehindClass)) +#define GIMP_IS_OPERATION_BEHIND(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_BEHIND)) +#define GIMP_IS_OPERATION_BEHIND_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_BEHIND)) +#define GIMP_OPERATION_BEHIND_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_BEHIND, GimpOperationBehindClass)) + + +typedef struct _GimpOperationBehind GimpOperationBehind; +typedef struct _GimpOperationBehindClass GimpOperationBehindClass; + +struct _GimpOperationBehind +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationBehindClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_behind_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_BEHIND_H__ */ diff --git a/app/operations/layer-modes/gimpoperationdissolve.c b/app/operations/layer-modes/gimpoperationdissolve.c new file mode 100644 index 0000000..fb4b1d0 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationdissolve.c @@ -0,0 +1,175 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdissolve.c + * Copyright (C) 2012 Ville Sokk <ville.sokk@gmail.com> + * 2012 Øyvind Kolås <pippin@gimp.org> + * 2003 Helvetix Victorinox + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationdissolve.h" + + +#define RANDOM_TABLE_SIZE 4096 + + +static gboolean gimp_operation_dissolve_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *result, + gint level); +static GimpLayerCompositeRegion gimp_operation_dissolve_get_affected_region (GimpOperationLayerMode *layer_mode); + + +G_DEFINE_TYPE (GimpOperationDissolve, gimp_operation_dissolve, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static gint32 random_table[RANDOM_TABLE_SIZE]; + + +static void +gimp_operation_dissolve_class_init (GimpOperationDissolveClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + GRand *gr; + gint i; + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:dissolve", + "description", "GIMP dissolve mode operation", + "categories", "compositors", + NULL); + + layer_mode_class->process = gimp_operation_dissolve_process; + layer_mode_class->get_affected_region = gimp_operation_dissolve_get_affected_region; + + /* generate a table of random seeds */ + gr = g_rand_new_with_seed (314159265); + for (i = 0; i < RANDOM_TABLE_SIZE; i++) + random_table[i] = g_rand_int (gr); + + g_rand_free (gr); +} + +static void +gimp_operation_dissolve_init (GimpOperationDissolve *self) +{ +} + +static gboolean +gimp_operation_dissolve_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *result, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + const gboolean has_mask = mask != NULL; + gint x, y; + + for (y = result->y; y < result->y + result->height; y++) + { + GRand *gr; + + /* The offset can be negative. I could just abs() the result, but we + * probably prefer to use different indexes of the table when possible for + * nicer randomization, so let's cycle the modulo so that -1 is the last + * table index. + */ + gr = g_rand_new_with_seed (random_table[((y % RANDOM_TABLE_SIZE) + RANDOM_TABLE_SIZE) % RANDOM_TABLE_SIZE]); + + /* fast forward through the rows pseudo random sequence */ + for (x = 0; x < result->x; x++) + g_rand_int (gr); + + for (x = result->x; x < result->x + result->width; x++) + { + gfloat value = layer[ALPHA] * opacity * 255; + + if (has_mask) + value *= *mask; + + if (g_rand_int_range (gr, 0, 255) >= value) + { + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; + + if (layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_UNION || + layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP) + { + out[3] = in[3]; + } + else + { + out[3] = 0.0f; + } + } + else + { + out[0] = layer[0]; + out[1] = layer[1]; + out[2] = layer[2]; + + if (layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_UNION || + layer_mode->composite_mode == GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER) + { + out[3] = 1.0f; + } + else + { + out[3] = in[3]; + } + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + + g_rand_free (gr); + } + + return TRUE; +} + +static GimpLayerCompositeRegion +gimp_operation_dissolve_get_affected_region (GimpOperationLayerMode *layer_mode) +{ + return GIMP_LAYER_COMPOSITE_REGION_SOURCE; +} diff --git a/app/operations/layer-modes/gimpoperationdissolve.h b/app/operations/layer-modes/gimpoperationdissolve.h new file mode 100644 index 0000000..d448918 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationdissolve.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationdissolve.h + * Copyright (C) 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_DISSOLVE_H__ +#define __GIMP_OPERATION_DISSOLVE_H__ + + +#include "gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_DISSOLVE (gimp_operation_dissolve_get_type ()) +#define GIMP_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_DISSOLVE, GimpOperationDissolve)) +#define GIMP_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_DISSOLVE, GimpOperationDissolveClass)) +#define GIMP_IS_OPERATION_DISSOLVE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_DISSOLVE)) +#define GIMP_IS_OPERATION_DISSOLVE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_DISSOLVE)) +#define GIMP_OPERATION_DISSOLVE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_DISSOLVE, GimpOperationDissolveClass)) + + +typedef struct _GimpOperationDissolve GimpOperationDissolve; +typedef struct _GimpOperationDissolveClass GimpOperationDissolveClass; + +struct _GimpOperationDissolveClass +{ + GimpOperationLayerModeClass parent_class; +}; + +struct _GimpOperationDissolve +{ + GimpOperationLayerMode parent_instance; +}; + + +GType gimp_operation_dissolve_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_DISSOLVE_H__ */ diff --git a/app/operations/layer-modes/gimpoperationerase.c b/app/operations/layer-modes/gimpoperationerase.c new file mode 100644 index 0000000..aae6eac --- /dev/null +++ b/app/operations/layer-modes/gimpoperationerase.c @@ -0,0 +1,214 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationerase.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2012 Ville Sokk <ville.sokk@gmail.com> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationerase.h" + + +static gboolean gimp_operation_erase_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationErase, gimp_operation_erase, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_erase_class_init (GimpOperationEraseClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:erase", + "description", "GIMP erase mode operation", + NULL); + + layer_mode_class->process = gimp_operation_erase_process; +} + +static void +gimp_operation_erase_init (GimpOperationErase *self) +{ +} + +static gboolean +gimp_operation_erase_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + const gboolean has_mask = mask != NULL; + + switch (layer_mode->composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + while (samples--) + { + gfloat layer_alpha; + gfloat new_alpha; + gint b; + + layer_alpha = layer[ALPHA] * opacity; + + if (has_mask) + layer_alpha *= (*mask); + + new_alpha = in[ALPHA] + layer_alpha - 2.0f * in[ALPHA] * layer_alpha; + + if (new_alpha != 0.0f) + { + gfloat ratio; + + ratio = (1.0f - in[ALPHA]) * layer_alpha / new_alpha; + + for (b = RED; b < ALPHA; b++) + { + out[b] = ratio * layer[b] + (1.0f - ratio) * in[b]; + } + } + else + { + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask ++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) + { + gfloat layer_alpha; + gfloat new_alpha; + gint b; + + layer_alpha = layer[ALPHA] * opacity; + + if (has_mask) + layer_alpha *= (*mask); + + new_alpha = (1.0f - layer_alpha) * in[ALPHA]; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask ++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + while (samples--) + { + gfloat layer_alpha; + gfloat new_alpha; + const gfloat *src; + gint b; + + layer_alpha = layer[ALPHA] * opacity; + + if (has_mask) + layer_alpha *= (*mask); + + new_alpha = (1.0f - in[ALPHA]) * layer_alpha; + + src = layer; + + if (new_alpha == 0.0f) + src = in; + + for (b = RED; b < ALPHA; b++) + { + out[b] = src[b]; + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask ++; + } + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + while (samples--) + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + + out[ALPHA] = 0.0f; + + in += 4; + out += 4; + } + break; + } + + return TRUE; +} diff --git a/app/operations/layer-modes/gimpoperationerase.h b/app/operations/layer-modes/gimpoperationerase.h new file mode 100644 index 0000000..fec309b --- /dev/null +++ b/app/operations/layer-modes/gimpoperationerase.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationerase.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_ERASE_H__ +#define __GIMP_OPERATION_ERASE_H__ + + +#include "gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_ERASE (gimp_operation_erase_get_type ()) +#define GIMP_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_ERASE, GimpOperationErase)) +#define GIMP_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_ERASE, GimpOperationEraseClass)) +#define GIMP_IS_OPERATION_ERASE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_ERASE)) +#define GIMP_IS_OPERATION_ERASE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_ERASE)) +#define GIMP_OPERATION_ERASE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_ERASE, GimpOperationEraseClass)) + + +typedef struct _GimpOperationErase GimpOperationErase; +typedef struct _GimpOperationEraseClass GimpOperationEraseClass; + +struct _GimpOperationErase +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationEraseClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_erase_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_ERASE_MODE_H__ */ diff --git a/app/operations/layer-modes/gimpoperationlayermode-blend.c b/app/operations/layer-modes/gimpoperationlayermode-blend.c new file mode 100644 index 0000000..e107462 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationlayermode-blend.c @@ -0,0 +1,1215 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlayermode-blend.c + * Copyright (C) 2017 Michael Natterer <mitch@gimp.org> + * 2017 Øyvind Kolås <pippin@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpcolor/gimpcolor.h" +#include "libgimpbase/gimpbase.h" +#include "libgimpmath/gimpmath.h" + +#include "../operations-types.h" + +#include "gimpoperationlayermode-blend.h" + + +#define EPSILON 1e-6f + +#define SAFE_DIV_MIN EPSILON +#define SAFE_DIV_MAX (1.0f / SAFE_DIV_MIN) + + +/* local function prototypes */ + +static inline gfloat safe_div (gfloat a, + gfloat b); + + +/* private functions */ + + +/* returns a / b, clamped to [-SAFE_DIV_MAX, SAFE_DIV_MAX]. + * if -SAFE_DIV_MIN <= a <= SAFE_DIV_MIN, returns 0. + */ +static inline gfloat +safe_div (gfloat a, + gfloat b) +{ + gfloat result = 0.0f; + + if (fabsf (a) > SAFE_DIV_MIN) + { + result = a / b; + result = CLAMP (result, -SAFE_DIV_MAX, SAFE_DIV_MAX); + } + + return result; +} + + +/* public functions */ + + +/* non-subtractive blending functions. these functions must set comp[ALPHA] + * to the same value as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are + * zero, the value of comp[RED..BLUE] is unconstrained (in particular, it may + * be NaN). + */ + + +void /* aka linear_dodge */ +gimp_operation_layer_mode_blend_addition (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = in[c] + layer[c]; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_burn (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = 1.0f - safe_div (1.0f - in[c], layer[c]); + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_darken_only (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = MIN (in[c], layer[c]); + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_difference (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = fabsf (in[c] - layer[c]); + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_divide (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = safe_div (in[c], layer[c]); + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_dodge (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = safe_div (in[c], 1.0f - layer[c]); + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_exclusion (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = 0.5f - 2.0f * (in[c] - 0.5f) * (layer[c] - 0.5f); + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_grain_extract (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = in[c] - layer[c] + 0.5f; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_grain_merge (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = in[c] + layer[c] - 0.5f; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_hard_mix (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = in[c] + layer[c] < 1.0f ? 0.0f : 1.0f; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_hardlight (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + { + gfloat val; + + if (layer[c] > 0.5f) + { + val = (1.0f - in[c]) * (1.0f - (layer[c] - 0.5f) * 2.0f); + val = MIN (1.0f - val, 1.0f); + } + else + { + val = in[c] * (layer[c] * 2.0f); + val = MIN (val, 1.0f); + } + + comp[c] = val; + } + } + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_hsl_color (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gfloat dest_min, dest_max, dest_l; + gfloat src_min, src_max, src_l; + + dest_min = MIN (in[0], in[1]); + dest_min = MIN (dest_min, in[2]); + dest_max = MAX (in[0], in[1]); + dest_max = MAX (dest_max, in[2]); + dest_l = (dest_min + dest_max) / 2.0f; + + src_min = MIN (layer[0], layer[1]); + src_min = MIN (src_min, layer[2]); + src_max = MAX (layer[0], layer[1]); + src_max = MAX (src_max, layer[2]); + src_l = (src_min + src_max) / 2.0f; + + if (fabs (src_l) > EPSILON && fabs (1.0 - src_l) > EPSILON) + { + gboolean dest_high; + gboolean src_high; + gfloat ratio; + gfloat offset; + gint c; + + dest_high = dest_l > 0.5f; + src_high = src_l > 0.5f; + + dest_l = MIN (dest_l, 1.0f - dest_l); + src_l = MIN (src_l, 1.0f - src_l); + + ratio = dest_l / src_l; + + offset = 0.0f; + if (dest_high) offset += 1.0f - 2.0f * dest_l; + if (src_high) offset += 2.0f * dest_l - ratio; + + for (c = 0; c < 3; c++) + comp[c] = layer[c] * ratio + offset; + } + else + { + comp[RED] = dest_l; + comp[GREEN] = dest_l; + comp[BLUE] = dest_l; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_hsv_hue (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gfloat src_min, src_max, src_delta; + gfloat dest_min, dest_max, dest_delta, dest_s; + + src_min = MIN (layer[0], layer[1]); + src_min = MIN (src_min, layer[2]); + src_max = MAX (layer[0], layer[1]); + src_max = MAX (src_max, layer[2]); + src_delta = src_max - src_min; + + if (src_delta > EPSILON) + { + gfloat ratio; + gfloat offset; + gint c; + + dest_min = MIN (in[0], in[1]); + dest_min = MIN (dest_min, in[2]); + dest_max = MAX (in[0], in[1]); + dest_max = MAX (dest_max, in[2]); + dest_delta = dest_max - dest_min; + dest_s = dest_max ? dest_delta / dest_max : 0.0f; + + ratio = dest_s * dest_max / src_delta; + offset = dest_max - src_max * ratio; + + for (c = 0; c < 3; c++) + comp[c] = layer[c] * ratio + offset; + } + else + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = in[c]; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_hsv_saturation (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gfloat src_min, src_max, src_delta, src_s; + gfloat dest_min, dest_max, dest_delta; + + dest_min = MIN (in[0], in[1]); + dest_min = MIN (dest_min, in[2]); + dest_max = MAX (in[0], in[1]); + dest_max = MAX (dest_max, in[2]); + dest_delta = dest_max - dest_min; + + if (dest_delta > EPSILON) + { + gfloat ratio; + gfloat offset; + gint c; + + src_min = MIN (layer[0], layer[1]); + src_min = MIN (src_min, layer[2]); + src_max = MAX (layer[0], layer[1]); + src_max = MAX (src_max, layer[2]); + src_delta = src_max - src_min; + src_s = src_max ? src_delta / src_max : 0.0f; + + ratio = src_s * dest_max / dest_delta; + offset = (1.0f - ratio) * dest_max; + + for (c = 0; c < 3; c++) + comp[c] = in[c] * ratio + offset; + } + else + { + comp[RED] = dest_max; + comp[GREEN] = dest_max; + comp[BLUE] = dest_max; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_hsv_value (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gfloat dest_v; + gfloat src_v; + + dest_v = MAX (in[0], in[1]); + dest_v = MAX (dest_v, in[2]); + + src_v = MAX (layer[0], layer[1]); + src_v = MAX (src_v, layer[2]); + + if (fabs (dest_v) > EPSILON) + { + gfloat ratio = src_v / dest_v; + gint c; + + for (c = 0; c < 3; c++) + comp[c] = in[c] * ratio; + } + else + { + comp[RED] = src_v; + comp[GREEN] = src_v; + comp[BLUE] = src_v; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_lch_chroma (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gfloat A1 = in[1]; + gfloat B1 = in[2]; + gfloat c1 = hypotf (A1, B1); + + if (c1 > EPSILON) + { + gfloat A2 = layer[1]; + gfloat B2 = layer[2]; + gfloat c2 = hypotf (A2, B2); + gfloat A = c2 * A1 / c1; + gfloat B = c2 * B1 / c1; + + comp[0] = in[0]; + comp[1] = A; + comp[2] = B; + } + else + { + comp[0] = in[0]; + comp[1] = in[1]; + comp[2] = in[2]; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_lch_color (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + comp[0] = in[0]; + comp[1] = layer[1]; + comp[2] = layer[2]; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_lch_hue (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gfloat A2 = layer[1]; + gfloat B2 = layer[2]; + gfloat c2 = hypotf (A2, B2); + + if (c2 > EPSILON) + { + gfloat A1 = in[1]; + gfloat B1 = in[2]; + gfloat c1 = hypotf (A1, B1); + gfloat A = c1 * A2 / c2; + gfloat B = c1 * B2 / c2; + + comp[0] = in[0]; + comp[1] = A; + comp[2] = B; + } + else + { + comp[0] = in[0]; + comp[1] = in[1]; + comp[2] = in[2]; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_lch_lightness (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + comp[0] = layer[0]; + comp[1] = in[1]; + comp[2] = in[2]; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_lighten_only (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = MAX (in[c], layer[c]); + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_linear_burn (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = in[c] + layer[c] - 1.0f; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +/* added according to: + http://www.deepskycolors.com/archivo/2010/04/21/formulas-for-Photoshop-blending-modes.html */ +void +gimp_operation_layer_mode_blend_linear_light (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + { + gfloat val; + + if (layer[c] <= 0.5f) + val = in[c] + 2.0f * layer[c] - 1.0f; + else + val = in[c] + 2.0f * (layer[c] - 0.5f); + + comp[c] = val; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_luma_darken_only (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gfloat dest_luminance; + gfloat src_luminance; + gint c; + + dest_luminance = GIMP_RGB_LUMINANCE (in[0], in[1], in[2]); + src_luminance = GIMP_RGB_LUMINANCE (layer[0], layer[1], layer[2]); + + if (dest_luminance <= src_luminance) + { + for (c = 0; c < 3; c++) + comp[c] = in[c]; + } + else + { + for (c = 0; c < 3; c++) + comp[c] = layer[c]; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_luma_lighten_only (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gfloat dest_luminance; + gfloat src_luminance; + gint c; + + dest_luminance = GIMP_RGB_LUMINANCE (in[0], in[1], in[2]); + src_luminance = GIMP_RGB_LUMINANCE (layer[0], layer[1], layer[2]); + + if (dest_luminance >= src_luminance) + { + for (c = 0; c < 3; c++) + comp[c] = in[c]; + } + else + { + for (c = 0; c < 3; c++) + comp[c] = layer[c]; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_luminance (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + static const Babl *fish; + gfloat *scratch; + gfloat *in_Y; + gfloat *layer_Y; + + if (! fish) + fish = babl_fish ("RGBA float", "Y float"); + + scratch = gegl_scratch_new (gfloat, 2 * samples); + + in_Y = scratch; + layer_Y = scratch + samples; + + babl_process (fish, in, in_Y, samples); + babl_process (fish, layer, layer_Y, samples); + + while (samples--) + { + if (layer[ALPHA] != 0.0f && in[ALPHA] != 0.0f) + { + gfloat ratio = safe_div (layer_Y[0], in_Y[0]); + gint c; + + for (c = 0; c < 3; c ++) + comp[c] = in[c] * ratio; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + in += 4; + layer += 4; + in_Y ++; + layer_Y ++; + } + + gegl_scratch_free (scratch); +} + +void +gimp_operation_layer_mode_blend_multiply (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = in[c] * layer[c]; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_overlay (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + { + gfloat val; + + if (in[c] < 0.5f) + val = 2.0f * in[c] * layer[c]; + else + val = 1.0f - 2.0f * (1.0f - layer[c]) * (1.0f - in[c]); + + comp[c] = val; + } + } + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +/* added according to: + http://www.deepskycolors.com/archivo/2010/04/21/formulas-for-Photoshop-blending-modes.html */ +void +gimp_operation_layer_mode_blend_pin_light (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + { + gfloat val; + + if (layer[c] > 0.5f) + val = MAX(in[c], 2.0f * (layer[c] - 0.5f)); + else + val = MIN(in[c], 2.0f * layer[c]); + + comp[c] = val; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_screen (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = 1.0f - (1.0f - in[c]) * (1.0f - layer[c]); + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_softlight (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + { + gfloat multiply = in[c] * layer[c]; + gfloat screen = 1.0f - (1.0f - in[c]) * (1.0f - layer[c]); + gfloat val = (1.0f - in[c]) * multiply + in[c] * screen; + + comp[c] = val; + } + } + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +void +gimp_operation_layer_mode_blend_subtract (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + comp[c] = in[c] - layer[c]; + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + +/* added according to: + http://www.simplefilter.de/en/basics/mixmods.html */ +void +gimp_operation_layer_mode_blend_vivid_light (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + gint c; + + for (c = 0; c < 3; c++) + { + gfloat val; + + if (layer[c] <= 0.5f) + { + val = 1.0f - safe_div (1.0f - in[c], 2.0f * layer[c]); + val = MAX (val, 0.0f); + } + else + { + val = safe_div (in[c], 2.0f * (1.0f - layer[c])); + val = MIN (val, 1.0f); + } + + comp[c] = val; + } + } + + comp[ALPHA] = layer[ALPHA]; + + comp += 4; + layer += 4; + in += 4; + } +} + + +/* subtractive blending functions. these functions must set comp[ALPHA] to + * the modified alpha of the overlapping content, as a fraction of the + * original overlapping content (i.e., an alpha of 1.0 specifies that no + * content is subtracted.) when in[ALPHA] or layer[ALPHA] are zero, the value + * of comp[RED..BLUE] is unconstrained (in particular, it may be NaN). + */ + + +void +gimp_operation_layer_mode_blend_color_erase (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples) +{ + while (samples--) + { + if (in[ALPHA] != 0.0f && layer[ALPHA] != 0.0f) + { + const gfloat *color = in; + const gfloat *bgcolor = layer; + gfloat alpha; + gint c; + + alpha = 0.0f; + + for (c = 0; c < 3; c++) + { + gfloat col = CLAMP (color[c], 0.0f, 1.0f); + gfloat bgcol = CLAMP (bgcolor[c], 0.0f, 1.0f); + + if (fabs (col - bgcol) > EPSILON) + { + gfloat a; + + if (col > bgcol) + a = (col - bgcol) / (1.0f - bgcol); + else + a = (bgcol - col) / bgcol; + + alpha = MAX (alpha, a); + } + } + + if (alpha > EPSILON) + { + gfloat alpha_inv = 1.0f / alpha; + + for (c = 0; c < 3; c++) + comp[c] = (color[c] - bgcolor[c]) * alpha_inv + bgcolor[c]; + } + else + { + comp[RED] = comp[GREEN] = comp[BLUE] = 0.0f; + } + + comp[ALPHA] = alpha; + } + else + comp[ALPHA] = 0.0f; + + comp += 4; + layer += 4; + in += 4; + } +} diff --git a/app/operations/layer-modes/gimpoperationlayermode-blend.h b/app/operations/layer-modes/gimpoperationlayermode-blend.h new file mode 100644 index 0000000..3a8f995 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationlayermode-blend.h @@ -0,0 +1,200 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlayermode-blend.h + * Copyright (C) 2017 Michael Natterer <mitch@gimp.org> + * 2017 Øyvind Kolås <pippin@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; withcomp even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_LAYER_MODE_BLEND_H__ +#define __GIMP_OPERATION_LAYER_MODE_BLEND_H__ + + +/* nonsubtractive blend functions */ + +void gimp_operation_layer_mode_blend_addition (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_burn (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_darken_only (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_difference (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_divide (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_dodge (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_exclusion (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_grain_extract (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_grain_merge (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_hard_mix (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_hardlight (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_hsl_color (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_hsv_hue (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_hsv_saturation (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_hsv_value (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_lch_chroma (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_lch_color (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_lch_hue (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_lch_lightness (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_lighten_only (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_linear_burn (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_linear_light (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_luma_darken_only (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_luma_lighten_only (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_luminance (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_multiply (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_overlay (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_pin_light (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_screen (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_softlight (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_subtract (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); +void gimp_operation_layer_mode_blend_vivid_light (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); + + +/* subtractive blend functions */ + +void gimp_operation_layer_mode_blend_color_erase (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *comp, + gint samples); + + +#endif /* __GIMP_OPERATION_LAYER_MODE_BLEND_H__ */ diff --git a/app/operations/layer-modes/gimpoperationlayermode-composite-sse2.c b/app/operations/layer-modes/gimpoperationlayermode-composite-sse2.c new file mode 100644 index 0000000..2630751 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationlayermode-composite-sse2.c @@ -0,0 +1,105 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlayermode-composite-sse2.c + * Copyright (C) 2017 Michael Natterer <mitch@gimp.org> + * 2017 Øyvind Kolås <pippin@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "../operations-types.h" + +#include "gimpoperationlayermode-composite.h" + + +#if COMPILE_SSE2_INTRINISICS + +/* SSE2 */ +#include <emmintrin.h> + + +/* non-subtractive compositing functions. these functions expect comp[ALPHA] + * to be the same as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are zero, + * the value of comp[RED..BLUE] is unconstrained (in particular, it may be + * NaN). + */ + + +void +gimp_operation_layer_mode_composite_clip_to_backdrop_sse2 (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples) +{ + if ((((uintptr_t)in) | /* alignment check */ + ((uintptr_t)comp) | + ((uintptr_t)out) ) & 0x0F) + { + gimp_operation_layer_mode_composite_clip_to_backdrop (in, layer, comp, + mask, opacity, out, + samples); + } + else + { + const __v4sf *v_in = (const __v4sf*) in; + const __v4sf *v_comp = (const __v4sf*) comp; + __v4sf *v_out = (__v4sf*) out; + const __v4sf v_one = _mm_set1_ps (1.0f); + const __v4sf v_opacity = _mm_set1_ps (opacity); + + while (samples--) + { + __v4sf alpha, rgba_in, rgba_comp; + + rgba_in = *v_in ++; + rgba_comp = *v_comp++; + + alpha = (__v4sf)_mm_shuffle_epi32((__m128i)rgba_comp,_MM_SHUFFLE(3,3,3,3)) * v_opacity; + + if (mask) + { + alpha = alpha * _mm_set1_ps (*mask++); + } + + if (rgba_in[ALPHA] != 0.0f && _mm_ucomineq_ss (alpha, _mm_setzero_ps ())) + { + __v4sf out_pixel, out_pixel_rbaa, out_alpha; + + out_alpha = (__v4sf)_mm_shuffle_epi32((__m128i)rgba_in,_MM_SHUFFLE(3,3,3,3)); + out_pixel = rgba_comp * alpha + rgba_in * (v_one - alpha); + out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0)); + out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0)); + + *v_out++ = out_pixel; + } + else + { + *v_out ++ = rgba_in; + } + } + } +} + +#endif /* COMPILE_SSE2_INTRINISICS */ diff --git a/app/operations/layer-modes/gimpoperationlayermode-composite.c b/app/operations/layer-modes/gimpoperationlayermode-composite.c new file mode 100644 index 0000000..4275818 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationlayermode-composite.c @@ -0,0 +1,434 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlayermode-composite.c + * Copyright (C) 2017 Michael Natterer <mitch@gimp.org> + * 2017 Øyvind Kolås <pippin@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "../operations-types.h" + +#include "gimpoperationlayermode-composite.h" + + +/* non-subtractive compositing functions. these functions expect comp[ALPHA] + * to be the same as layer[ALPHA]. when in[ALPHA] or layer[ALPHA] are zero, + * the value of comp[RED..BLUE] is unconstrained (in particular, it may be + * NaN). + */ + + +void +gimp_operation_layer_mode_composite_union (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples) +{ + while (samples--) + { + gfloat new_alpha; + gfloat in_alpha = in[ALPHA]; + gfloat layer_alpha = layer[ALPHA] * opacity; + + if (mask) + layer_alpha *= *mask; + + new_alpha = layer_alpha + (1.0f - layer_alpha) * in_alpha; + + if (layer_alpha == 0.0f || new_alpha == 0.0f) + { + out[RED] = in[RED]; + out[GREEN] = in[GREEN]; + out[BLUE] = in[BLUE]; + } + else if (in_alpha == 0.0f) + { + out[RED] = layer[RED]; + out[GREEN] = layer[GREEN]; + out[BLUE] = layer[BLUE]; + } + else + { + gfloat ratio = layer_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + out[b] = ratio * (in_alpha * (comp[b] - layer[b]) + layer[b] - in[b]) + in[b]; + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + comp += 4; + out += 4; + + if (mask) + mask++; + } +} + +void +gimp_operation_layer_mode_composite_clip_to_backdrop (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples) +{ + while (samples--) + { + gfloat layer_alpha = comp[ALPHA] * opacity; + + if (mask) + layer_alpha *= *mask; + + if (in[ALPHA] == 0.0f || layer_alpha == 0.0f) + { + out[RED] = in[RED]; + out[GREEN] = in[GREEN]; + out[BLUE] = in[BLUE]; + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + out[b] = comp[b] * layer_alpha + in[b] * (1.0f - layer_alpha); + } + + out[ALPHA] = in[ALPHA]; + + in += 4; + comp += 4; + out += 4; + + if (mask) + mask++; + } +} + +void +gimp_operation_layer_mode_composite_clip_to_layer (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples) +{ + while (samples--) + { + gfloat layer_alpha = layer[ALPHA] * opacity; + + if (mask) + layer_alpha *= *mask; + + if (layer_alpha == 0.0f) + { + out[RED] = in[RED]; + out[GREEN] = in[GREEN]; + out[BLUE] = in[BLUE]; + } + else if (in[ALPHA] == 0.0f) + { + out[RED] = layer[RED]; + out[GREEN] = layer[GREEN]; + out[BLUE] = layer[BLUE]; + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + out[b] = comp[b] * in[ALPHA] + layer[b] * (1.0f - in[ALPHA]); + } + + out[ALPHA] = layer_alpha; + + in += 4; + layer += 4; + comp += 4; + out += 4; + + if (mask) + mask++; + } +} + +void +gimp_operation_layer_mode_composite_intersection (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples) +{ + while (samples--) + { + gfloat new_alpha = in[ALPHA] * comp[ALPHA] * opacity; + + if (mask) + new_alpha *= *mask; + + if (new_alpha == 0.0f) + { + out[RED] = in[RED]; + out[GREEN] = in[GREEN]; + out[BLUE] = in[BLUE]; + } + else + { + out[RED] = comp[RED]; + out[GREEN] = comp[GREEN]; + out[BLUE] = comp[BLUE]; + } + + out[ALPHA] = new_alpha; + + in += 4; + comp += 4; + out += 4; + + if (mask) + mask++; + } +} + +/* subtractive compositing functions. these functions expect comp[ALPHA] to + * specify the modified alpha of the overlapping content, as a fraction of the + * original overlapping content (i.e., an alpha of 1.0 specifies that no + * content is subtracted.) when in[ALPHA] or layer[ALPHA] are zero, the value + * of comp[RED..BLUE] is unconstrained (in particular, it may be NaN). + */ + +void +gimp_operation_layer_mode_composite_union_sub (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples) +{ + while (samples--) + { + gfloat in_alpha = in[ALPHA]; + gfloat layer_alpha = layer[ALPHA] * opacity; + gfloat comp_alpha = comp[ALPHA]; + gfloat new_alpha; + + if (mask) + layer_alpha *= *mask; + + new_alpha = in_alpha + layer_alpha - + (2.0f - comp_alpha) * in_alpha * layer_alpha; + + if (layer_alpha == 0.0f || new_alpha == 0.0f) + { + out[RED] = in[RED]; + out[GREEN] = in[GREEN]; + out[BLUE] = in[BLUE]; + } + else if (in_alpha == 0.0f) + { + out[RED] = layer[RED]; + out[GREEN] = layer[GREEN]; + out[BLUE] = layer[BLUE]; + } + else + { + gfloat ratio = in_alpha / new_alpha; + gfloat layer_coeff = 1.0f / in_alpha - 1.0f; + gint b; + + for (b = RED; b < ALPHA; b++) + out[b] = ratio * (layer_alpha * (comp_alpha * comp[b] + layer_coeff * layer[b] - in[b]) + in[b]); + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + comp += 4; + out += 4; + + if (mask) + mask++; + } +} + +void +gimp_operation_layer_mode_composite_clip_to_backdrop_sub (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples) +{ + while (samples--) + { + gfloat layer_alpha = layer[ALPHA] * opacity; + gfloat comp_alpha = comp[ALPHA]; + gfloat new_alpha; + + if (mask) + layer_alpha *= *mask; + + comp_alpha *= layer_alpha; + + new_alpha = 1.0f - layer_alpha + comp_alpha; + + if (in[ALPHA] == 0.0f || comp_alpha == 0.0f) + { + out[RED] = in[RED]; + out[GREEN] = in[GREEN]; + out[BLUE] = in[BLUE]; + } + else + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + out[b] = comp[b] * ratio + in[b] * (1.0f - ratio); + } + + new_alpha *= in[ALPHA]; + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + comp += 4; + out += 4; + + if (mask) + mask++; + } +} + +void +gimp_operation_layer_mode_composite_clip_to_layer_sub (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples) +{ + while (samples--) + { + gfloat in_alpha = in[ALPHA]; + gfloat layer_alpha = layer[ALPHA] * opacity; + gfloat comp_alpha = comp[ALPHA]; + gfloat new_alpha; + + if (mask) + layer_alpha *= *mask; + + comp_alpha *= in_alpha; + + new_alpha = 1.0f - in_alpha + comp_alpha; + + if (layer_alpha == 0.0f) + { + out[RED] = in[RED]; + out[GREEN] = in[GREEN]; + out[BLUE] = in[BLUE]; + } + else if (in_alpha == 0.0f) + { + out[RED] = layer[RED]; + out[GREEN] = layer[GREEN]; + out[BLUE] = layer[BLUE]; + } + else + { + gfloat ratio = comp_alpha / new_alpha; + gint b; + + for (b = RED; b < ALPHA; b++) + out[b] = comp[b] * ratio + layer[b] * (1.0f - ratio); + } + + new_alpha *= layer_alpha; + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + comp += 4; + out += 4; + + if (mask) + mask++; + } +} + +void +gimp_operation_layer_mode_composite_intersection_sub (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples) +{ + while (samples--) + { + gfloat new_alpha = in[ALPHA] * layer[ALPHA] * comp[ALPHA] * opacity; + + if (mask) + new_alpha *= *mask; + + if (new_alpha == 0.0f) + { + out[RED] = in[RED]; + out[GREEN] = in[GREEN]; + out[BLUE] = in[BLUE]; + } + else + { + out[RED] = comp[RED]; + out[GREEN] = comp[GREEN]; + out[BLUE] = comp[BLUE]; + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + comp += 4; + out += 4; + + if (mask) + mask++; + } +} diff --git a/app/operations/layer-modes/gimpoperationlayermode-composite.h b/app/operations/layer-modes/gimpoperationlayermode-composite.h new file mode 100644 index 0000000..f9ec2a5 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationlayermode-composite.h @@ -0,0 +1,98 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlayermode-composite.h + * Copyright (C) 2017 Michael Natterer <mitch@gimp.org> + * 2017 Øyvind Kolås <pippin@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__ +#define __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__ + + +void gimp_operation_layer_mode_composite_union (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples); +void gimp_operation_layer_mode_composite_clip_to_backdrop (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples); +void gimp_operation_layer_mode_composite_clip_to_layer (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples); +void gimp_operation_layer_mode_composite_intersection (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples); + +void gimp_operation_layer_mode_composite_union_sub (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples); +void gimp_operation_layer_mode_composite_clip_to_backdrop_sub (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples); +void gimp_operation_layer_mode_composite_clip_to_layer_sub (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples); +void gimp_operation_layer_mode_composite_intersection_sub (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples); + +#if COMPILE_SSE2_INTRINISICS + +void gimp_operation_layer_mode_composite_clip_to_backdrop_sse2 (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + gfloat opacity, + gfloat *out, + gint samples); + +#endif /* COMPILE_SSE2_INTRINISICS */ + + +#endif /* __GIMP_OPERATION_LAYER_MODE_COMPOSITE_H__ */ diff --git a/app/operations/layer-modes/gimpoperationlayermode.c b/app/operations/layer-modes/gimpoperationlayermode.c new file mode 100644 index 0000000..db74ed5 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationlayermode.c @@ -0,0 +1,914 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlayermode.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * Copyright (C) 2008 Martin Nordholts <martinn@svn.gnome.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> +#include <cairo.h> +#include <gdk-pixbuf/gdk-pixbuf.h> + +#include "libgimpbase/gimpbase.h" + +#include "../operations-types.h" + +#include "gimp-layer-modes.h" +#include "gimpoperationlayermode.h" +#include "gimpoperationlayermode-composite.h" + + +/* the maximum number of samples to process in one go. used to limit + * the size of the buffers we allocate on the stack. + */ +#define GIMP_COMPOSITE_BLEND_MAX_SAMPLES ((1 << 18) /* 256 KiB */ / \ + 16 /* bytes per pixel */ / \ + 2 /* max number of buffers */) + +/* number of consecutive unblended samples (whose source or destination alpha + * is zero) above which to split the blending process, in order to avoid + * performing too many unnecessary conversions. + */ +#define GIMP_COMPOSITE_BLEND_SPLIT_THRESHOLD 32 + + +enum +{ + PROP_0, + PROP_LAYER_MODE, + PROP_OPACITY, + PROP_BLEND_SPACE, + PROP_COMPOSITE_SPACE, + PROP_COMPOSITE_MODE +}; + + +typedef void (* CompositeFunc) (const gfloat *in, + const gfloat *layer, + const gfloat *comp, + const gfloat *mask, + float opacity, + gfloat *out, + gint samples); + + +static void gimp_operation_layer_mode_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_operation_layer_mode_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static void gimp_operation_layer_mode_prepare (GeglOperation *operation); +static GeglRectangle gimp_operation_layer_mode_get_bounding_box (GeglOperation *operation); +static gboolean gimp_operation_layer_mode_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level); + +static gboolean gimp_operation_layer_mode_process (GeglOperation *operation, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + +static gboolean gimp_operation_layer_mode_real_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level); +static gboolean gimp_operation_layer_mode_real_process (GeglOperation *operation, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + +static gboolean process_last_node (GeglOperation *operation, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationLayerMode, gimp_operation_layer_mode, + GEGL_TYPE_OPERATION_POINT_COMPOSER3) + +#define parent_class gimp_operation_layer_mode_parent_class + + +static const Babl *gimp_layer_color_space_fish[3 /* from */][3 /* to */]; + +static CompositeFunc composite_union = gimp_operation_layer_mode_composite_union; +static CompositeFunc composite_clip_to_backdrop = gimp_operation_layer_mode_composite_clip_to_backdrop; +static CompositeFunc composite_clip_to_layer = gimp_operation_layer_mode_composite_clip_to_layer; +static CompositeFunc composite_intersection = gimp_operation_layer_mode_composite_intersection; + +static CompositeFunc composite_union_sub = gimp_operation_layer_mode_composite_union_sub; +static CompositeFunc composite_clip_to_backdrop_sub = gimp_operation_layer_mode_composite_clip_to_backdrop_sub; +static CompositeFunc composite_clip_to_layer_sub = gimp_operation_layer_mode_composite_clip_to_layer_sub; +static CompositeFunc composite_intersection_sub = gimp_operation_layer_mode_composite_intersection_sub; + + +static void +gimp_operation_layer_mode_class_init (GimpOperationLayerModeClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GeglOperationPointComposer3Class *point_composer3_class = GEGL_OPERATION_POINT_COMPOSER3_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:layer-mode", NULL); + + object_class->set_property = gimp_operation_layer_mode_set_property; + object_class->get_property = gimp_operation_layer_mode_get_property; + + operation_class->prepare = gimp_operation_layer_mode_prepare; + operation_class->get_bounding_box = gimp_operation_layer_mode_get_bounding_box; + operation_class->process = gimp_operation_layer_mode_parent_process; + + point_composer3_class->process = gimp_operation_layer_mode_process; + + klass->parent_process = gimp_operation_layer_mode_real_parent_process; + klass->process = gimp_operation_layer_mode_real_process; + klass->get_affected_region = NULL; + + g_object_class_install_property (object_class, PROP_LAYER_MODE, + g_param_spec_enum ("layer-mode", + NULL, NULL, + GIMP_TYPE_LAYER_MODE, + GIMP_LAYER_MODE_NORMAL, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_OPACITY, + g_param_spec_double ("opacity", + NULL, NULL, + 0.0, 1.0, 1.0, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_BLEND_SPACE, + g_param_spec_enum ("blend-space", + NULL, NULL, + GIMP_TYPE_LAYER_COLOR_SPACE, + GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + + g_object_class_install_property (object_class, PROP_COMPOSITE_SPACE, + g_param_spec_enum ("composite-space", + NULL, NULL, + GIMP_TYPE_LAYER_COLOR_SPACE, + GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + g_object_class_install_property (object_class, PROP_COMPOSITE_MODE, + g_param_spec_enum ("composite-mode", + NULL, NULL, + GIMP_TYPE_LAYER_COMPOSITE_MODE, + GIMP_LAYER_COMPOSITE_UNION, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT)); + + gimp_layer_color_space_fish + /* from */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1] + /* to */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] = + babl_fish ("RGBA float", "R'G'B'A float"); + gimp_layer_color_space_fish + /* from */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1] + /* to */ [GIMP_LAYER_COLOR_SPACE_LAB - 1] = + babl_fish ("RGBA float", "CIE Lab alpha float"); + + gimp_layer_color_space_fish + /* from */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] + /* to */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1] = + babl_fish ("R'G'B'A float", "RGBA float"); + gimp_layer_color_space_fish + /* from */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] + /* to */ [GIMP_LAYER_COLOR_SPACE_LAB - 1] = + babl_fish ("R'G'B'A float", "CIE Lab alpha float"); + + gimp_layer_color_space_fish + /* from */ [GIMP_LAYER_COLOR_SPACE_LAB - 1] + /* to */ [GIMP_LAYER_COLOR_SPACE_RGB_LINEAR - 1] = + babl_fish ("CIE Lab alpha float", "RGBA float"); + gimp_layer_color_space_fish + /* from */ [GIMP_LAYER_COLOR_SPACE_LAB - 1] + /* to */ [GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL - 1] = + babl_fish ("CIE Lab alpha float", "R'G'B'A float"); + +#if COMPILE_SSE2_INTRINISICS + if (gimp_cpu_accel_get_support () & GIMP_CPU_ACCEL_X86_SSE2) + composite_clip_to_backdrop = gimp_operation_layer_mode_composite_clip_to_backdrop_sse2; +#endif +} + +static void +gimp_operation_layer_mode_init (GimpOperationLayerMode *self) +{ +} + +static void +gimp_operation_layer_mode_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (object); + + switch (property_id) + { + case PROP_LAYER_MODE: + self->layer_mode = g_value_get_enum (value); + break; + + case PROP_OPACITY: + self->prop_opacity = g_value_get_double (value); + break; + + case PROP_BLEND_SPACE: + self->blend_space = g_value_get_enum (value); + break; + + case PROP_COMPOSITE_SPACE: + self->composite_space = g_value_get_enum (value); + break; + + case PROP_COMPOSITE_MODE: + self->prop_composite_mode = g_value_get_enum (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_layer_mode_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (object); + + switch (property_id) + { + case PROP_LAYER_MODE: + g_value_set_enum (value, self->layer_mode); + break; + + case PROP_OPACITY: + g_value_set_double (value, self->prop_opacity); + break; + + case PROP_BLEND_SPACE: + g_value_set_enum (value, self->blend_space); + break; + + case PROP_COMPOSITE_SPACE: + g_value_set_enum (value, self->composite_space); + break; + + case PROP_COMPOSITE_MODE: + g_value_set_enum (value, self->prop_composite_mode); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_operation_layer_mode_prepare (GeglOperation *operation) +{ + GimpOperationLayerMode *self = GIMP_OPERATION_LAYER_MODE (operation); + const GeglRectangle *input_extent; + const GeglRectangle *mask_extent; + const Babl *preferred_format; + const Babl *format; + + self->composite_mode = self->prop_composite_mode; + + if (self->composite_mode == GIMP_LAYER_COMPOSITE_AUTO) + { + self->composite_mode = + gimp_layer_mode_get_composite_mode (self->layer_mode); + + g_warn_if_fail (self->composite_mode != GIMP_LAYER_COMPOSITE_AUTO); + } + + self->function = gimp_layer_mode_get_function (self->layer_mode); + self->blend_function = gimp_layer_mode_get_blend_function (self->layer_mode); + + input_extent = gegl_operation_source_get_bounding_box (operation, "input"); + mask_extent = gegl_operation_source_get_bounding_box (operation, "aux2"); + + /* if the input pad has data, work as usual. */ + if (input_extent && ! gegl_rectangle_is_empty (input_extent)) + { + self->is_last_node = FALSE; + + preferred_format = gegl_operation_get_source_format (operation, "input"); + } + /* otherwise, we're the last node (corresponding to the bottom layer). + * in this case, we render the layer (as if) using UNION mode. + */ + else + { + self->is_last_node = TRUE; + + /* if the layer mode doesn't affect the source, use a shortcut + * function that only applies the opacity/mask to the layer. + */ + if (! (gimp_operation_layer_mode_get_affected_region (self) & + GIMP_LAYER_COMPOSITE_REGION_SOURCE)) + { + self->function = process_last_node; + } + /* otherwise, use the original process function, but force the + * composite mode to UNION. + */ + else + { + self->composite_mode = GIMP_LAYER_COMPOSITE_UNION; + } + + preferred_format = gegl_operation_get_source_format (operation, "aux"); + } + + self->has_mask = mask_extent && ! gegl_rectangle_is_empty (mask_extent); + + format = gimp_layer_mode_get_format (self->layer_mode, + self->blend_space, + self->composite_space, + self->composite_mode, + preferred_format); + + gegl_operation_set_format (operation, "input", format); + gegl_operation_set_format (operation, "output", format); + gegl_operation_set_format (operation, "aux", format); + gegl_operation_set_format (operation, "aux2", babl_format ("Y float")); +} + +static GeglRectangle +gimp_operation_layer_mode_get_bounding_box (GeglOperation *op) +{ + GimpOperationLayerMode *self = (gpointer) op; + GeglRectangle *in_rect; + GeglRectangle *aux_rect; + GeglRectangle *aux2_rect; + GeglRectangle src_rect = {}; + GeglRectangle dst_rect = {}; + GeglRectangle result; + GimpLayerCompositeRegion included_region; + + in_rect = gegl_operation_source_get_bounding_box (op, "input"); + aux_rect = gegl_operation_source_get_bounding_box (op, "aux"); + aux2_rect = gegl_operation_source_get_bounding_box (op, "aux2"); + + if (in_rect) + dst_rect = *in_rect; + + if (aux_rect) + { + src_rect = *aux_rect; + + if (aux2_rect) + gegl_rectangle_intersect (&src_rect, &src_rect, aux2_rect); + } + + if (self->is_last_node) + { + included_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE; + } + else + { + included_region = gimp_layer_mode_get_included_region (self->layer_mode, + self->composite_mode); + } + + if (self->prop_opacity == 0.0) + included_region &= ~GIMP_LAYER_COMPOSITE_REGION_SOURCE; + + gegl_rectangle_intersect (&result, &src_rect, &dst_rect); + + if (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE) + gegl_rectangle_bounding_box (&result, &result, &src_rect); + + if (included_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION) + gegl_rectangle_bounding_box (&result, &result, &dst_rect); + + return result; +} + +static gboolean +gimp_operation_layer_mode_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level) +{ + GimpOperationLayerMode *point = GIMP_OPERATION_LAYER_MODE (operation); + + point->opacity = point->prop_opacity; + + /* if we have a mask, but it's not included in the output, pretend the + * opacity is 0, so that we don't composite 'aux' over 'input' as if there + * was no mask. + */ + if (point->has_mask) + { + GObject *mask; + gboolean has_mask; + + /* get the raw value. this does not increase the reference count. */ + mask = gegl_operation_context_get_object (context, "aux2"); + + /* disregard 'mask' if it's not included in the roi. */ + has_mask = + mask && + gegl_rectangle_intersect (NULL, + gegl_buffer_get_extent (GEGL_BUFFER (mask)), + result); + + if (! has_mask) + point->opacity = 0.0; + } + + return GIMP_OPERATION_LAYER_MODE_GET_CLASS (point)->parent_process ( + operation, context, output_prop, result, level); +} + +static gboolean +gimp_operation_layer_mode_process (GeglOperation *operation, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level) +{ + return ((GimpOperationLayerMode *) operation)->function ( + operation, in, layer, mask, out, samples, roi, level); +} + +static gboolean +gimp_operation_layer_mode_real_parent_process (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level) +{ + GimpOperationLayerMode *point = GIMP_OPERATION_LAYER_MODE (operation); + GObject *input; + GObject *aux; + gboolean has_input; + gboolean has_aux; + GimpLayerCompositeRegion included_region; + + /* get the raw values. this does not increase the reference count. */ + input = gegl_operation_context_get_object (context, "input"); + aux = gegl_operation_context_get_object (context, "aux"); + + /* disregard 'input' if it's not included in the roi. */ + has_input = + input && + gegl_rectangle_intersect (NULL, + gegl_buffer_get_extent (GEGL_BUFFER (input)), + result); + + /* disregard 'aux' if it's not included in the roi, or if it's fully + * transparent. + */ + has_aux = + aux && + point->opacity != 0.0 && + gegl_rectangle_intersect (NULL, + gegl_buffer_get_extent (GEGL_BUFFER (aux)), + result); + + if (point->is_last_node) + { + included_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE; + } + else + { + included_region = gimp_layer_mode_get_included_region (point->layer_mode, + point->composite_mode); + } + + /* if there's no 'input' ... */ + if (! has_input) + { + /* ... and there's 'aux', and the composite mode includes it (or we're + * the last node) ... + */ + if (has_aux && (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE)) + { + GimpLayerCompositeRegion affected_region; + + affected_region = + gimp_operation_layer_mode_get_affected_region (point); + + /* ... and the op doesn't otherwise affect 'aux', or changes its + * alpha ... + */ + if (! (affected_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE) && + point->opacity == 1.0 && + ! gegl_operation_context_get_object (context, "aux2")) + { + /* pass 'aux' directly as output; */ + gegl_operation_context_set_object (context, "output", aux); + return TRUE; + } + + /* otherwise, if the op affects 'aux', or changes its alpha, process + * it even though there's no 'input'; + */ + } + /* otherwise, there's no 'aux', or the composite mode doesn't include it, + * and so ... + */ + else + { + /* ... the output is empty. */ + gegl_operation_context_set_object (context, "output", NULL); + return TRUE; + } + } + /* otherwise, if there's 'input' but no 'aux' ... */ + else if (! has_aux) + { + /* ... and the composite mode includes 'input' ... */ + if (included_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION) + { + GimpLayerCompositeRegion affected_region; + + affected_region = + gimp_operation_layer_mode_get_affected_region (point); + + /* ... and the op doesn't otherwise affect 'input' ... */ + if (! (affected_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION)) + { + /* pass 'input' directly as output; */ + gegl_operation_context_set_object (context, "output", input); + return TRUE; + } + + /* otherwise, if the op affects 'input', process it even though + * there's no 'aux'; + */ + } + + /* otherwise, the output is fully transparent, but we process it anyway + * to maintain the 'input' color values. + */ + } + + /* FIXME: we don't actually handle the case where one of the inputs + * is NULL -- it'll just segfault. 'input' is not expected to be NULL, + * but 'aux' might be, currently. + */ + if (! input || ! aux) + { + GObject *empty = G_OBJECT (gegl_buffer_new (NULL, NULL)); + + if (! input) gegl_operation_context_set_object (context, "input", empty); + if (! aux) gegl_operation_context_set_object (context, "aux", empty); + + if (! input && ! aux) + gegl_object_set_has_forked (G_OBJECT (empty)); + + g_object_unref (empty); + } + + /* chain up, which will create the needed buffers for our actual + * process function + */ + return GEGL_OPERATION_CLASS (parent_class)->process (operation, context, + output_prop, result, + level); +} + +static gboolean +gimp_operation_layer_mode_real_process (GeglOperation *operation, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) operation; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + GimpLayerColorSpace blend_space = layer_mode->blend_space; + GimpLayerColorSpace composite_space = layer_mode->composite_space; + GimpLayerCompositeMode composite_mode = layer_mode->composite_mode; + GimpLayerModeBlendFunc blend_function = layer_mode->blend_function; + gboolean composite_needs_in_color; + gfloat *blend_in; + gfloat *blend_layer; + gfloat *blend_out; + const Babl *composite_to_blend_fish = NULL; + const Babl *blend_to_composite_fish = NULL; + + /* make sure we don't process more than GIMP_COMPOSITE_BLEND_MAX_SAMPLES + * at a time, so that we don't overflow the stack if we allocate buffers + * on it. note that this has to be done with a nested function call, + * because alloca'd buffers remain for the duration of the stack frame. + */ + while (samples > GIMP_COMPOSITE_BLEND_MAX_SAMPLES) + { + gimp_operation_layer_mode_real_process (operation, + in, layer, mask, out, + GIMP_COMPOSITE_BLEND_MAX_SAMPLES, + roi, level); + + in += 4 * GIMP_COMPOSITE_BLEND_MAX_SAMPLES; + layer += 4 * GIMP_COMPOSITE_BLEND_MAX_SAMPLES; + if (mask) + mask += GIMP_COMPOSITE_BLEND_MAX_SAMPLES; + out += 4 * GIMP_COMPOSITE_BLEND_MAX_SAMPLES; + + samples -= GIMP_COMPOSITE_BLEND_MAX_SAMPLES; + } + + composite_needs_in_color = + composite_mode == GIMP_LAYER_COMPOSITE_UNION || + composite_mode == GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP; + + blend_in = in; + blend_layer = layer; + blend_out = out; + + if (blend_space != GIMP_LAYER_COLOR_SPACE_AUTO) + { + gimp_assert (composite_space >= 1 && composite_space < 4); + gimp_assert (blend_space >= 1 && blend_space < 4); + + composite_to_blend_fish = gimp_layer_color_space_fish [composite_space - 1] + [blend_space - 1]; + + blend_to_composite_fish = gimp_layer_color_space_fish [blend_space - 1] + [composite_space - 1]; + } + + /* if we need to convert the samples between the composite and blend + * spaces... + */ + if (composite_to_blend_fish) + { + gint i; + gint end; + + if (in != out || composite_needs_in_color) + { + /* don't convert input in-place if we're not doing in-place output, + * or if we're going to need the original input for compositing. + */ + blend_in = g_alloca (sizeof (gfloat) * 4 * samples); + } + blend_layer = g_alloca (sizeof (gfloat) * 4 * samples); + + if (in == out) /* in-place detected, avoid clobbering since we need to + read 'in' for the compositing stage */ + { + if (blend_layer != layer) + blend_out = blend_layer; + else + blend_out = g_alloca (sizeof (gfloat) * 4 * samples); + } + + /* samples whose the source or destination alpha is zero are not blended, + * and therefore do not need to be converted. while it's generally + * desirable to perform conversion and blending in bulk, when we have + * more than a certain number of consecutive unblended samples, the cost + * of converting them outweighs the cost of splitting the process around + * them to avoid the conversion. + */ + + i = ALPHA; + end = 4 * samples + ALPHA; + + while (TRUE) + { + gint first; + gint last; + gint count; + + /* skip any unblended samples. the color values of `blend_out` for + * these samples are unconstrained, in particular, they may be NaN, + * but the alpha values should generally be finite, and specifically + * 0 when the source alpha is 0. + */ + while (i < end && (in[i] == 0.0f || layer[i] == 0.0f)) + { + blend_out[i] = 0.0f; + i += 4; + } + + /* stop if there are no more samples */ + if (i == end) + break; + + /* otherwise, keep scanning the samples until we find + * GIMP_COMPOSITE_BLEND_SPLIT_THRESHOLD consecutive unblended + * samples. + */ + + first = i; + i += 4; + last = i; + + while (i < end && i - last < 4 * GIMP_COMPOSITE_BLEND_SPLIT_THRESHOLD) + { + gboolean blended; + + blended = (in[i] != 0.0f && layer[i] != 0.0f); + + i += 4; + if (blended) + last = i; + } + + /* convert and blend the samples in the range [first, last) */ + + count = (last - first) / 4; + first -= ALPHA; + + babl_process (composite_to_blend_fish, + in + first, blend_in + first, count); + babl_process (composite_to_blend_fish, + layer + first, blend_layer + first, count); + + blend_function (operation, blend_in + first, blend_layer + first, + blend_out + first, count); + + babl_process (blend_to_composite_fish, + blend_out + first, blend_out + first, count); + + /* make sure the alpha values of `blend_out` are valid for the + * trailing unblended samples. + */ + for (; last < i; last += 4) + blend_out[last] = 0.0f; + } + } + else + { + /* if both blending and compositing use the same color space, things are + * much simpler. + */ + + if (in == out) /* in-place detected, avoid clobbering since we need to + read 'in' for the compositing stage */ + { + blend_out = g_alloca (sizeof (gfloat) * 4 * samples); + } + + blend_function (operation, blend_in, blend_layer, blend_out, samples); + } + + if (! gimp_layer_mode_is_subtractive (layer_mode->layer_mode)) + { + switch (composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + case GIMP_LAYER_COMPOSITE_AUTO: + composite_union (in, layer, blend_out, mask, opacity, + out, samples); + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + composite_clip_to_backdrop (in, layer, blend_out, mask, opacity, + out, samples); + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + composite_clip_to_layer (in, layer, blend_out, mask, opacity, + out, samples); + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + composite_intersection (in, layer, blend_out, mask, opacity, + out, samples); + break; + } + } + else + { + switch (composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + case GIMP_LAYER_COMPOSITE_AUTO: + composite_union_sub (in, layer, blend_out, mask, opacity, + out, samples); + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + composite_clip_to_backdrop_sub (in, layer, blend_out, mask, opacity, + out, samples); + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + composite_clip_to_layer_sub (in, layer, blend_out, mask, opacity, + out, samples); + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + composite_intersection_sub (in, layer, blend_out, mask, opacity, + out, samples); + break; + } + } + + return TRUE; +} + +static gboolean +process_last_node (GeglOperation *operation, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = GIMP_OPERATION_LAYER_MODE (operation)->opacity; + + while (samples--) + { + memcpy (out, layer, 3 * sizeof (gfloat)); + + out[ALPHA] = layer[ALPHA] * opacity; + if (mask) + out[ALPHA] *= *mask++; + + layer += 4; + out += 4; + } + + return TRUE; +} + + +/* public functions */ + + +GimpLayerCompositeRegion +gimp_operation_layer_mode_get_affected_region (GimpOperationLayerMode *layer_mode) +{ + GimpOperationLayerModeClass *klass; + + g_return_val_if_fail (GIMP_IS_OPERATION_LAYER_MODE (layer_mode), + GIMP_LAYER_COMPOSITE_REGION_INTERSECTION); + + klass = GIMP_OPERATION_LAYER_MODE_GET_CLASS (layer_mode); + + if (klass->get_affected_region) + return klass->get_affected_region (layer_mode); + + return GIMP_LAYER_COMPOSITE_REGION_INTERSECTION; +} diff --git a/app/operations/layer-modes/gimpoperationlayermode.h b/app/operations/layer-modes/gimpoperationlayermode.h new file mode 100644 index 0000000..a2a5463 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationlayermode.h @@ -0,0 +1,89 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationlayermode.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_LAYER_MODE_H__ +#define __GIMP_OPERATION_LAYER_MODE_H__ + + +#include <gegl-plugin.h> + + +#define GIMP_TYPE_OPERATION_LAYER_MODE (gimp_operation_layer_mode_get_type ()) +#define GIMP_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_LAYER_MODE, GimpOperationLayerMode)) +#define GIMP_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_LAYER_MODE, GimpOperationLayerModeClass)) +#define GIMP_IS_OPERATION_LAYER_MODE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_LAYER_MODE)) +#define GIMP_IS_OPERATION_LAYER_MODE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_LAYER_MODE)) +#define GIMP_OPERATION_LAYER_MODE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_LAYER_MODE, GimpOperationLayerModeClass)) + + +typedef struct _GimpOperationLayerModeClass GimpOperationLayerModeClass; + +struct _GimpOperationLayerMode +{ + GeglOperationPointComposer3 parent_instance; + + GimpLayerMode layer_mode; + gdouble opacity; + GimpLayerColorSpace blend_space; + GimpLayerColorSpace composite_space; + GimpLayerCompositeMode composite_mode; + + gdouble prop_opacity; + GimpLayerCompositeMode prop_composite_mode; + + GimpLayerModeFunc function; + GimpLayerModeBlendFunc blend_function; + gboolean is_last_node; + gboolean has_mask; +}; + +struct _GimpOperationLayerModeClass +{ + GeglOperationPointComposer3Class parent_class; + + /* virtual functions */ + gboolean (* parent_process) (GeglOperation *operation, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level); + gboolean (* process) (GeglOperation *operation, + void *in, + void *aux, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + /* Returns the composite region (any combination of the layer and the + * backdrop) that the layer mode affects. Most modes only affect the + * overlapping region, and don't need to override this function. + */ + GimpLayerCompositeRegion (* get_affected_region) (GimpOperationLayerMode *layer_mode); +}; + + +GType gimp_operation_layer_mode_get_type (void) G_GNUC_CONST; + +GimpLayerCompositeRegion gimp_operation_layer_mode_get_affected_region (GimpOperationLayerMode *layer_mode); + + +#endif /* __GIMP_OPERATION_LAYER_MODE_H__ */ diff --git a/app/operations/layer-modes/gimpoperationmerge.c b/app/operations/layer-modes/gimpoperationmerge.c new file mode 100644 index 0000000..e1b25ca --- /dev/null +++ b/app/operations/layer-modes/gimpoperationmerge.c @@ -0,0 +1,243 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationmerge.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationmerge.h" + + +static gboolean gimp_operation_merge_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationMerge, gimp_operation_merge, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_merge_class_init (GimpOperationMergeClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:merge", + "description", "GIMP merge mode operation", + NULL); + + layer_mode_class->process = gimp_operation_merge_process; +} + +static void +gimp_operation_merge_init (GimpOperationMerge *self) +{ +} + +static gboolean +gimp_operation_merge_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + const gboolean has_mask = mask != NULL; + + switch (layer_mode->composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) + { + gfloat in_alpha = in[ALPHA]; + gfloat layer_alpha = layer[ALPHA] * opacity; + gfloat new_alpha; + gint b; + + if (has_mask) + layer_alpha *= *mask; + + in_alpha = MIN (in_alpha, 1.0f - layer_alpha); + new_alpha = in_alpha + layer_alpha; + + if (new_alpha) + { + gfloat ratio = layer_alpha / new_alpha; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b] + (layer[b] - in[b]) * ratio; + } + } + else + { + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + while (samples--) + { + gfloat in_alpha = in[ALPHA]; + gfloat layer_alpha = layer[ALPHA] * opacity; + gint b; + + if (has_mask) + layer_alpha *= *mask; + + layer_alpha -= 1.0f - in_alpha; + + if (layer_alpha > 0.0f) + { + gfloat ratio = layer_alpha / in_alpha; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b] + (layer[b] - in[b]) * ratio; + } + } + else + { + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = in_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + while (samples--) + { + gfloat layer_alpha = layer[ALPHA] * opacity; + gint b; + + if (has_mask) + layer_alpha *= *mask; + + if (layer_alpha != 0.0f) + { + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + else + { + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = layer_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + while (samples--) + { + gfloat in_alpha = in[ALPHA]; + gfloat layer_alpha = layer[ALPHA] * opacity; + gint b; + + if (has_mask) + layer_alpha *= *mask; + + layer_alpha -= 1.0f - in_alpha; + layer_alpha = MAX (layer_alpha, 0.0f); + + if (layer_alpha != 0.0f) + { + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + else + { + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = layer_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + } + + return TRUE; +} diff --git a/app/operations/layer-modes/gimpoperationmerge.h b/app/operations/layer-modes/gimpoperationmerge.h new file mode 100644 index 0000000..01afde1 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationmerge.h @@ -0,0 +1,54 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationmerge.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_MERGE_H__ +#define __GIMP_OPERATION_MERGE_H__ + + +#include "gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_MERGE (gimp_operation_merge_get_type ()) +#define GIMP_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_MERGE, GimpOperationMerge)) +#define GIMP_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_MERGE, GimpOperationMergeClass)) +#define GIMP_IS_OPERATION_MERGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_MERGE)) +#define GIMP_IS_OPERATION_MERGE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_MERGE)) +#define GIMP_OPERATION_MERGE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_MERGE, GimpOperationMergeClass)) + + +typedef struct _GimpOperationMerge GimpOperationMerge; +typedef struct _GimpOperationMergeClass GimpOperationMergeClass; + +struct _GimpOperationMerge +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationMergeClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_merge_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_MERGE_H__ */ diff --git a/app/operations/layer-modes/gimpoperationnormal-sse2.c b/app/operations/layer-modes/gimpoperationnormal-sse2.c new file mode 100644 index 0000000..73e42ed --- /dev/null +++ b/app/operations/layer-modes/gimpoperationnormal-sse2.c @@ -0,0 +1,264 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationnormal-sse2.c + * Copyright (C) 2013 Daniel Sabo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "operations/operations-types.h" + +#include "gimpoperationnormal.h" + + +#if COMPILE_SSE2_INTRINISICS + +/* SSE2 */ +#include <emmintrin.h> + + +gboolean +gimp_operation_normal_process_sse2 (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + /* check alignment */ + if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F) + { + return gimp_operation_normal_process (op, + in_p, layer_p, mask_p, out_p, + samples, roi, level); + } + else + { + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat opacity = layer_mode->opacity; + gfloat *mask = mask_p; + const __v4sf *v_in = (const __v4sf*) in_p; + const __v4sf *v_layer = (const __v4sf*) layer_p; + __v4sf *v_out = ( __v4sf*) out_p; + + const __v4sf one = _mm_set1_ps (1.0f); + const __v4sf v_opacity = _mm_set1_ps (opacity); + + switch (layer_mode->composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) + { + __v4sf rgba_in, rgba_layer, alpha; + + rgba_in = *v_in++; + rgba_layer = *v_layer++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply layer's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + __v4sf dst_alpha, a_term, out_pixel, out_alpha, out_pixel_rbaa; + + /* expand alpha */ + dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + /* a_term = dst_a * (1.0 - src_a) */ + a_term = dst_alpha * (one - alpha); + + /* out(color) = src * src_a + dst * a_term */ + out_pixel = rgba_layer * alpha + rgba_in * a_term; + + /* out(alpha) = 1.0 * src_a + 1.0 * a_term */ + out_alpha = alpha + a_term; + + /* un-premultiply */ + out_pixel = out_pixel / out_alpha; + + /* swap in the real alpha */ + out_pixel_rbaa = _mm_shuffle_ps (out_pixel, out_alpha, _MM_SHUFFLE (3, 3, 2, 0)); + out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0)); + + *v_out++ = out_pixel; + } + else + { + *v_out++ = rgba_in; + } + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + while (samples--) + { + __v4sf rgba_in, rgba_layer, alpha; + + rgba_in = *v_in++; + rgba_layer = *v_layer++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply layer's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + __v4sf dst_alpha, out_pixel, out_pixel_rbaa; + + /* expand alpha */ + dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + /* out(color) = dst * (1 - src_a) + src * src_a */ + out_pixel = rgba_in + (rgba_layer - rgba_in) * alpha; + + /* swap in the real alpha */ + out_pixel_rbaa = _mm_shuffle_ps (out_pixel, dst_alpha, _MM_SHUFFLE (3, 3, 2, 0)); + out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0)); + + *v_out++ = out_pixel; + } + else + { + *v_out++ = rgba_in; + } + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + while (samples--) + { + __v4sf rgba_in, rgba_layer, alpha; + __v4sf out_pixel, out_pixel_rbaa; + + rgba_in = *v_in++; + rgba_layer = *v_layer++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply layer's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + /* out(color) = src */ + out_pixel = rgba_layer; + } + else + { + out_pixel = rgba_in; + } + + /* swap in the real alpha */ + out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0)); + out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0)); + + *v_out++ = out_pixel; + } + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + while (samples--) + { + __v4sf rgba_in, rgba_layer, alpha; + __v4sf out_pixel, out_pixel_rbaa; + + rgba_in = *v_in++; + rgba_layer = *v_layer++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply layer's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + /* multiply the alpha by in's alpha */ + alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + /* out(color) = src */ + out_pixel = rgba_layer; + } + else + { + out_pixel = rgba_in; + } + + /* swap in the real alpha */ + out_pixel_rbaa = _mm_shuffle_ps (out_pixel, alpha, _MM_SHUFFLE (3, 3, 2, 0)); + out_pixel = _mm_shuffle_ps (out_pixel, out_pixel_rbaa, _MM_SHUFFLE (2, 1, 1, 0)); + + *v_out++ = out_pixel; + } + break; + } + } + + return TRUE; +} + +#endif /* COMPILE_SSE2_INTRINISICS */ diff --git a/app/operations/layer-modes/gimpoperationnormal-sse4.c b/app/operations/layer-modes/gimpoperationnormal-sse4.c new file mode 100644 index 0000000..ba621a2 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationnormal-sse4.c @@ -0,0 +1,260 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationnormalmode-sse2.c + * Copyright (C) 2013 Daniel Sabo + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "operations/operations-types.h" + +#include "gimpoperationnormal.h" + + +#if COMPILE_SSE4_1_INTRINISICS + +/* SSE4 */ +#include <smmintrin.h> + + +gboolean +gimp_operation_normal_process_sse4 (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + /* check alignment */ + if ((((uintptr_t)in_p) | ((uintptr_t)layer_p) | ((uintptr_t)out_p)) & 0x0F) + { + return gimp_operation_normal_process (op, + in_p, layer_p, mask_p, out_p, + samples, roi, level); + } + else + { + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat opacity = layer_mode->opacity; + gfloat *mask = mask_p; + const __v4sf *v_in = (const __v4sf*) in_p; + const __v4sf *v_layer = (const __v4sf*) layer_p; + __v4sf *v_out = ( __v4sf*) out_p; + + const __v4sf one = _mm_set1_ps (1.0f); + const __v4sf v_opacity = _mm_set1_ps (opacity); + + switch (layer_mode->composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) + { + __v4sf rgba_in, rgba_layer, alpha; + + rgba_in = *v_in++; + rgba_layer = *v_layer++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply layer's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + __v4sf dst_alpha, a_term, out_pixel, out_alpha; + + /* expand alpha */ + dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + /* a_term = dst_a * (1.0 - src_a) */ + a_term = dst_alpha * (one - alpha); + + /* out(color) = src * src_a + dst * a_term */ + out_pixel = rgba_layer * alpha + rgba_in * a_term; + + /* out(alpha) = 1.0 * src_a + 1.0 * a_term */ + out_alpha = alpha + a_term; + + /* un-premultiply */ + out_pixel = out_pixel / out_alpha; + + /* swap in the real alpha */ + out_pixel = _mm_blend_ps (out_pixel, out_alpha, 0x08); + + *v_out++ = out_pixel; + } + else + { + *v_out++ = rgba_in; + } + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + while (samples--) + { + __v4sf rgba_in, rgba_layer, alpha; + + rgba_in = *v_in++; + rgba_layer = *v_layer++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply layer's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + __v4sf dst_alpha, out_pixel; + + /* expand alpha */ + dst_alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + /* out(color) = dst * (1 - src_a) + src * src_a */ + out_pixel = rgba_in + (rgba_layer - rgba_in) * alpha; + + /* swap in the real alpha */ + out_pixel = _mm_blend_ps (out_pixel, dst_alpha, 0x08); + + *v_out++ = out_pixel; + } + else + { + *v_out++ = rgba_in; + } + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + while (samples--) + { + __v4sf rgba_in, rgba_layer, alpha; + __v4sf out_pixel; + + rgba_in = *v_in++; + rgba_layer = *v_layer++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply layer's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + /* out(color) = src */ + out_pixel = rgba_layer; + } + else + { + out_pixel = rgba_in; + } + + /* swap in the real alpha */ + out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08); + + *v_out++ = out_pixel; + } + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + while (samples--) + { + __v4sf rgba_in, rgba_layer, alpha; + __v4sf out_pixel; + + rgba_in = *v_in++; + rgba_layer = *v_layer++; + + /* expand alpha */ + alpha = (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_layer, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (mask) + { + __v4sf mask_alpha; + + /* multiply layer's alpha by the mask */ + mask_alpha = _mm_set1_ps (*mask++); + alpha = alpha * mask_alpha; + } + + alpha = alpha * v_opacity; + + /* multiply the alpha by in's alpha */ + alpha *= (__v4sf)_mm_shuffle_epi32 ((__m128i)rgba_in, + _MM_SHUFFLE (3, 3, 3, 3)); + + if (_mm_ucomigt_ss (alpha, _mm_setzero_ps ())) + { + /* out(color) = src */ + out_pixel = rgba_layer; + } + else + { + out_pixel = rgba_in; + } + + /* swap in the real alpha */ + out_pixel = _mm_blend_ps (out_pixel, alpha, 0x08); + + *v_out++ = out_pixel; + } + break; + } + } + + return TRUE; +} + +#endif /* COMPILE_SSE4_1_INTRINISICS */ diff --git a/app/operations/layer-modes/gimpoperationnormal.c b/app/operations/layer-modes/gimpoperationnormal.c new file mode 100644 index 0000000..9bd8705 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationnormal.c @@ -0,0 +1,266 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationnormalmode.c + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gio/gio.h> +#include <gegl-plugin.h> + +#include "libgimpbase/gimpbase.h" + +#include "../operations-types.h" + +#include "gimpoperationnormal.h" + + +G_DEFINE_TYPE (GimpOperationNormal, gimp_operation_normal, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static const gchar* reference_xml = "<?xml version='1.0' encoding='UTF-8'?>" +"<gegl>" +"<node operation='gimp:normal'>" +" <node operation='gegl:load'>" +" <params>" +" <param name='path'>blending-test-B.png</param>" +" </params>" +" </node>" +"</node>" +"<node operation='gegl:load'>" +" <params>" +" <param name='path'>blending-test-A.png</param>" +" </params>" +"</node>" +"</gegl>"; + + +static void +gimp_operation_normal_class_init (GimpOperationNormalClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:normal", + "description", "GIMP normal mode operation", + "reference-image", "normal-mode.png", + "reference-composition", reference_xml, + NULL); + + layer_mode_class->process = gimp_operation_normal_process; + +#if COMPILE_SSE2_INTRINISICS + if (gimp_cpu_accel_get_support() & GIMP_CPU_ACCEL_X86_SSE2) + layer_mode_class->process = gimp_operation_normal_process_sse2; +#endif /* COMPILE_SSE2_INTRINISICS */ + +#if COMPILE_SSE4_1_INTRINISICS + if (gimp_cpu_accel_get_support() & GIMP_CPU_ACCEL_X86_SSE4_1) + layer_mode_class->process = gimp_operation_normal_process_sse4; +#endif /* COMPILE_SSE4_1_INTRINISICS */ +} + +static void +gimp_operation_normal_init (GimpOperationNormal *self) +{ +} + +gboolean +gimp_operation_normal_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + const gboolean has_mask = mask != NULL; + + switch (layer_mode->composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) + { + gfloat layer_alpha; + + layer_alpha = layer[ALPHA] * opacity; + if (has_mask) + layer_alpha *= *mask; + + out[ALPHA] = layer_alpha + in[ALPHA] - layer_alpha * in[ALPHA]; + + if (out[ALPHA]) + { + gfloat layer_weight = layer_alpha / out[ALPHA]; + gfloat in_weight = 1.0f - layer_weight; + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b] * layer_weight + in[b] * in_weight; + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + while (samples--) + { + gfloat layer_alpha; + + layer_alpha = layer[ALPHA] * opacity; + if (has_mask) + layer_alpha *= *mask; + + out[ALPHA] = in[ALPHA]; + + if (out[ALPHA]) + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b] + (layer[b] - in[b]) * layer_alpha; + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + while (samples--) + { + gfloat layer_alpha; + + layer_alpha = layer[ALPHA] * opacity; + if (has_mask) + layer_alpha *= *mask; + + out[ALPHA] = layer_alpha; + + if (out[ALPHA]) + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + while (samples--) + { + gfloat layer_alpha; + + layer_alpha = layer[ALPHA] * opacity; + if (has_mask) + layer_alpha *= *mask; + + out[ALPHA] = in[ALPHA] * layer_alpha; + + if (out[ALPHA]) + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + else + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + } + + return TRUE; +} diff --git a/app/operations/layer-modes/gimpoperationnormal.h b/app/operations/layer-modes/gimpoperationnormal.h new file mode 100644 index 0000000..6fa1b36 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationnormal.h @@ -0,0 +1,91 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationnormal.h + * Copyright (C) 2012 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_NORMAL_H__ +#define __GIMP_OPERATION_NORMAL_H__ + + +#include "gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_NORMAL (gimp_operation_normal_get_type ()) +#define GIMP_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_NORMAL, GimpOperationNormal)) +#define GIMP_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_NORMAL, GimpOperationNormalClass)) +#define GIMP_IS_OPERATION_NORMAL(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_NORMAL)) +#define GIMP_IS_OPERATION_NORMAL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_NORMAL)) +#define GIMP_OPERATION_NORMAL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_NORMAL, GimpOperationNormalClass)) + + +typedef struct _GimpOperationNormal GimpOperationNormal; +typedef struct _GimpOperationNormalClass GimpOperationNormalClass; + +struct _GimpOperationNormal +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationNormalClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_normal_get_type (void) G_GNUC_CONST; + + +/* protected */ + +gboolean gimp_operation_normal_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + +#if COMPILE_SSE2_INTRINISICS + +gboolean gimp_operation_normal_process_sse2 (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + +#endif /* COMPILE_SSE2_INTRINISICS */ + +#if COMPILE_SSE4_1_INTRINISICS + +gboolean gimp_operation_normal_process_sse4 (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + +#endif /* COMPILE_SSE4_1_INTRINISICS */ + + +#endif /* __GIMP_OPERATION_NORMAL_H__ */ diff --git a/app/operations/layer-modes/gimpoperationpassthrough.c b/app/operations/layer-modes/gimpoperationpassthrough.c new file mode 100644 index 0000000..bc7d328 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationpassthrough.c @@ -0,0 +1,55 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationpassthrough.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationpassthrough.h" + + +G_DEFINE_TYPE (GimpOperationPassThrough, gimp_operation_pass_through, + GIMP_TYPE_OPERATION_REPLACE) + + +static void +gimp_operation_pass_through_class_init (GimpOperationPassThroughClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:pass-through", + "description", "GIMP pass through mode operation", + NULL); + + /* don't use REPLACE mode's specialized get_affected_region(); PASS_THROUGH + * behaves like an ordinary layer mode here. + */ + layer_mode_class->get_affected_region = NULL; +} + +static void +gimp_operation_pass_through_init (GimpOperationPassThrough *self) +{ +} diff --git a/app/operations/layer-modes/gimpoperationpassthrough.h b/app/operations/layer-modes/gimpoperationpassthrough.h new file mode 100644 index 0000000..5a5b838 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationpassthrough.h @@ -0,0 +1,54 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationpassthrough.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_PASS_THROUGH_H__ +#define __GIMP_OPERATION_PASS_THROUGH_H__ + + +#include "gimpoperationreplace.h" + + +#define GIMP_TYPE_OPERATION_PASS_THROUGH (gimp_operation_pass_through_get_type ()) +#define GIMP_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_PASS_THROUGH, GimpOperationPassThrough)) +#define GIMP_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_PASS_THROUGH, GimpOperationPassThroughClass)) +#define GIMP_IS_OPERATION_PASS_THROUGH(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_PASS_THROUGH)) +#define GIMP_IS_OPERATION_PASS_THROUGH_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_PASS_THROUGH)) +#define GIMP_OPERATION_PASS_THROUGH_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_PASS_THROUGH, GimpOperationPassThroughClass)) + + +typedef struct _GimpOperationPassThrough GimpOperationPassThrough; +typedef struct _GimpOperationPassThroughClass GimpOperationPassThroughClass; + +struct _GimpOperationPassThrough +{ + GimpOperationReplace parent_instance; +}; + +struct _GimpOperationPassThroughClass +{ + GimpOperationReplaceClass parent_class; +}; + + +GType gimp_operation_pass_through_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_PASS_THROUGH_H__ */ diff --git a/app/operations/layer-modes/gimpoperationreplace.c b/app/operations/layer-modes/gimpoperationreplace.c new file mode 100644 index 0000000..ed1ac19 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationreplace.c @@ -0,0 +1,347 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationreplace.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <string.h> + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimp-layer-modes.h" +#include "gimpoperationreplace.h" + + +static GeglRectangle gimp_operation_replace_get_bounding_box (GeglOperation *op); + +static gboolean gimp_operation_replace_parent_process (GeglOperation *op, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level); +static gboolean gimp_operation_replace_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); +static GimpLayerCompositeRegion gimp_operation_replace_get_affected_region (GimpOperationLayerMode *layer_mode); + + +G_DEFINE_TYPE (GimpOperationReplace, gimp_operation_replace, + GIMP_TYPE_OPERATION_LAYER_MODE) + +#define parent_class gimp_operation_replace_parent_class + + +static void +gimp_operation_replace_class_init (GimpOperationReplaceClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:replace", + "description", "GIMP replace mode operation", + NULL); + + operation_class->get_bounding_box = gimp_operation_replace_get_bounding_box; + + layer_mode_class->parent_process = gimp_operation_replace_parent_process; + layer_mode_class->process = gimp_operation_replace_process; + layer_mode_class->get_affected_region = gimp_operation_replace_get_affected_region; +} + +static void +gimp_operation_replace_init (GimpOperationReplace *self) +{ +} + +static GeglRectangle +gimp_operation_replace_get_bounding_box (GeglOperation *op) +{ + GimpOperationLayerMode *self = (gpointer) op; + GeglRectangle *in_rect; + GeglRectangle *aux_rect; + GeglRectangle *aux2_rect; + GeglRectangle src_rect = {}; + GeglRectangle dst_rect = {}; + GeglRectangle result; + GimpLayerCompositeRegion included_region; + + in_rect = gegl_operation_source_get_bounding_box (op, "input"); + aux_rect = gegl_operation_source_get_bounding_box (op, "aux"); + aux2_rect = gegl_operation_source_get_bounding_box (op, "aux2"); + + if (in_rect) + dst_rect = *in_rect; + + if (aux_rect) + { + src_rect = *aux_rect; + + if (aux2_rect) + gegl_rectangle_intersect (&src_rect, &src_rect, aux2_rect); + } + + if (self->is_last_node) + { + included_region = GIMP_LAYER_COMPOSITE_REGION_SOURCE; + } + else + { + included_region = gimp_layer_mode_get_included_region (self->layer_mode, + self->composite_mode); + } + + if (self->prop_opacity == 0.0) + included_region &= ~GIMP_LAYER_COMPOSITE_REGION_SOURCE; + else if (self->prop_opacity == 1.0 && ! aux2_rect) + included_region &= ~GIMP_LAYER_COMPOSITE_REGION_DESTINATION; + + gegl_rectangle_intersect (&result, &src_rect, &dst_rect); + + if (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE) + gegl_rectangle_bounding_box (&result, &result, &src_rect); + + if (included_region & GIMP_LAYER_COMPOSITE_REGION_DESTINATION) + gegl_rectangle_bounding_box (&result, &result, &dst_rect); + + return result; +} + +static gboolean +gimp_operation_replace_parent_process (GeglOperation *op, + GeglOperationContext *context, + const gchar *output_prop, + const GeglRectangle *result, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + GimpLayerCompositeRegion included_region; + + included_region = gimp_layer_mode_get_included_region + (layer_mode->layer_mode, layer_mode->composite_mode); + + /* if the layer's opacity is 100%, it has no mask, and its composite mode + * contains "aux" (the latter should always be the case in practice, + * currently,) we can just pass "aux" directly as output. + */ + if (layer_mode->opacity == 1.0 && + ! gegl_operation_context_get_object (context, "aux2") && + (included_region & GIMP_LAYER_COMPOSITE_REGION_SOURCE)) + { + GObject *aux; + + aux = gegl_operation_context_get_object (context, "aux"); + + gegl_operation_context_set_object (context, "output", aux); + + return TRUE; + } + /* the opposite case, where the opacity is 0%, is handled by + * GimpOperationLayerMode. + */ + else if (layer_mode->opacity == 0.0) + { + } + /* if both buffers are included in the result, and if both of them have the + * same content -- i.e., if they share the same storage, same alignment, and + * same abyss (or if the abyss is irrelevant) -- we can just pass either of + * them directly as output. + */ + else if (included_region == GIMP_LAYER_COMPOSITE_REGION_UNION) + { + GObject *input; + GObject *aux; + + input = gegl_operation_context_get_object (context, "input"); + aux = gegl_operation_context_get_object (context, "aux"); + + if (input && aux && + gegl_buffer_share_storage (GEGL_BUFFER (input), GEGL_BUFFER (aux))) + { + gint input_shift_x; + gint input_shift_y; + gint aux_shift_x; + gint aux_shift_y; + + g_object_get (input, + "shift-x", &input_shift_x, + "shift-y", &input_shift_y, + NULL); + g_object_get (aux, + "shift-x", &aux_shift_x, + "shift-y", &aux_shift_y, + NULL); + + if (input_shift_x == aux_shift_x && input_shift_y == aux_shift_y) + { + const GeglRectangle *input_abyss; + const GeglRectangle *aux_abyss; + + input_abyss = gegl_buffer_get_abyss (GEGL_BUFFER (input)); + aux_abyss = gegl_buffer_get_abyss (GEGL_BUFFER (aux)); + + if (gegl_rectangle_equal (input_abyss, aux_abyss) || + (gegl_rectangle_contains (input_abyss, result) && + gegl_rectangle_contains (aux_abyss, result))) + { + gegl_operation_context_set_object (context, "output", input); + + return TRUE; + } + } + } + } + + return GIMP_OPERATION_LAYER_MODE_CLASS (parent_class)->parent_process ( + op, context, output_prop, result, level); +} + +static gboolean +gimp_operation_replace_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + const gboolean has_mask = mask != NULL; + + switch (layer_mode->composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) + { + gfloat opacity_value = opacity; + gfloat new_alpha; + gfloat ratio; + gint b; + + if (has_mask) + opacity_value *= *mask; + + new_alpha = (layer[ALPHA] - in[ALPHA]) * opacity_value + in[ALPHA]; + + ratio = opacity_value; + + if (new_alpha) + ratio *= layer[ALPHA] / new_alpha; + + for (b = RED; b < ALPHA; b++) + out[b] = (layer[b] - in[b]) * ratio + in[b]; + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + while (samples--) + { + gfloat opacity_value = opacity; + gfloat new_alpha; + gint b; + + if (has_mask) + opacity_value *= *mask; + + new_alpha = in[ALPHA] * (1.0f - opacity_value); + + for (b = RED; b < ALPHA; b++) + out[b] = in[b]; + + out[ALPHA] = new_alpha; + + in += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + while (samples--) + { + gfloat opacity_value = opacity; + gfloat new_alpha; + gint b; + + if (has_mask) + opacity_value *= *mask; + + new_alpha = layer[ALPHA] * opacity_value; + + for (b = RED; b < ALPHA; b++) + out[b] = layer[b]; + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + memset (out, 0, 4 * samples * sizeof (gfloat)); + break; + } + + return TRUE; +} + +static GimpLayerCompositeRegion +gimp_operation_replace_get_affected_region (GimpOperationLayerMode *layer_mode) +{ + GimpLayerCompositeRegion affected_region = GIMP_LAYER_COMPOSITE_REGION_INTERSECTION; + + if (layer_mode->prop_opacity != 0.0) + affected_region |= GIMP_LAYER_COMPOSITE_REGION_DESTINATION; + + /* if opacity != 1.0, or we have a mask, then we also affect SOURCE, but this + * is considered the case anyway, so no need for special handling. + */ + + return affected_region; +} diff --git a/app/operations/layer-modes/gimpoperationreplace.h b/app/operations/layer-modes/gimpoperationreplace.h new file mode 100644 index 0000000..f8d7b0c --- /dev/null +++ b/app/operations/layer-modes/gimpoperationreplace.h @@ -0,0 +1,53 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationreplace.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_REPLACE_H__ +#define __GIMP_OPERATION_REPLACE_H__ + + +#include "gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_REPLACE (gimp_operation_replace_get_type ()) +#define GIMP_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_REPLACE, GimpOperationReplace)) +#define GIMP_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_REPLACE, GimpOperationReplaceClass)) +#define GIMP_IS_OPERATION_REPLACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_REPLACE)) +#define GIMP_IS_OPERATION_REPLACE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_REPLACE)) +#define GIMP_OPERATION_REPLACE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_REPLACE, GimpOperationReplaceClass)) + + +typedef struct _GimpOperationReplace GimpOperationReplace; +typedef struct _GimpOperationReplaceClass GimpOperationReplaceClass; + +struct _GimpOperationReplace +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationReplaceClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_replace_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_REPLACE_H__ */ diff --git a/app/operations/layer-modes/gimpoperationsplit.c b/app/operations/layer-modes/gimpoperationsplit.c new file mode 100644 index 0000000..fe83d3f --- /dev/null +++ b/app/operations/layer-modes/gimpoperationsplit.c @@ -0,0 +1,213 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsplit.c + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gegl-plugin.h> + +#include "../operations-types.h" + +#include "gimpoperationsplit.h" + + +static gboolean gimp_operation_split_process (GeglOperation *op, + void *in, + void *layer, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + + +G_DEFINE_TYPE (GimpOperationSplit, gimp_operation_split, + GIMP_TYPE_OPERATION_LAYER_MODE) + + +static void +gimp_operation_split_class_init (GimpOperationSplitClass *klass) +{ + GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass); + GimpOperationLayerModeClass *layer_mode_class = GIMP_OPERATION_LAYER_MODE_CLASS (klass); + + gegl_operation_class_set_keys (operation_class, + "name", "gimp:split", + "description", "GIMP split mode operation", + NULL); + + layer_mode_class->process = gimp_operation_split_process; +} + +static void +gimp_operation_split_init (GimpOperationSplit *self) +{ +} + +static gboolean +gimp_operation_split_process (GeglOperation *op, + void *in_p, + void *layer_p, + void *mask_p, + void *out_p, + glong samples, + const GeglRectangle *roi, + gint level) +{ + GimpOperationLayerMode *layer_mode = (gpointer) op; + gfloat *in = in_p; + gfloat *out = out_p; + gfloat *layer = layer_p; + gfloat *mask = mask_p; + gfloat opacity = layer_mode->opacity; + const gboolean has_mask = mask != NULL; + + switch (layer_mode->composite_mode) + { + case GIMP_LAYER_COMPOSITE_UNION: + while (samples--) + { + gfloat in_alpha = in[ALPHA]; + gfloat layer_alpha = layer[ALPHA] * opacity; + gfloat new_alpha; + gint b; + + if (has_mask) + layer_alpha *= *mask; + + if (layer_alpha <= in_alpha) + { + new_alpha = in_alpha - layer_alpha; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + else + { + new_alpha = layer_alpha - in_alpha; + + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP: + case GIMP_LAYER_COMPOSITE_AUTO: + while (samples--) + { + gfloat in_alpha = in[ALPHA]; + gfloat layer_alpha = layer[ALPHA] * opacity; + gfloat new_alpha; + gint b; + + if (has_mask) + layer_alpha *= *mask; + + new_alpha = MAX (in_alpha - layer_alpha, 0.0f); + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER: + while (samples--) + { + gfloat in_alpha = in[ALPHA]; + gfloat layer_alpha = layer[ALPHA] * opacity; + gfloat new_alpha; + gint b; + + if (has_mask) + layer_alpha *= *mask; + + new_alpha = MAX (layer_alpha - in_alpha, 0.0f); + + if (new_alpha != 0.0f) + { + for (b = RED; b < ALPHA; b++) + { + out[b] = layer[b]; + } + } + else + { + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + } + + out[ALPHA] = new_alpha; + + in += 4; + layer += 4; + out += 4; + + if (has_mask) + mask++; + } + break; + + case GIMP_LAYER_COMPOSITE_INTERSECTION: + while (samples--) + { + gint b; + + for (b = RED; b < ALPHA; b++) + { + out[b] = in[b]; + } + + out[ALPHA] = 0.0f; + + in += 4; + out += 4; + } + break; + } + + return TRUE; +} diff --git a/app/operations/layer-modes/gimpoperationsplit.h b/app/operations/layer-modes/gimpoperationsplit.h new file mode 100644 index 0000000..e1dbbe9 --- /dev/null +++ b/app/operations/layer-modes/gimpoperationsplit.h @@ -0,0 +1,54 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * gimpoperationsplit.h + * Copyright (C) 2008 Michael Natterer <mitch@gimp.org> + * 2017 Ell + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __GIMP_OPERATION_SPLIT_H__ +#define __GIMP_OPERATION_SPLIT_H__ + + +#include "gimpoperationlayermode.h" + + +#define GIMP_TYPE_OPERATION_SPLIT (gimp_operation_split_get_type ()) +#define GIMP_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplit)) +#define GIMP_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplitClass)) +#define GIMP_IS_OPERATION_SPLIT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_OPERATION_SPLIT)) +#define GIMP_IS_OPERATION_SPLIT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_OPERATION_SPLIT)) +#define GIMP_OPERATION_SPLIT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_OPERATION_SPLIT, GimpOperationSplitClass)) + + +typedef struct _GimpOperationSplit GimpOperationSplit; +typedef struct _GimpOperationSplitClass GimpOperationSplitClass; + +struct _GimpOperationSplit +{ + GimpOperationLayerMode parent_instance; +}; + +struct _GimpOperationSplitClass +{ + GimpOperationLayerModeClass parent_class; +}; + + +GType gimp_operation_split_get_type (void) G_GNUC_CONST; + + +#endif /* __GIMP_OPERATION_SPLIT_H__ */ diff --git a/app/operations/operations-enums.c b/app/operations/operations-enums.c new file mode 100644 index 0000000..1e8101d --- /dev/null +++ b/app/operations/operations-enums.c @@ -0,0 +1,370 @@ + +/* Generated data (by gimp-mkenums) */ + +#include "config.h" +#include <gio/gio.h> +#include "libgimpbase/gimpbase.h" +#include "operations-enums.h" +#include "gimp-intl.h" + +/* enumerations from "operations-enums.h" */ +GType +gimp_layer_color_space_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_LAYER_COLOR_SPACE_AUTO, "GIMP_LAYER_COLOR_SPACE_AUTO", "auto" }, + { GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, "GIMP_LAYER_COLOR_SPACE_RGB_LINEAR", "rgb-linear" }, + { GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, "GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL", "rgb-perceptual" }, + { GIMP_LAYER_COLOR_SPACE_LAB, "GIMP_LAYER_COLOR_SPACE_LAB", "lab" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_LAYER_COLOR_SPACE_AUTO, NC_("layer-color-space", "Auto"), NULL }, + { GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, NC_("layer-color-space", "RGB (linear)"), NULL }, + { GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, NC_("layer-color-space", "RGB (perceptual)"), NULL }, + { GIMP_LAYER_COLOR_SPACE_LAB, NC_("layer-color-space", "LAB"), NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpLayerColorSpace", values); + gimp_type_set_translation_context (type, "layer-color-space"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + +GType +gimp_layer_composite_mode_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_LAYER_COMPOSITE_AUTO, "GIMP_LAYER_COMPOSITE_AUTO", "auto" }, + { GIMP_LAYER_COMPOSITE_UNION, "GIMP_LAYER_COMPOSITE_UNION", "union" }, + { GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, "GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP", "clip-to-backdrop" }, + { GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER, "GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER", "clip-to-layer" }, + { GIMP_LAYER_COMPOSITE_INTERSECTION, "GIMP_LAYER_COMPOSITE_INTERSECTION", "intersection" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_LAYER_COMPOSITE_AUTO, NC_("layer-composite-mode", "Auto"), NULL }, + { GIMP_LAYER_COMPOSITE_UNION, NC_("layer-composite-mode", "Union"), NULL }, + { GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, NC_("layer-composite-mode", "Clip to backdrop"), NULL }, + { GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER, NC_("layer-composite-mode", "Clip to layer"), NULL }, + { GIMP_LAYER_COMPOSITE_INTERSECTION, NC_("layer-composite-mode", "Intersection"), NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpLayerCompositeMode", values); + gimp_type_set_translation_context (type, "layer-composite-mode"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + +GType +gimp_layer_mode_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_LAYER_MODE_NORMAL_LEGACY, "GIMP_LAYER_MODE_NORMAL_LEGACY", "normal-legacy" }, + { GIMP_LAYER_MODE_DISSOLVE, "GIMP_LAYER_MODE_DISSOLVE", "dissolve" }, + { GIMP_LAYER_MODE_BEHIND_LEGACY, "GIMP_LAYER_MODE_BEHIND_LEGACY", "behind-legacy" }, + { GIMP_LAYER_MODE_MULTIPLY_LEGACY, "GIMP_LAYER_MODE_MULTIPLY_LEGACY", "multiply-legacy" }, + { GIMP_LAYER_MODE_SCREEN_LEGACY, "GIMP_LAYER_MODE_SCREEN_LEGACY", "screen-legacy" }, + { GIMP_LAYER_MODE_OVERLAY_LEGACY, "GIMP_LAYER_MODE_OVERLAY_LEGACY", "overlay-legacy" }, + { GIMP_LAYER_MODE_DIFFERENCE_LEGACY, "GIMP_LAYER_MODE_DIFFERENCE_LEGACY", "difference-legacy" }, + { GIMP_LAYER_MODE_ADDITION_LEGACY, "GIMP_LAYER_MODE_ADDITION_LEGACY", "addition-legacy" }, + { GIMP_LAYER_MODE_SUBTRACT_LEGACY, "GIMP_LAYER_MODE_SUBTRACT_LEGACY", "subtract-legacy" }, + { GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY, "GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY", "darken-only-legacy" }, + { GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY, "GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY", "lighten-only-legacy" }, + { GIMP_LAYER_MODE_HSV_HUE_LEGACY, "GIMP_LAYER_MODE_HSV_HUE_LEGACY", "hsv-hue-legacy" }, + { GIMP_LAYER_MODE_HSV_SATURATION_LEGACY, "GIMP_LAYER_MODE_HSV_SATURATION_LEGACY", "hsv-saturation-legacy" }, + { GIMP_LAYER_MODE_HSL_COLOR_LEGACY, "GIMP_LAYER_MODE_HSL_COLOR_LEGACY", "hsl-color-legacy" }, + { GIMP_LAYER_MODE_HSV_VALUE_LEGACY, "GIMP_LAYER_MODE_HSV_VALUE_LEGACY", "hsv-value-legacy" }, + { GIMP_LAYER_MODE_DIVIDE_LEGACY, "GIMP_LAYER_MODE_DIVIDE_LEGACY", "divide-legacy" }, + { GIMP_LAYER_MODE_DODGE_LEGACY, "GIMP_LAYER_MODE_DODGE_LEGACY", "dodge-legacy" }, + { GIMP_LAYER_MODE_BURN_LEGACY, "GIMP_LAYER_MODE_BURN_LEGACY", "burn-legacy" }, + { GIMP_LAYER_MODE_HARDLIGHT_LEGACY, "GIMP_LAYER_MODE_HARDLIGHT_LEGACY", "hardlight-legacy" }, + { GIMP_LAYER_MODE_SOFTLIGHT_LEGACY, "GIMP_LAYER_MODE_SOFTLIGHT_LEGACY", "softlight-legacy" }, + { GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY, "GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY", "grain-extract-legacy" }, + { GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY, "GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY", "grain-merge-legacy" }, + { GIMP_LAYER_MODE_COLOR_ERASE_LEGACY, "GIMP_LAYER_MODE_COLOR_ERASE_LEGACY", "color-erase-legacy" }, + { GIMP_LAYER_MODE_OVERLAY, "GIMP_LAYER_MODE_OVERLAY", "overlay" }, + { GIMP_LAYER_MODE_LCH_HUE, "GIMP_LAYER_MODE_LCH_HUE", "lch-hue" }, + { GIMP_LAYER_MODE_LCH_CHROMA, "GIMP_LAYER_MODE_LCH_CHROMA", "lch-chroma" }, + { GIMP_LAYER_MODE_LCH_COLOR, "GIMP_LAYER_MODE_LCH_COLOR", "lch-color" }, + { GIMP_LAYER_MODE_LCH_LIGHTNESS, "GIMP_LAYER_MODE_LCH_LIGHTNESS", "lch-lightness" }, + { GIMP_LAYER_MODE_NORMAL, "GIMP_LAYER_MODE_NORMAL", "normal" }, + { GIMP_LAYER_MODE_BEHIND, "GIMP_LAYER_MODE_BEHIND", "behind" }, + { GIMP_LAYER_MODE_MULTIPLY, "GIMP_LAYER_MODE_MULTIPLY", "multiply" }, + { GIMP_LAYER_MODE_SCREEN, "GIMP_LAYER_MODE_SCREEN", "screen" }, + { GIMP_LAYER_MODE_DIFFERENCE, "GIMP_LAYER_MODE_DIFFERENCE", "difference" }, + { GIMP_LAYER_MODE_ADDITION, "GIMP_LAYER_MODE_ADDITION", "addition" }, + { GIMP_LAYER_MODE_SUBTRACT, "GIMP_LAYER_MODE_SUBTRACT", "subtract" }, + { GIMP_LAYER_MODE_DARKEN_ONLY, "GIMP_LAYER_MODE_DARKEN_ONLY", "darken-only" }, + { GIMP_LAYER_MODE_LIGHTEN_ONLY, "GIMP_LAYER_MODE_LIGHTEN_ONLY", "lighten-only" }, + { GIMP_LAYER_MODE_HSV_HUE, "GIMP_LAYER_MODE_HSV_HUE", "hsv-hue" }, + { GIMP_LAYER_MODE_HSV_SATURATION, "GIMP_LAYER_MODE_HSV_SATURATION", "hsv-saturation" }, + { GIMP_LAYER_MODE_HSL_COLOR, "GIMP_LAYER_MODE_HSL_COLOR", "hsl-color" }, + { GIMP_LAYER_MODE_HSV_VALUE, "GIMP_LAYER_MODE_HSV_VALUE", "hsv-value" }, + { GIMP_LAYER_MODE_DIVIDE, "GIMP_LAYER_MODE_DIVIDE", "divide" }, + { GIMP_LAYER_MODE_DODGE, "GIMP_LAYER_MODE_DODGE", "dodge" }, + { GIMP_LAYER_MODE_BURN, "GIMP_LAYER_MODE_BURN", "burn" }, + { GIMP_LAYER_MODE_HARDLIGHT, "GIMP_LAYER_MODE_HARDLIGHT", "hardlight" }, + { GIMP_LAYER_MODE_SOFTLIGHT, "GIMP_LAYER_MODE_SOFTLIGHT", "softlight" }, + { GIMP_LAYER_MODE_GRAIN_EXTRACT, "GIMP_LAYER_MODE_GRAIN_EXTRACT", "grain-extract" }, + { GIMP_LAYER_MODE_GRAIN_MERGE, "GIMP_LAYER_MODE_GRAIN_MERGE", "grain-merge" }, + { GIMP_LAYER_MODE_VIVID_LIGHT, "GIMP_LAYER_MODE_VIVID_LIGHT", "vivid-light" }, + { GIMP_LAYER_MODE_PIN_LIGHT, "GIMP_LAYER_MODE_PIN_LIGHT", "pin-light" }, + { GIMP_LAYER_MODE_LINEAR_LIGHT, "GIMP_LAYER_MODE_LINEAR_LIGHT", "linear-light" }, + { GIMP_LAYER_MODE_HARD_MIX, "GIMP_LAYER_MODE_HARD_MIX", "hard-mix" }, + { GIMP_LAYER_MODE_EXCLUSION, "GIMP_LAYER_MODE_EXCLUSION", "exclusion" }, + { GIMP_LAYER_MODE_LINEAR_BURN, "GIMP_LAYER_MODE_LINEAR_BURN", "linear-burn" }, + { GIMP_LAYER_MODE_LUMA_DARKEN_ONLY, "GIMP_LAYER_MODE_LUMA_DARKEN_ONLY", "luma-darken-only" }, + { GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY, "GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY", "luma-lighten-only" }, + { GIMP_LAYER_MODE_LUMINANCE, "GIMP_LAYER_MODE_LUMINANCE", "luminance" }, + { GIMP_LAYER_MODE_COLOR_ERASE, "GIMP_LAYER_MODE_COLOR_ERASE", "color-erase" }, + { GIMP_LAYER_MODE_ERASE, "GIMP_LAYER_MODE_ERASE", "erase" }, + { GIMP_LAYER_MODE_MERGE, "GIMP_LAYER_MODE_MERGE", "merge" }, + { GIMP_LAYER_MODE_SPLIT, "GIMP_LAYER_MODE_SPLIT", "split" }, + { GIMP_LAYER_MODE_PASS_THROUGH, "GIMP_LAYER_MODE_PASS_THROUGH", "pass-through" }, + { GIMP_LAYER_MODE_REPLACE, "GIMP_LAYER_MODE_REPLACE", "replace" }, + { GIMP_LAYER_MODE_ANTI_ERASE, "GIMP_LAYER_MODE_ANTI_ERASE", "anti-erase" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_LAYER_MODE_NORMAL_LEGACY, NC_("layer-mode", "Normal (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Normal (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_NORMAL_LEGACY, NC_("layer-mode", "Normal (l)"), NULL }, + { GIMP_LAYER_MODE_DISSOLVE, NC_("layer-mode", "Dissolve"), NULL }, + { GIMP_LAYER_MODE_BEHIND_LEGACY, NC_("layer-mode", "Behind (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Behind (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_BEHIND_LEGACY, NC_("layer-mode", "Behind (l)"), NULL }, + { GIMP_LAYER_MODE_MULTIPLY_LEGACY, NC_("layer-mode", "Multiply (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Multiply (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_MULTIPLY_LEGACY, NC_("layer-mode", "Multiply (l)"), NULL }, + { GIMP_LAYER_MODE_SCREEN_LEGACY, NC_("layer-mode", "Screen (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Screen (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_SCREEN_LEGACY, NC_("layer-mode", "Screen (l)"), NULL }, + { GIMP_LAYER_MODE_OVERLAY_LEGACY, NC_("layer-mode", "Old broken Overlay"), NULL }, + /* Translators: this is an abbreviated version of "Old broken Overlay". + Keep it short. */ + { GIMP_LAYER_MODE_OVERLAY_LEGACY, NC_("layer-mode", "Old Overlay"), NULL }, + { GIMP_LAYER_MODE_DIFFERENCE_LEGACY, NC_("layer-mode", "Difference (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Difference (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_DIFFERENCE_LEGACY, NC_("layer-mode", "Difference (l)"), NULL }, + { GIMP_LAYER_MODE_ADDITION_LEGACY, NC_("layer-mode", "Addition (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Addition (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_ADDITION_LEGACY, NC_("layer-mode", "Addition (l)"), NULL }, + { GIMP_LAYER_MODE_SUBTRACT_LEGACY, NC_("layer-mode", "Subtract (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Subtract (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_SUBTRACT_LEGACY, NC_("layer-mode", "Subtract (l)"), NULL }, + { GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY, NC_("layer-mode", "Darken only (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Darken only (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY, NC_("layer-mode", "Darken only (l)"), NULL }, + { GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY, NC_("layer-mode", "Lighten only (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Lighten only (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY, NC_("layer-mode", "Lighten only (l)"), NULL }, + { GIMP_LAYER_MODE_HSV_HUE_LEGACY, NC_("layer-mode", "HSV Hue (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "HSV Hue (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_HSV_HUE_LEGACY, NC_("layer-mode", "HSV Hue (l)"), NULL }, + { GIMP_LAYER_MODE_HSV_SATURATION_LEGACY, NC_("layer-mode", "HSV Saturation (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "HSV Saturation (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_HSV_SATURATION_LEGACY, NC_("layer-mode", "HSV Saturation (l)"), NULL }, + { GIMP_LAYER_MODE_HSL_COLOR_LEGACY, NC_("layer-mode", "HSL Color (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "HSL Color (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_HSL_COLOR_LEGACY, NC_("layer-mode", "HSL Color (l)"), NULL }, + { GIMP_LAYER_MODE_HSV_VALUE_LEGACY, NC_("layer-mode", "HSV Value (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "HSV Value (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_HSV_VALUE_LEGACY, NC_("layer-mode", "HSV Value (l)"), NULL }, + { GIMP_LAYER_MODE_DIVIDE_LEGACY, NC_("layer-mode", "Divide (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Divide (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_DIVIDE_LEGACY, NC_("layer-mode", "Divide (l)"), NULL }, + { GIMP_LAYER_MODE_DODGE_LEGACY, NC_("layer-mode", "Dodge (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Dodge (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_DODGE_LEGACY, NC_("layer-mode", "Dodge (l)"), NULL }, + { GIMP_LAYER_MODE_BURN_LEGACY, NC_("layer-mode", "Burn (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Burn (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_BURN_LEGACY, NC_("layer-mode", "Burn (l)"), NULL }, + { GIMP_LAYER_MODE_HARDLIGHT_LEGACY, NC_("layer-mode", "Hard light (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Hard light (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_HARDLIGHT_LEGACY, NC_("layer-mode", "Hard light (l)"), NULL }, + { GIMP_LAYER_MODE_SOFTLIGHT_LEGACY, NC_("layer-mode", "Soft light (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Soft light (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_SOFTLIGHT_LEGACY, NC_("layer-mode", "Soft light (l)"), NULL }, + { GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY, NC_("layer-mode", "Grain extract (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Grain extract (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY, NC_("layer-mode", "Grain extract (l)"), NULL }, + { GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY, NC_("layer-mode", "Grain merge (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Grain merge (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY, NC_("layer-mode", "Grain merge (l)"), NULL }, + { GIMP_LAYER_MODE_COLOR_ERASE_LEGACY, NC_("layer-mode", "Color erase (legacy)"), NULL }, + /* Translators: this is an abbreviated version of "Color erase (legacy)". + Keep it short. */ + { GIMP_LAYER_MODE_COLOR_ERASE_LEGACY, NC_("layer-mode", "Color erase (l)"), NULL }, + { GIMP_LAYER_MODE_OVERLAY, NC_("layer-mode", "Overlay"), NULL }, + { GIMP_LAYER_MODE_LCH_HUE, NC_("layer-mode", "LCh Hue"), NULL }, + { GIMP_LAYER_MODE_LCH_CHROMA, NC_("layer-mode", "LCh Chroma"), NULL }, + { GIMP_LAYER_MODE_LCH_COLOR, NC_("layer-mode", "LCh Color"), NULL }, + { GIMP_LAYER_MODE_LCH_LIGHTNESS, NC_("layer-mode", "LCh Lightness"), NULL }, + { GIMP_LAYER_MODE_NORMAL, NC_("layer-mode", "Normal"), NULL }, + { GIMP_LAYER_MODE_BEHIND, NC_("layer-mode", "Behind"), NULL }, + { GIMP_LAYER_MODE_MULTIPLY, NC_("layer-mode", "Multiply"), NULL }, + { GIMP_LAYER_MODE_SCREEN, NC_("layer-mode", "Screen"), NULL }, + { GIMP_LAYER_MODE_DIFFERENCE, NC_("layer-mode", "Difference"), NULL }, + { GIMP_LAYER_MODE_ADDITION, NC_("layer-mode", "Addition"), NULL }, + { GIMP_LAYER_MODE_SUBTRACT, NC_("layer-mode", "Subtract"), NULL }, + { GIMP_LAYER_MODE_DARKEN_ONLY, NC_("layer-mode", "Darken only"), NULL }, + { GIMP_LAYER_MODE_LIGHTEN_ONLY, NC_("layer-mode", "Lighten only"), NULL }, + { GIMP_LAYER_MODE_HSV_HUE, NC_("layer-mode", "HSV Hue"), NULL }, + { GIMP_LAYER_MODE_HSV_SATURATION, NC_("layer-mode", "HSV Saturation"), NULL }, + { GIMP_LAYER_MODE_HSL_COLOR, NC_("layer-mode", "HSL Color"), NULL }, + { GIMP_LAYER_MODE_HSV_VALUE, NC_("layer-mode", "HSV Value"), NULL }, + { GIMP_LAYER_MODE_DIVIDE, NC_("layer-mode", "Divide"), NULL }, + { GIMP_LAYER_MODE_DODGE, NC_("layer-mode", "Dodge"), NULL }, + { GIMP_LAYER_MODE_BURN, NC_("layer-mode", "Burn"), NULL }, + { GIMP_LAYER_MODE_HARDLIGHT, NC_("layer-mode", "Hard light"), NULL }, + { GIMP_LAYER_MODE_SOFTLIGHT, NC_("layer-mode", "Soft light"), NULL }, + { GIMP_LAYER_MODE_GRAIN_EXTRACT, NC_("layer-mode", "Grain extract"), NULL }, + { GIMP_LAYER_MODE_GRAIN_MERGE, NC_("layer-mode", "Grain merge"), NULL }, + { GIMP_LAYER_MODE_VIVID_LIGHT, NC_("layer-mode", "Vivid light"), NULL }, + { GIMP_LAYER_MODE_PIN_LIGHT, NC_("layer-mode", "Pin light"), NULL }, + { GIMP_LAYER_MODE_LINEAR_LIGHT, NC_("layer-mode", "Linear light"), NULL }, + { GIMP_LAYER_MODE_HARD_MIX, NC_("layer-mode", "Hard mix"), NULL }, + { GIMP_LAYER_MODE_EXCLUSION, NC_("layer-mode", "Exclusion"), NULL }, + { GIMP_LAYER_MODE_LINEAR_BURN, NC_("layer-mode", "Linear burn"), NULL }, + { GIMP_LAYER_MODE_LUMA_DARKEN_ONLY, NC_("layer-mode", "Luma/Luminance darken only"), NULL }, + /* Translators: this is an abbreviated version of "Luma/Luminance darken only". + Keep it short. */ + { GIMP_LAYER_MODE_LUMA_DARKEN_ONLY, NC_("layer-mode", "Luma darken only"), NULL }, + { GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY, NC_("layer-mode", "Luma/Luminance lighten only"), NULL }, + /* Translators: this is an abbreviated version of "Luma/Luminance lighten only". + Keep it short. */ + { GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY, NC_("layer-mode", "Luma lighten only"), NULL }, + { GIMP_LAYER_MODE_LUMINANCE, NC_("layer-mode", "Luminance"), NULL }, + { GIMP_LAYER_MODE_COLOR_ERASE, NC_("layer-mode", "Color erase"), NULL }, + { GIMP_LAYER_MODE_ERASE, NC_("layer-mode", "Erase"), NULL }, + { GIMP_LAYER_MODE_MERGE, NC_("layer-mode", "Merge"), NULL }, + { GIMP_LAYER_MODE_SPLIT, NC_("layer-mode", "Split"), NULL }, + { GIMP_LAYER_MODE_PASS_THROUGH, NC_("layer-mode", "Pass through"), NULL }, + { GIMP_LAYER_MODE_REPLACE, NC_("layer-mode", "Replace"), NULL }, + { GIMP_LAYER_MODE_ANTI_ERASE, NC_("layer-mode", "Anti erase"), NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpLayerMode", values); + gimp_type_set_translation_context (type, "layer-mode"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + +GType +gimp_layer_mode_group_get_type (void) +{ + static const GEnumValue values[] = + { + { GIMP_LAYER_MODE_GROUP_DEFAULT, "GIMP_LAYER_MODE_GROUP_DEFAULT", "default" }, + { GIMP_LAYER_MODE_GROUP_LEGACY, "GIMP_LAYER_MODE_GROUP_LEGACY", "legacy" }, + { 0, NULL, NULL } + }; + + static const GimpEnumDesc descs[] = + { + { GIMP_LAYER_MODE_GROUP_DEFAULT, NC_("layer-mode-group", "Default"), NULL }, + { GIMP_LAYER_MODE_GROUP_LEGACY, NC_("layer-mode-group", "Legacy"), NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_enum_register_static ("GimpLayerModeGroup", values); + gimp_type_set_translation_context (type, "layer-mode-group"); + gimp_enum_set_value_descriptions (type, descs); + } + + return type; +} + +GType +gimp_layer_mode_context_get_type (void) +{ + static const GFlagsValue values[] = + { + { GIMP_LAYER_MODE_CONTEXT_LAYER, "GIMP_LAYER_MODE_CONTEXT_LAYER", "layer" }, + { GIMP_LAYER_MODE_CONTEXT_GROUP, "GIMP_LAYER_MODE_CONTEXT_GROUP", "group" }, + { GIMP_LAYER_MODE_CONTEXT_PAINT, "GIMP_LAYER_MODE_CONTEXT_PAINT", "paint" }, + { GIMP_LAYER_MODE_CONTEXT_FILTER, "GIMP_LAYER_MODE_CONTEXT_FILTER", "filter" }, + { GIMP_LAYER_MODE_CONTEXT_ALL, "GIMP_LAYER_MODE_CONTEXT_ALL", "all" }, + { 0, NULL, NULL } + }; + + static const GimpFlagsDesc descs[] = + { + { GIMP_LAYER_MODE_CONTEXT_LAYER, "GIMP_LAYER_MODE_CONTEXT_LAYER", NULL }, + { GIMP_LAYER_MODE_CONTEXT_GROUP, "GIMP_LAYER_MODE_CONTEXT_GROUP", NULL }, + { GIMP_LAYER_MODE_CONTEXT_PAINT, "GIMP_LAYER_MODE_CONTEXT_PAINT", NULL }, + { GIMP_LAYER_MODE_CONTEXT_FILTER, "GIMP_LAYER_MODE_CONTEXT_FILTER", NULL }, + { GIMP_LAYER_MODE_CONTEXT_ALL, "GIMP_LAYER_MODE_CONTEXT_ALL", NULL }, + { 0, NULL, NULL } + }; + + static GType type = 0; + + if (G_UNLIKELY (! type)) + { + type = g_flags_register_static ("GimpLayerModeContext", values); + gimp_type_set_translation_context (type, "layer-mode-context"); + gimp_flags_set_value_descriptions (type, descs); + } + + return type; +} + + +/* Generated data ends here */ + diff --git a/app/operations/operations-enums.h b/app/operations/operations-enums.h new file mode 100644 index 0000000..0dc51b9 --- /dev/null +++ b/app/operations/operations-enums.h @@ -0,0 +1,190 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * operations-enums.h + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __OPERATIONS_ENUMS_H__ +#define __OPERATIONS_ENUMS_H__ + + +#define GIMP_TYPE_LAYER_COLOR_SPACE (gimp_layer_color_space_get_type ()) + +GType gimp_layer_color_space_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_LAYER_COLOR_SPACE_AUTO, /*< desc="Auto" >*/ + GIMP_LAYER_COLOR_SPACE_RGB_LINEAR, /*< desc="RGB (linear)" >*/ + GIMP_LAYER_COLOR_SPACE_RGB_PERCEPTUAL, /*< desc="RGB (perceptual)" >*/ + GIMP_LAYER_COLOR_SPACE_LAB, /*< desc="LAB", pdb-skip >*/ +} GimpLayerColorSpace; + + +#define GIMP_TYPE_LAYER_COMPOSITE_MODE (gimp_layer_composite_mode_get_type ()) + +GType gimp_layer_composite_mode_get_type (void) G_GNUC_CONST; + +typedef enum +{ + GIMP_LAYER_COMPOSITE_AUTO, /*< desc="Auto" >*/ + GIMP_LAYER_COMPOSITE_UNION, /*< desc="Union" >*/ + GIMP_LAYER_COMPOSITE_CLIP_TO_BACKDROP, /*< desc="Clip to backdrop" >*/ + GIMP_LAYER_COMPOSITE_CLIP_TO_LAYER, /*< desc="Clip to layer" >*/ + GIMP_LAYER_COMPOSITE_INTERSECTION /*< desc="Intersection" >*/ +} GimpLayerCompositeMode; + + +#define GIMP_TYPE_LAYER_MODE (gimp_layer_mode_get_type ()) + +GType gimp_layer_mode_get_type (void) G_GNUC_CONST; + +typedef enum +{ + /* Modes that exist since ancient times */ + GIMP_LAYER_MODE_NORMAL_LEGACY, /*< desc="Normal (legacy)", abbrev="Normal (l)" >*/ + GIMP_LAYER_MODE_DISSOLVE, /*< desc="Dissolve" >*/ + GIMP_LAYER_MODE_BEHIND_LEGACY, /*< desc="Behind (legacy)", abbrev="Behind (l)" >*/ + GIMP_LAYER_MODE_MULTIPLY_LEGACY, /*< desc="Multiply (legacy)", abbrev="Multiply (l)" >*/ + GIMP_LAYER_MODE_SCREEN_LEGACY, /*< desc="Screen (legacy)", abbrev="Screen (l)" >*/ + GIMP_LAYER_MODE_OVERLAY_LEGACY, /*< desc="Old broken Overlay", abbrev="Old Overlay" >*/ + GIMP_LAYER_MODE_DIFFERENCE_LEGACY, /*< desc="Difference (legacy)", abbrev="Difference (l)" >*/ + GIMP_LAYER_MODE_ADDITION_LEGACY, /*< desc="Addition (legacy)", abbrev="Addition (l)" >*/ + GIMP_LAYER_MODE_SUBTRACT_LEGACY, /*< desc="Subtract (legacy)", abbrev="Subtract (l)" >*/ + GIMP_LAYER_MODE_DARKEN_ONLY_LEGACY, /*< desc="Darken only (legacy)", abbrev="Darken only (l)" >*/ + GIMP_LAYER_MODE_LIGHTEN_ONLY_LEGACY, /*< desc="Lighten only (legacy)", abbrev="Lighten only (l)" >*/ + GIMP_LAYER_MODE_HSV_HUE_LEGACY, /*< desc="HSV Hue (legacy)", abbrev="HSV Hue (l)" >*/ + GIMP_LAYER_MODE_HSV_SATURATION_LEGACY, /*< desc="HSV Saturation (legacy)", abbrev="HSV Saturation (l)" >*/ + GIMP_LAYER_MODE_HSL_COLOR_LEGACY, /*< desc="HSL Color (legacy)", abbrev="HSL Color (l)" >*/ + GIMP_LAYER_MODE_HSV_VALUE_LEGACY, /*< desc="HSV Value (legacy)", abbrev="HSV Value (l)" >*/ + GIMP_LAYER_MODE_DIVIDE_LEGACY, /*< desc="Divide (legacy)", abbrev="Divide (l)" >*/ + GIMP_LAYER_MODE_DODGE_LEGACY, /*< desc="Dodge (legacy)", abbrev="Dodge (l)" >*/ + GIMP_LAYER_MODE_BURN_LEGACY, /*< desc="Burn (legacy)", abbrev="Burn (l)" >*/ + GIMP_LAYER_MODE_HARDLIGHT_LEGACY, /*< desc="Hard light (legacy)", abbrev="Hard light (l)" >*/ + + /* Since 2.8 (XCF version 2) */ + GIMP_LAYER_MODE_SOFTLIGHT_LEGACY, /*< desc="Soft light (legacy)", abbrev="Soft light (l)" >*/ + GIMP_LAYER_MODE_GRAIN_EXTRACT_LEGACY, /*< desc="Grain extract (legacy)", abbrev="Grain extract (l)" >*/ + GIMP_LAYER_MODE_GRAIN_MERGE_LEGACY, /*< desc="Grain merge (legacy)", abbrev="Grain merge (l)" >*/ + GIMP_LAYER_MODE_COLOR_ERASE_LEGACY, /*< desc="Color erase (legacy)", abbrev="Color erase (l)" >*/ + + /* Since 2.10 (XCF version 9) */ + GIMP_LAYER_MODE_OVERLAY, /*< desc="Overlay" >*/ + GIMP_LAYER_MODE_LCH_HUE, /*< desc="LCh Hue" >*/ + GIMP_LAYER_MODE_LCH_CHROMA, /*< desc="LCh Chroma" >*/ + GIMP_LAYER_MODE_LCH_COLOR, /*< desc="LCh Color" >*/ + GIMP_LAYER_MODE_LCH_LIGHTNESS, /*< desc="LCh Lightness" >*/ + + /* Since 2.10 (XCF version 10) */ + GIMP_LAYER_MODE_NORMAL, /*< desc="Normal" >*/ + GIMP_LAYER_MODE_BEHIND, /*< desc="Behind" >*/ + GIMP_LAYER_MODE_MULTIPLY, /*< desc="Multiply" >*/ + GIMP_LAYER_MODE_SCREEN, /*< desc="Screen" >*/ + GIMP_LAYER_MODE_DIFFERENCE, /*< desc="Difference" >*/ + GIMP_LAYER_MODE_ADDITION, /*< desc="Addition" >*/ + GIMP_LAYER_MODE_SUBTRACT, /*< desc="Subtract" >*/ + GIMP_LAYER_MODE_DARKEN_ONLY, /*< desc="Darken only" >*/ + GIMP_LAYER_MODE_LIGHTEN_ONLY, /*< desc="Lighten only" >*/ + GIMP_LAYER_MODE_HSV_HUE, /*< desc="HSV Hue" >*/ + GIMP_LAYER_MODE_HSV_SATURATION, /*< desc="HSV Saturation" >*/ + GIMP_LAYER_MODE_HSL_COLOR, /*< desc="HSL Color" >*/ + GIMP_LAYER_MODE_HSV_VALUE, /*< desc="HSV Value" >*/ + GIMP_LAYER_MODE_DIVIDE, /*< desc="Divide" >*/ + GIMP_LAYER_MODE_DODGE, /*< desc="Dodge" >*/ + GIMP_LAYER_MODE_BURN, /*< desc="Burn" >*/ + GIMP_LAYER_MODE_HARDLIGHT, /*< desc="Hard light" >*/ + GIMP_LAYER_MODE_SOFTLIGHT, /*< desc="Soft light" >*/ + GIMP_LAYER_MODE_GRAIN_EXTRACT, /*< desc="Grain extract" >*/ + GIMP_LAYER_MODE_GRAIN_MERGE, /*< desc="Grain merge" >*/ + GIMP_LAYER_MODE_VIVID_LIGHT, /*< desc="Vivid light" >*/ + GIMP_LAYER_MODE_PIN_LIGHT, /*< desc="Pin light" >*/ + GIMP_LAYER_MODE_LINEAR_LIGHT, /*< desc="Linear light" >*/ + GIMP_LAYER_MODE_HARD_MIX, /*< desc="Hard mix" >*/ + GIMP_LAYER_MODE_EXCLUSION, /*< desc="Exclusion" >*/ + GIMP_LAYER_MODE_LINEAR_BURN, /*< desc="Linear burn" >*/ + GIMP_LAYER_MODE_LUMA_DARKEN_ONLY, /*< desc="Luma/Luminance darken only", abbrev="Luma darken only" >*/ + GIMP_LAYER_MODE_LUMA_LIGHTEN_ONLY, /*< desc="Luma/Luminance lighten only", abbrev="Luma lighten only" >*/ + GIMP_LAYER_MODE_LUMINANCE, /*< desc="Luminance" >*/ + GIMP_LAYER_MODE_COLOR_ERASE, /*< desc="Color erase" >*/ + GIMP_LAYER_MODE_ERASE, /*< desc="Erase" >*/ + GIMP_LAYER_MODE_MERGE, /*< desc="Merge" >*/ + GIMP_LAYER_MODE_SPLIT, /*< desc="Split" >*/ + GIMP_LAYER_MODE_PASS_THROUGH, /*< desc="Pass through" >*/ + + /* Internal modes, not available to the PDB, must be kept at the end */ + GIMP_LAYER_MODE_REPLACE, /*< pdb-skip, desc="Replace" >*/ + GIMP_LAYER_MODE_ANTI_ERASE, /*< pdb-skip, desc="Anti erase" >*/ + + /* Layer mode menu separator */ + GIMP_LAYER_MODE_SEPARATOR = -1 /*< pdb-skip, skip >*/ +} GimpLayerMode; + + +#define GIMP_TYPE_LAYER_MODE_GROUP (gimp_layer_mode_group_get_type ()) + +GType gimp_layer_mode_group_get_type (void) G_GNUC_CONST; + +typedef enum /*< pdb-skip >*/ +{ + GIMP_LAYER_MODE_GROUP_DEFAULT, /*< desc="Default" >*/ + GIMP_LAYER_MODE_GROUP_LEGACY, /*< desc="Legacy" >*/ +} GimpLayerModeGroup; + + +#define GIMP_TYPE_LAYER_MODE_CONTEXT (gimp_layer_mode_context_get_type ()) + +GType gimp_layer_mode_context_get_type (void) G_GNUC_CONST; + +typedef enum /*< pdb-skip >*/ +{ + GIMP_LAYER_MODE_CONTEXT_LAYER = 1 << 0, + GIMP_LAYER_MODE_CONTEXT_GROUP = 1 << 1, + GIMP_LAYER_MODE_CONTEXT_PAINT = 1 << 2, + GIMP_LAYER_MODE_CONTEXT_FILTER = 1 << 3, + + GIMP_LAYER_MODE_CONTEXT_ALL = (GIMP_LAYER_MODE_CONTEXT_LAYER | + GIMP_LAYER_MODE_CONTEXT_GROUP | + GIMP_LAYER_MODE_CONTEXT_PAINT | + GIMP_LAYER_MODE_CONTEXT_FILTER) +} GimpLayerModeContext; + + +/* + * non-registered enums; register them if needed + */ + +typedef enum /*< pdb-skip, skip >*/ +{ + GIMP_LAYER_COMPOSITE_REGION_INTERSECTION = 0, + GIMP_LAYER_COMPOSITE_REGION_DESTINATION = 1 << 0, + GIMP_LAYER_COMPOSITE_REGION_SOURCE = 1 << 1, + GIMP_LAYER_COMPOSITE_REGION_UNION = (GIMP_LAYER_COMPOSITE_REGION_DESTINATION | + GIMP_LAYER_COMPOSITE_REGION_SOURCE), +} GimpLayerCompositeRegion; + +typedef enum /*< pdb-skip, skip >*/ +{ + GIMP_LAYER_MODE_FLAG_LEGACY = 1 << 0, + GIMP_LAYER_MODE_FLAG_BLEND_SPACE_IMMUTABLE = 1 << 1, + GIMP_LAYER_MODE_FLAG_COMPOSITE_SPACE_IMMUTABLE = 1 << 2, + GIMP_LAYER_MODE_FLAG_COMPOSITE_MODE_IMMUTABLE = 1 << 3, + GIMP_LAYER_MODE_FLAG_SUBTRACTIVE = 1 << 4, + GIMP_LAYER_MODE_FLAG_ALPHA_ONLY = 1 << 5, + GIMP_LAYER_MODE_FLAG_TRIVIAL = 1 << 6 +} GimpLayerModeFlags; + + +#endif /* __OPERATIONS_ENUMS_H__ */ diff --git a/app/operations/operations-types.h b/app/operations/operations-types.h new file mode 100644 index 0000000..15e97d8 --- /dev/null +++ b/app/operations/operations-types.h @@ -0,0 +1,76 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * operations-types.h + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#ifndef __OPERATIONS_TYPES_H__ +#define __OPERATIONS_TYPES_H__ + + +#include <gegl-types.h> + +#include "gegl/gimp-gegl-types.h" + +#include "operations-enums.h" + + +/* operations */ + +typedef struct _GimpOperationPointFilter GimpOperationPointFilter; +typedef struct _GimpOperationLayerMode GimpOperationLayerMode; + + +/* operation config objects */ + +typedef struct _GimpOperationSettings GimpOperationSettings; + +typedef struct _GimpBrightnessContrastConfig GimpBrightnessContrastConfig; +typedef struct _GimpCageConfig GimpCageConfig; +typedef struct _GimpColorBalanceConfig GimpColorBalanceConfig; +typedef struct _GimpColorizeConfig GimpColorizeConfig; +typedef struct _GimpCurvesConfig GimpCurvesConfig; +typedef struct _GimpDesaturateConfig GimpDesaturateConfig; +typedef struct _GimpHueSaturationConfig GimpHueSaturationConfig; +typedef struct _GimpLevelsConfig GimpLevelsConfig; +typedef struct _GimpPosterizeConfig GimpPosterizeConfig; +typedef struct _GimpThresholdConfig GimpThresholdConfig; + + +/* non-object types */ + +typedef struct _GimpCagePoint GimpCagePoint; + + +/* functions */ + +typedef gboolean (* GimpLayerModeFunc) (GeglOperation *operation, + void *in, + void *aux, + void *mask, + void *out, + glong samples, + const GeglRectangle *roi, + gint level); + +typedef void (* GimpLayerModeBlendFunc) (GeglOperation *operation, + const gfloat *in, + const gfloat *layer, + gfloat *out, + gint samples); + + +#endif /* __OPERATIONS_TYPES_H__ */ diff --git a/app/operations/tests/Makefile.am b/app/operations/tests/Makefile.am new file mode 100644 index 0000000..fdf0a9a --- /dev/null +++ b/app/operations/tests/Makefile.am @@ -0,0 +1,71 @@ +#TESTS = test-operations + +EXTRA_PROGRAMS = $(TESTS) +CLEANFILES = $(EXTRA_PROGRAMS) + +$(TESTS): output-dir + +libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la +libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la +libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la +libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la +libgimpmodule = $(top_builddir)/libgimpmodule/libgimpmodule-$(GIMP_API_VERSION).la +libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la +libgimpthumb = $(top_builddir)/libgimpthumb/libgimpthumb-$(GIMP_API_VERSION).la + +if OS_WIN32 +else +libm = -lm +endif + +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/app \ + $(GEGL_CFLAGS) \ + -I$(includedir) + +# We need this due to circular dependencies, see more detailed +# comments about it in app/Makefile.am +AM_LDFLAGS = \ + -Wl,-u,$(SYMPREFIX)xcf_init \ + -Wl,-u,$(SYMPREFIX)internal_procs_init \ + -Wl,-u,$(SYMPREFIX)gimp_plug_in_manager_restore \ + -Wl,-u,$(SYMPREFIX)gimp_pdb_compat_param_spec \ + -Wl,-u,$(SYMPREFIX)gimp_vectors_undo_get_type \ + -Wl,-u,$(SYMPREFIX)gimp_vectors_mod_undo_get_type \ + -Wl,-u,$(SYMPREFIX)gimp_vectors_prop_undo_get_type + +# Note that we have some duplicate entries here too to work around +# circular dependencies and systems on the same architectural layer as +# an alternative to LDFLAGS above +LDADD = \ + $(top_builddir)/app/xcf/libappxcf.a \ + $(top_builddir)/app/pdb/libappinternal-procs.a \ + $(top_builddir)/app/pdb/libapppdb.a \ + $(top_builddir)/app/plug-in/libappplug-in.a \ + $(top_builddir)/app/vectors/libappvectors.a \ + $(top_builddir)/app/core/libappcore.a \ + $(top_builddir)/app/file/libappfile.a \ + $(top_builddir)/app/text/libapptext.a \ + $(top_builddir)/app/paint/libapppaint.a \ + $(top_builddir)/app/config/libappconfig.a \ + $(top_builddir)/app/libapp.a \ + $(top_builddir)/app/gegl/libappgegl.a \ + $(top_builddir)/app/operations/libappoperations.a \ + $(libgimpconfig) \ + $(libgimpmath) \ + $(libgimpthumb) \ + $(libgimpcolor) \ + $(libgimpmodule) \ + $(libgimpbase) \ + $(GDK_PIXBUF_LIBS) \ + $(PANGOCAIRO_LIBS) \ + $(GEGL_LIBS) \ + $(GLIB_LIBS) \ + $(libm) + +output-dir: + mkdir -p output + +clean-local: + rm -rf output diff --git a/app/operations/tests/Makefile.in b/app/operations/tests/Makefile.in new file mode 100644 index 0000000..41af881 --- /dev/null +++ b/app/operations/tests/Makefile.in @@ -0,0 +1,815 @@ +# 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@ + +#TESTS = test-operations +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 = +subdir = app/operations/tests +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 $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +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 = +SOURCES = +DIST_SOURCES = +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +am__DIST_COMMON = $(srcdir)/Makefile.in +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@ +CLEANFILES = $(EXTRA_PROGRAMS) +libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la +libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la +libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la +libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la +libgimpmodule = $(top_builddir)/libgimpmodule/libgimpmodule-$(GIMP_API_VERSION).la +libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la +libgimpthumb = $(top_builddir)/libgimpthumb/libgimpthumb-$(GIMP_API_VERSION).la +@OS_WIN32_FALSE@libm = -lm +AM_CPPFLAGS = \ + -I$(top_srcdir) \ + -I$(top_srcdir)/app \ + $(GEGL_CFLAGS) \ + -I$(includedir) + + +# We need this due to circular dependencies, see more detailed +# comments about it in app/Makefile.am +AM_LDFLAGS = \ + -Wl,-u,$(SYMPREFIX)xcf_init \ + -Wl,-u,$(SYMPREFIX)internal_procs_init \ + -Wl,-u,$(SYMPREFIX)gimp_plug_in_manager_restore \ + -Wl,-u,$(SYMPREFIX)gimp_pdb_compat_param_spec \ + -Wl,-u,$(SYMPREFIX)gimp_vectors_undo_get_type \ + -Wl,-u,$(SYMPREFIX)gimp_vectors_mod_undo_get_type \ + -Wl,-u,$(SYMPREFIX)gimp_vectors_prop_undo_get_type + + +# Note that we have some duplicate entries here too to work around +# circular dependencies and systems on the same architectural layer as +# an alternative to LDFLAGS above +LDADD = \ + $(top_builddir)/app/xcf/libappxcf.a \ + $(top_builddir)/app/pdb/libappinternal-procs.a \ + $(top_builddir)/app/pdb/libapppdb.a \ + $(top_builddir)/app/plug-in/libappplug-in.a \ + $(top_builddir)/app/vectors/libappvectors.a \ + $(top_builddir)/app/core/libappcore.a \ + $(top_builddir)/app/file/libappfile.a \ + $(top_builddir)/app/text/libapptext.a \ + $(top_builddir)/app/paint/libapppaint.a \ + $(top_builddir)/app/config/libappconfig.a \ + $(top_builddir)/app/libapp.a \ + $(top_builddir)/app/gegl/libappgegl.a \ + $(top_builddir)/app/operations/libappoperations.a \ + $(libgimpconfig) \ + $(libgimpmath) \ + $(libgimpthumb) \ + $(libgimpcolor) \ + $(libgimpmodule) \ + $(libgimpbase) \ + $(GDK_PIXBUF_LIBS) \ + $(PANGOCAIRO_LIBS) \ + $(GEGL_LIBS) \ + $(GLIB_LIBS) \ + $(libm) + +all: all-am + +.SUFFIXES: +$(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 app/operations/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu app/operations/tests/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): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +tags TAGS: + +ctags CTAGS: + +cscope cscopelist: + + +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 +check: check-am +all-am: Makefile +installdirs: +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: + +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-libtool clean-local mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +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 Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + clean-local cscopelist-am ctags-am distclean distclean-generic \ + distclean-libtool distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am 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-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags-am uninstall uninstall-am + +.PRECIOUS: Makefile + + +$(TESTS): output-dir + +output-dir: + mkdir -p output + +clean-local: + rm -rf output + +# 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: |