mirror of https://github.com/GNOME/gimp.git
674 lines
22 KiB
C
674 lines
22 KiB
C
/* LIBGIMP - The GIMP Library
|
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
|
*
|
|
* gimpdrawable.c
|
|
*
|
|
* This library is free software: you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with this library. If not, see
|
|
* <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include "gimp.h"
|
|
|
|
#include <gobject/gvaluecollector.h>
|
|
|
|
#include "gimppixbuf.h"
|
|
#include "gimptilebackendplugin.h"
|
|
|
|
|
|
G_DEFINE_ABSTRACT_TYPE (GimpDrawable, gimp_drawable, GIMP_TYPE_ITEM)
|
|
|
|
#define parent_class gimp_drawable_parent_class
|
|
|
|
|
|
static void
|
|
gimp_drawable_class_init (GimpDrawableClass *klass)
|
|
{
|
|
}
|
|
|
|
static void
|
|
gimp_drawable_init (GimpDrawable *drawable)
|
|
{
|
|
}
|
|
|
|
|
|
/* Public API. */
|
|
|
|
/**
|
|
* gimp_drawable_get_by_id:
|
|
* @drawable_id: The drawable id.
|
|
*
|
|
* Returns a #GimpDrawable representing @drawable_id. This function
|
|
* calls gimp_item_get_by_id() and returns the item if it is drawable
|
|
* or %NULL otherwise.
|
|
*
|
|
* Returns: (nullable) (transfer none): a #GimpDrawable for
|
|
* @drawable_id or %NULL if @drawable_id does not represent a
|
|
* valid drawable. The object belongs to libgimp and you must
|
|
* not modify or unref it.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
GimpDrawable *
|
|
gimp_drawable_get_by_id (gint32 drawable_id)
|
|
{
|
|
GimpItem *item = gimp_item_get_by_id (drawable_id);
|
|
|
|
if (GIMP_IS_DRAWABLE (item))
|
|
return (GimpDrawable *) item;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_get_thumbnail_data:
|
|
* @drawable: the drawable
|
|
* @width: the requested thumbnail width (<= 1024 pixels)
|
|
* @height: the requested thumbnail height (<= 1024 pixels)
|
|
* @actual_width: (out): the resulting thumbnail's actual width
|
|
* @actual_height: (out): the resulting thumbnail's actual height
|
|
* @bpp: (out): the bytes per pixel of the returned thubmnail data
|
|
*
|
|
* Retrieves thumbnail data for the drawable identified by @drawable.
|
|
* The thumbnail will be not larger than the requested size.
|
|
*
|
|
* Returns: (transfer full) (nullable): thumbnail data or %NULL if
|
|
* @drawable is invalid.
|
|
**/
|
|
GBytes *
|
|
gimp_drawable_get_thumbnail_data (GimpDrawable *drawable,
|
|
gint width,
|
|
gint height,
|
|
gint *actual_width,
|
|
gint *actual_height,
|
|
gint *bpp)
|
|
{
|
|
GBytes *image_data;
|
|
|
|
g_return_val_if_fail (actual_width != NULL, NULL);
|
|
g_return_val_if_fail (actual_height != NULL, NULL);
|
|
g_return_val_if_fail (bpp != NULL, NULL);
|
|
|
|
_gimp_drawable_thumbnail (drawable,
|
|
width,
|
|
height,
|
|
actual_width,
|
|
actual_height,
|
|
bpp,
|
|
&image_data);
|
|
|
|
return image_data;
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_get_thumbnail:
|
|
* @drawable: the drawable
|
|
* @width: the requested thumbnail width (<= 1024 pixels)
|
|
* @height: the requested thumbnail height (<= 1024 pixels)
|
|
* @alpha: how to handle an alpha channel
|
|
*
|
|
* Retrieves a thumbnail pixbuf for the drawable identified by
|
|
* @drawable. The thumbnail will be not larger than the requested
|
|
* size.
|
|
*
|
|
* Returns: (transfer full): a new #GdkPixbuf
|
|
*
|
|
* Since: 2.2
|
|
**/
|
|
GdkPixbuf *
|
|
gimp_drawable_get_thumbnail (GimpDrawable *drawable,
|
|
gint width,
|
|
gint height,
|
|
GimpPixbufTransparency alpha)
|
|
{
|
|
gint thumb_width, thumb_height, thumb_bpp;
|
|
GBytes *data;
|
|
gsize data_size;
|
|
GdkPixbuf *pixbuf = NULL;
|
|
|
|
g_return_val_if_fail (width > 0 && width <= 1024, NULL);
|
|
g_return_val_if_fail (height > 0 && height <= 1024, NULL);
|
|
|
|
data = gimp_drawable_get_thumbnail_data (drawable,
|
|
width,
|
|
height,
|
|
&thumb_width,
|
|
&thumb_height,
|
|
&thumb_bpp);
|
|
|
|
if (data)
|
|
pixbuf = _gimp_pixbuf_from_data (g_bytes_unref_to_data (data, &data_size),
|
|
thumb_width, thumb_height, thumb_bpp,
|
|
alpha);
|
|
|
|
return pixbuf;
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_get_sub_thumbnail_data:
|
|
* @drawable: the drawable ID
|
|
* @src_x: the x coordinate of the area
|
|
* @src_y: the y coordinate of the area
|
|
* @src_width: the width of the area
|
|
* @src_height: the height of the area
|
|
* @dest_width: the requested thumbnail width (<= 1024 pixels)
|
|
* @dest_height: the requested thumbnail height (<= 1024 pixels)
|
|
* @actual_width: (out): the width of the returned thumbnail
|
|
* @actual_height: (out): the height of the returned thumbnail
|
|
* @bpp: (out): the bytes per pixel of the returned thumbnail data
|
|
*
|
|
* Retrieves thumbnail data for the drawable identified by @drawable.
|
|
* The thumbnail will be not larger than the requested size.
|
|
*
|
|
* Returns: (transfer full): thumbnail data or %NULL if
|
|
* @drawable is invalid.
|
|
**/
|
|
GBytes *
|
|
gimp_drawable_get_sub_thumbnail_data (GimpDrawable *drawable,
|
|
gint src_x,
|
|
gint src_y,
|
|
gint src_width,
|
|
gint src_height,
|
|
gint dest_width,
|
|
gint dest_height,
|
|
gint *actual_width,
|
|
gint *actual_height,
|
|
gint *bpp)
|
|
{
|
|
GBytes *image_bytes;
|
|
|
|
_gimp_drawable_sub_thumbnail (drawable,
|
|
src_x, src_y,
|
|
src_width, src_height,
|
|
dest_width,
|
|
dest_height,
|
|
actual_width,
|
|
actual_height,
|
|
bpp,
|
|
&image_bytes);
|
|
|
|
return image_bytes;
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_get_sub_thumbnail:
|
|
* @drawable: the drawable ID
|
|
* @src_x: the x coordinate of the area
|
|
* @src_y: the y coordinate of the area
|
|
* @src_width: the width of the area
|
|
* @src_height: the height of the area
|
|
* @dest_width: the requested thumbnail width (<= 1024 pixels)
|
|
* @dest_height: the requested thumbnail height (<= 1024 pixels)
|
|
* @alpha: how to handle an alpha channel
|
|
*
|
|
* Retrieves a thumbnail pixbuf for the drawable identified by
|
|
* @drawable. The thumbnail will be not larger than the requested
|
|
* size.
|
|
*
|
|
* Returns: (transfer full): a new #GdkPixbuf
|
|
*
|
|
* Since: 2.2
|
|
**/
|
|
GdkPixbuf *
|
|
gimp_drawable_get_sub_thumbnail (GimpDrawable *drawable,
|
|
gint src_x,
|
|
gint src_y,
|
|
gint src_width,
|
|
gint src_height,
|
|
gint dest_width,
|
|
gint dest_height,
|
|
GimpPixbufTransparency alpha)
|
|
{
|
|
gint thumb_width = dest_width;
|
|
gint thumb_height = dest_height;
|
|
gint thumb_bpp;
|
|
GBytes *data;
|
|
gsize data_size;
|
|
GdkPixbuf *pixbuf = NULL;
|
|
|
|
g_return_val_if_fail (src_x >= 0, NULL);
|
|
g_return_val_if_fail (src_y >= 0, NULL);
|
|
g_return_val_if_fail (src_width > 0, NULL);
|
|
g_return_val_if_fail (src_height > 0, NULL);
|
|
g_return_val_if_fail (dest_width > 0 && dest_width <= 1024, NULL);
|
|
g_return_val_if_fail (dest_height > 0 && dest_height <= 1024, NULL);
|
|
|
|
data = gimp_drawable_get_sub_thumbnail_data (drawable,
|
|
src_x, src_y,
|
|
src_width, src_height,
|
|
dest_width, dest_height,
|
|
&thumb_width,
|
|
&thumb_height,
|
|
&thumb_bpp);
|
|
|
|
if (data)
|
|
pixbuf = _gimp_pixbuf_from_data (g_bytes_unref_to_data (data, &data_size),
|
|
thumb_width, thumb_height, thumb_bpp,
|
|
alpha);
|
|
g_bytes_unref (data);
|
|
|
|
return pixbuf;
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_get_buffer:
|
|
* @drawable: the ID of the #GimpDrawable to get the buffer for.
|
|
*
|
|
* Returns a #GeglBuffer of a specified drawable. The buffer can be used
|
|
* like any other GEGL buffer. Its data will we synced back with the core
|
|
* drawable when the buffer gets destroyed, or when gegl_buffer_flush()
|
|
* is called.
|
|
*
|
|
* Returns: (transfer full): The #GeglBuffer.
|
|
*
|
|
* See Also: gimp_drawable_get_shadow_buffer()
|
|
*
|
|
* Since: 2.10
|
|
*/
|
|
GeglBuffer *
|
|
gimp_drawable_get_buffer (GimpDrawable *drawable)
|
|
{
|
|
if (gimp_item_is_valid (GIMP_ITEM (drawable)))
|
|
{
|
|
GeglTileBackend *backend;
|
|
GeglBuffer *buffer;
|
|
|
|
backend = _gimp_tile_backend_plugin_new (drawable, FALSE);
|
|
buffer = gegl_buffer_new_for_backend (NULL, backend);
|
|
g_object_unref (backend);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_get_shadow_buffer:
|
|
* @drawable: the ID of the #GimpDrawable to get the buffer for.
|
|
*
|
|
* Returns a #GeglBuffer of a specified drawable's shadow tiles. The
|
|
* buffer can be used like any other GEGL buffer. Its data will we
|
|
* synced back with the core drawable's shadow tiles when the buffer
|
|
* gets destroyed, or when gegl_buffer_flush() is called.
|
|
*
|
|
* Returns: (transfer full): The #GeglBuffer.
|
|
*
|
|
* Since: 2.10
|
|
*/
|
|
GeglBuffer *
|
|
gimp_drawable_get_shadow_buffer (GimpDrawable *drawable)
|
|
{
|
|
if (gimp_item_is_valid (GIMP_ITEM (drawable)))
|
|
{
|
|
GeglTileBackend *backend;
|
|
GeglBuffer *buffer;
|
|
|
|
backend = _gimp_tile_backend_plugin_new (drawable, TRUE);
|
|
buffer = gegl_buffer_new_for_backend (NULL, backend);
|
|
g_object_unref (backend);
|
|
|
|
return buffer;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_get_format:
|
|
* @drawable: the ID of the #GimpDrawable to get the format for.
|
|
*
|
|
* Returns the #Babl format of the drawable.
|
|
*
|
|
* Returns: The #Babl format.
|
|
*
|
|
* Since: 2.10
|
|
*/
|
|
const Babl *
|
|
gimp_drawable_get_format (GimpDrawable *drawable)
|
|
{
|
|
const Babl *format = NULL;
|
|
gchar *format_str = _gimp_drawable_get_format (drawable);
|
|
|
|
/* _gimp_drawable_get_format() only returns the encoding, so we
|
|
* create the actual space from the image's profile
|
|
*/
|
|
|
|
if (format_str)
|
|
{
|
|
const Babl *space = NULL;
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
|
|
|
|
if (gimp_item_is_layer (GIMP_ITEM (drawable)))
|
|
{
|
|
GimpColorProfile *profile = gimp_image_get_color_profile (image);
|
|
|
|
if (profile)
|
|
{
|
|
GError *error = NULL;
|
|
|
|
space = gimp_color_profile_get_space
|
|
(profile,
|
|
GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
|
|
&error);
|
|
|
|
if (! space)
|
|
{
|
|
g_printerr ("%s: failed to create Babl space from "
|
|
"profile: %s\n",
|
|
G_STRFUNC, error->message);
|
|
g_clear_error (&error);
|
|
}
|
|
|
|
g_object_unref (profile);
|
|
}
|
|
}
|
|
|
|
if (gimp_drawable_is_indexed (drawable))
|
|
{
|
|
const Babl *palette;
|
|
const Babl *palette_alpha;
|
|
const Babl *color_format;
|
|
guchar *colormap;
|
|
gint n_colors;
|
|
|
|
babl_new_palette_with_space (format_str, space,
|
|
&palette, &palette_alpha);
|
|
|
|
if (gimp_drawable_has_alpha (drawable))
|
|
format = palette_alpha;
|
|
else
|
|
format = palette;
|
|
|
|
color_format = babl_format_with_space ("R'G'B' u8", space);
|
|
colormap = gimp_palette_get_colormap (gimp_image_get_palette (image), color_format, &n_colors, NULL);
|
|
|
|
if (colormap)
|
|
{
|
|
babl_palette_set_palette (format, color_format, colormap, n_colors);
|
|
g_free (colormap);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
format = babl_format_with_space (format_str, space);
|
|
}
|
|
|
|
g_free (format_str);
|
|
}
|
|
|
|
return format;
|
|
}
|
|
/**
|
|
* gimp_drawable_get_thumbnail_format:
|
|
* @drawable: the ID of the #GimpDrawable to get the thumbnail format for.
|
|
*
|
|
* Returns the #Babl thumbnail format of the drawable.
|
|
*
|
|
* Returns: The #Babl thumbnail format.
|
|
*
|
|
* Since: 2.10.14
|
|
*/
|
|
const Babl *
|
|
gimp_drawable_get_thumbnail_format (GimpDrawable *drawable)
|
|
{
|
|
const Babl *format = NULL;
|
|
gchar *format_str = _gimp_drawable_get_thumbnail_format (drawable);
|
|
|
|
if (format_str)
|
|
{
|
|
format = babl_format (format_str);
|
|
g_free (format_str);
|
|
}
|
|
|
|
return format;
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_append_filter:
|
|
* @drawable: The drawable.
|
|
* @filter: The drawable filter to append.
|
|
*
|
|
* This procedure appends the specified drawable effect at the top of the
|
|
* effect list of @drawable.
|
|
*
|
|
* The @drawable argument must be the same as the one used when you
|
|
* created the effect with [ctor@Gimp.DrawableFilter.new].
|
|
* Some effects may be slower than others to render. In order to
|
|
* minimize processing time, it is preferred to customize the
|
|
* operation's arguments as received with
|
|
* [method@Gimp.DrawableFilter.get_config] before adding the effect.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
void
|
|
gimp_drawable_append_filter (GimpDrawable *drawable,
|
|
GimpDrawableFilter *filter)
|
|
{
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
|
|
|
|
gimp_drawable_filter_update (filter);
|
|
_gimp_drawable_append_filter_private (drawable, filter);
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_merge_filter:
|
|
* @drawable: The drawable.
|
|
* @filter: The drawable filter to merge.
|
|
*
|
|
* This procedure applies the specified drawable effect on @drawable
|
|
* and merge it (therefore before any non-destructive effects are
|
|
* computed).
|
|
*
|
|
* The @drawable argument must be the same as the one used when you
|
|
* created the effect with [ctor@Gimp.DrawableFilter.new].
|
|
* Once this is run, @filter is not valid anymore and you should not
|
|
* try to do anything with it. In particular, you must customize the
|
|
* operation's arguments as received with
|
|
* [method@Gimp.DrawableFilter.get_config] or set the filter's opacity
|
|
* and blend mode before merging the effect.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
void
|
|
gimp_drawable_merge_filter (GimpDrawable *drawable,
|
|
GimpDrawableFilter *filter)
|
|
{
|
|
g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
|
|
g_return_if_fail (GIMP_IS_DRAWABLE_FILTER (filter));
|
|
|
|
gimp_drawable_filter_update (filter);
|
|
_gimp_drawable_merge_filter_private (drawable, filter);
|
|
}
|
|
|
|
/**
|
|
* gimp_drawable_append_new_filter: (skip)
|
|
* @drawable: The #GimpDrawable.
|
|
* @operation_name: The GEGL operation's name.
|
|
* @name: The effect name.
|
|
* @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 appending with
|
|
* [method@Gimp.Drawable.append_filter]
|
|
*
|
|
* The variable arguments are couples of an argument name followed by a
|
|
* value, NULL-terminated, such as:
|
|
*
|
|
* ```C
|
|
* filter = gimp_drawable_append_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);
|
|
* ```
|
|
*
|
|
* Returns: (transfer none): The newly created filter.
|
|
*/
|
|
GimpDrawableFilter *
|
|
gimp_drawable_append_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_val_if_fail (GIMP_IS_DRAWABLE (drawable), NULL);
|
|
g_return_val_if_fail (opacity >= 0.0 && opacity <= 1.0, NULL);
|
|
|
|
filter = gimp_drawable_filter_new (drawable, operation_name, name);
|
|
|
|
g_return_val_if_fail (filter != NULL, 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_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 (GIMP_IS_DRAWABLE (drawable));
|
|
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_merge_filter (drawable, filter);
|
|
}
|