app, extensions, libgimp: new convenient function gimp_drawable_merge_new_filter().

Also adding an example of using it in the C goat exercise, though I
leave it commented out because showing code for direct GEGL usage is
also of interest.

As a side update, I am adding proper support of the NULL or empty string
value for the filter name. In this case, the default human-readable
title of the operation will be used instead.
This commit is contained in:
Jehan 2024-12-12 17:14:59 +01:00
parent 0223694583
commit 58b11d9d98
5 changed files with 115 additions and 0 deletions

View File

@ -30,6 +30,7 @@
#include <cairo.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include <gegl-plugin.h>
#include <gegl-paramspecs.h>
#include "libgimpbase/gimpbase.h"
@ -307,6 +308,16 @@ gimp_drawable_filter_new (GimpDrawable *drawable,
g_return_val_if_fail (GEGL_IS_NODE (operation), NULL);
g_return_val_if_fail (gegl_node_has_pad (operation, "output"), NULL);
if (undo_desc == NULL || strlen (undo_desc) == 0)
{
GeglOperation *op;
GeglOperationClass *opclass;
op = gegl_node_get_gegl_operation (operation);
opclass = GEGL_OPERATION_GET_CLASS (op);
undo_desc = gegl_operation_class_get_key (opclass, "title");
}
filter = g_object_new (GIMP_TYPE_DRAWABLE_FILTER,
"name", undo_desc,
"icon-name", icon_name,

View File

@ -279,6 +279,15 @@ goat_run (GimpProcedure *procedure,
gimp_displays_flush ();
gegl_exit ();
#if 0
/* Above is an example of using GEGL API directly within the
* plug-in process. Below is a variant using drawable filters. The
* operation rendering is done core process side.
*/
gimp_drawable_merge_new_filter (drawable, "gegl:invert", NULL,
GIMP_LAYER_MODE_REPLACE, 1.0,
NULL);
#endif
}
return gimp_procedure_new_return_values (procedure, status, NULL);

View File

@ -262,6 +262,7 @@ EXPORTS
gimp_drawable_mask_intersect
gimp_drawable_merge_filter
gimp_drawable_merge_filters
gimp_drawable_merge_new_filter
gimp_drawable_merge_shadow
gimp_drawable_offset
gimp_drawable_posterize

View File

@ -512,7 +512,95 @@ gimp_drawable_append_new_filter (GimpDrawable *drawable,
}
va_end (va_args);
gimp_drawable_filter_update (filter);
gimp_drawable_append_filter (drawable, filter);
return filter;
}
/**
* gimp_drawable_merge_new_filter: (skip)
* @drawable: The #GimpDrawable.
* @operation_name: The GEGL operation's name.
* @name: The effect name which will show in undo step.
* @mode: The blend mode.
* @opacity: The opacity from 0.0 (transparent) to 1.0 (opaque).
* @...: a %NULL-terminated list of operation argument names
* and values.
*
* Utility function which combines [ctor@Gimp.DrawableFilter.new]
* followed by setting arguments for the
* [class@Gimp.DrawableFilterConfig] returned by
* [method@Gimp.DrawableFilter.get_config], and finally applying the
* effect to @drawable with [method@Gimp.Drawable.merge_filter]
*
* The variable arguments are couples of an argument name followed by a
* value, NULL-terminated, such as:
*
* ```C
* filter = gimp_drawable_merge_new_filter (drawable,
* GIMP_LAYER_MODE_REPLACE, 1.0,
* "gegl:gaussian-blur", "My Gaussian Blur",
* "std-dev-x", 2.5,
* "std-dev-y", 2.5,
* "abyss-policy", "clamp",
* NULL);
* ```
*/
void
gimp_drawable_merge_new_filter (GimpDrawable *drawable,
const gchar *operation_name,
const gchar *name,
GimpLayerMode mode,
gdouble opacity,
...)
{
GimpDrawableFilter *filter;
GimpDrawableFilterConfig *config;
const gchar *arg_name;
va_list va_args;
g_return_if_fail (opacity >= 0.0 && opacity <= 1.0);
filter = gimp_drawable_filter_new (drawable, operation_name, name);
g_return_if_fail (filter != NULL);
config = gimp_drawable_filter_get_config (filter);
va_start (va_args, opacity);
while ((arg_name = va_arg (va_args, const gchar *)))
{
GParamSpec *pspec;
gchar *error = NULL;
GValue value = G_VALUE_INIT;
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), arg_name);
if (pspec == NULL)
{
g_warning ("%s: %s has no property named '%s'",
G_STRFUNC,
g_type_name (G_TYPE_FROM_INSTANCE (config)),
arg_name);
break;
}
g_value_init (&value, pspec->value_type);
G_VALUE_COLLECT (&value, va_args, G_VALUE_NOCOPY_CONTENTS, &error);
if (error)
{
g_warning ("%s: %s", G_STRFUNC, error);
g_free (error);
break;
}
g_object_set_property (G_OBJECT (config), arg_name, &value);
g_value_unset (&value);
}
va_end (va_args);
gimp_drawable_filter_set_blend_mode (filter, mode);
gimp_drawable_filter_set_opacity (filter, opacity);
gimp_drawable_filter_update (filter);
gimp_drawable_merge_filter (drawable, filter);
}

View File

@ -97,6 +97,12 @@ GimpDrawableFilter * gimp_drawable_append_new_filter (GimpDrawable *drawab
const gchar *operation_name,
const gchar *name,
...) G_GNUC_NULL_TERMINATED;
void gimp_drawable_merge_new_filter (GimpDrawable *drawable,
const gchar *operation_name,
const gchar *name,
GimpLayerMode mode,
gdouble opacity,
...) G_GNUC_NULL_TERMINATED;
G_END_DECLS