Issue #10566: support GimpConfig and enum arguments and a few more fixes.

Now that we save GEGL operation arguments ourselves (instead of relying on
GEGL-generated XML), we can serialize and deserialize GimpConfig arguments which
are used in various operations implemented within GIMP core code.

Additionally:

- Also support saving and loading all enum types.
- PROP_EFFECT_ARGUMENT renamed to PROP_FILTER_ARGUMENT for consistent naming.
- A bit more accurate handling on save and load errors with dedicated messages
  to various issues.
- Use PROP_FLOAT_OPACITY instead of the obsolete 8-bit PROP_OPACITY (actually
  32-bit but stored as 0-255 int).
- Fix a leaking string.
This commit is contained in:
Jehan 2024-01-22 17:49:10 +01:00
parent 8b2975e0e8
commit 956f16e173
3 changed files with 125 additions and 34 deletions

View file

@ -26,6 +26,7 @@
#include "libgimpbase/gimpbase.h"
#include "libgimpcolor/gimpcolor.h"
#include "libgimpconfig/gimpconfig.h"
#include "core/core-types.h"
@ -2379,9 +2380,12 @@ xcf_load_effect_props (XcfInfo *info,
while (TRUE)
{
goffset next_prop;
if (! xcf_load_prop (info, &prop_type, &prop_size))
return FALSE;
next_prop = info->cp + prop_size;
switch (prop_type)
{
case PROP_END:
@ -2396,12 +2400,13 @@ xcf_load_effect_props (XcfInfo *info,
}
break;
case PROP_OPACITY:
case PROP_FLOAT_OPACITY:
{
guint32 opacity;
gfloat opacity;
xcf_read_int32 (info, &opacity, 1);
filter->opacity = (gdouble) opacity / 255.0;
xcf_read_float (info, &opacity, 1);
filter->opacity = (gdouble) opacity;
}
break;
@ -2470,30 +2475,43 @@ xcf_load_effect_props (XcfInfo *info,
}
break;
case PROP_EFFECT_ARGUMENT:
case PROP_FILTER_ARGUMENT:
{
gchar *filter_prop_name;
guint32 filter_type = FILTER_PROP_UNKNOWN;
GValue filter_prop_value = G_VALUE_INIT;
gboolean valid_property = FALSE;
GParamSpec *pspec;
gchar *filter_prop_name;
guint32 filter_type = FILTER_PROP_UNKNOWN;
GValue filter_prop_value = G_VALUE_INIT;
gboolean valid_prop_value = TRUE;
xcf_read_string (info, &filter_prop_name, 1);
xcf_read_int32 (info, (guint32 *) &filter_type, 1);
/* Check if valid property first */
if (gegl_operation_find_property (filter->operation_name,
filter_prop_name))
valid_property = TRUE;
if (! (pspec = gegl_operation_find_property (filter->operation_name,
filter_prop_name)))
{
gimp_message (info->gimp, G_OBJECT (info->progress),
GIMP_MESSAGE_WARNING,
"XCF Warning: filter \"%s\" does not "
"have the %s property. It was not set.",
filter->operation_name, filter_prop_name);
g_free (filter_prop_name);
break;
}
switch (filter_type)
{
case FILTER_PROP_INT:
case FILTER_PROP_ENUM:
{
guint32 value;
xcf_read_int32 (info, (guint32 *) &value, 1);
g_value_init (&filter_prop_value, G_TYPE_INT);
g_value_set_int (&filter_prop_value, value);
g_value_init (&filter_prop_value, pspec->value_type);
if (filter_type == FILTER_PROP_INT)
g_value_set_int (&filter_prop_value, value);
else
g_value_set_enum (&filter_prop_value, value);
}
break;
@ -2529,23 +2547,59 @@ xcf_load_effect_props (XcfInfo *info,
}
break;
case FILTER_PROP_CONFIG:
{
GObject *config;
gchar *serialized;
GError *error = NULL;
if (! g_type_is_a (pspec->value_type, GIMP_TYPE_CONFIG))
{
gimp_message (info->gimp, G_OBJECT (info->progress),
GIMP_MESSAGE_WARNING,
"XCF Warning: property '%s' of filter '%s' is a %s, which does not implement GimpConfig interface.\n",
filter_prop_name, filter->operation_name, g_type_name (pspec->value_type));
valid_prop_value = FALSE;
break;
}
xcf_read_string (info, &serialized, 1);
g_value_init (&filter_prop_value, pspec->value_type);
config = g_object_new (pspec->value_type, NULL);
if (gimp_config_deserialize_string (GIMP_CONFIG (config), serialized, -1, NULL, &error))
{
g_value_set_object (&filter_prop_value, config);
}
else
{
gimp_message (info->gimp, G_OBJECT (info->progress),
GIMP_MESSAGE_WARNING,
"XCF Warning: failure to deserialize config object for property '%s' of filter '%s': %s\n"
"Serialized config was: %s",
filter_prop_name, filter->operation_name,
error->message, serialized);
valid_prop_value = FALSE;
}
g_object_unref (config);
g_free (serialized);
}
break;
default:
gimp_message (info->gimp, G_OBJECT (info->progress),
GIMP_MESSAGE_WARNING,
"XCF Warning: property '%s' of filter '%s' holds unsupported type %s.\n",
filter_prop_name, filter->operation_name, g_type_name (pspec->value_type));
valid_prop_value = FALSE;
break;
}
if (valid_property)
{
gegl_node_set_property (filter->operation, filter_prop_name,
&filter_prop_value);
}
if (valid_prop_value)
gegl_node_set_property (filter->operation, filter_prop_name,
&filter_prop_value);
else
{
gimp_message (info->gimp, G_OBJECT (info->progress),
GIMP_MESSAGE_WARNING,
"XCF Warning: filter \"%s\" does not "
"have the %s property. It was not set.",
filter->operation_name, filter_prop_name);
}
xcf_seek_pos (info, next_prop, NULL);
g_value_unset (&filter_prop_value);
g_free (filter_prop_name);
@ -4453,4 +4507,4 @@ xcf_fix_item_path (GimpLayer *layer,
break;
}
}
}
}

View file

@ -71,7 +71,7 @@ typedef enum
PROP_LOCK_VISIBILITY = 42,
PROP_SELECTED_PATH = 43,
PROP_FILTER_REGION = 44,
PROP_EFFECT_ARGUMENT = 45
PROP_FILTER_ARGUMENT = 45
} PropType;
typedef enum
@ -105,7 +105,9 @@ typedef enum
FILTER_PROP_INT = 1,
FILTER_PROP_BOOL = 2,
FILTER_PROP_FLOAT = 3,
FILTER_PROP_STRING = 4
FILTER_PROP_STRING = 4,
FILTER_PROP_ENUM = 5,
FILTER_PROP_CONFIG = 6,
} FilterPropType;
typedef struct _XcfInfo XcfInfo;

View file

@ -26,6 +26,7 @@
#include "libgimpbase/gimpbase.h"
#include "libgimpcolor/gimpcolor.h"
#include "libgimpconfig/gimpconfig.h"
#include "config/gimpgeglconfig.h"
@ -837,11 +838,11 @@ xcf_save_effect_props (XcfInfo *info,
GParamSpec **pspecs;
guint n_pspecs;
GeglNode *node;
const gchar *operation;
gchar *operation;
xcf_check_error (xcf_save_prop (info, image, PROP_VISIBLE, error,
gimp_filter_get_active (filter)), ;);
xcf_check_error (xcf_save_prop (info, image, PROP_OPACITY, error,
xcf_check_error (xcf_save_prop (info, image, PROP_FLOAT_OPACITY, error,
gimp_drawable_filter_get_opacity (GIMP_DRAWABLE_FILTER (filter))), ;);
xcf_check_error (xcf_save_prop (info, image, PROP_MODE, error,
gimp_drawable_filter_get_paint_mode (GIMP_DRAWABLE_FILTER (filter))), ;);
@ -893,15 +894,33 @@ xcf_save_effect_props (XcfInfo *info,
break;
default:
if (g_type_is_a (G_VALUE_TYPE (&value), GIMP_TYPE_CONFIG))
{
filter_type = FILTER_PROP_CONFIG;
}
else if (g_type_is_a (G_VALUE_TYPE (&value), G_TYPE_ENUM))
{
filter_type = FILTER_PROP_ENUM;
}
else
{
gimp_message (info->gimp, G_OBJECT (info->progress),
GIMP_MESSAGE_WARNING,
"XCF Warning: argument \"%s\" of filter %s has "
"unsupported type %s. It was discarded.",
pspec->name, operation,
g_type_name (G_VALUE_TYPE (&value)));
}
break;
}
if (filter_type != FILTER_PROP_UNKNOWN)
xcf_check_error (xcf_save_prop (info, image, PROP_EFFECT_ARGUMENT, error,
xcf_check_error (xcf_save_prop (info, image, PROP_FILTER_ARGUMENT, error,
pspec->name, filter_type, value), ;);
g_value_unset (&value);
}
g_free (operation);
g_free (pspecs);
xcf_check_error (xcf_save_prop (info, image, PROP_END, error), ;);
@ -1726,7 +1745,7 @@ xcf_save_prop (XcfInfo *info,
}
break;
case PROP_EFFECT_ARGUMENT:
case PROP_FILTER_ARGUMENT:
{
const gchar *string = va_arg (args, const gchar *);
guint32 filter_type = va_arg (args, guint32);
@ -1748,8 +1767,14 @@ xcf_save_prop (XcfInfo *info,
switch (filter_type)
{
case FILTER_PROP_INT:
case FILTER_PROP_ENUM:
{
guint32 value = g_value_get_int (&filter_value);
guint32 value;
if (filter_type == FILTER_PROP_INT)
value = g_value_get_int (&filter_value);
else
value = g_value_get_enum (&filter_value);
xcf_write_int32_check_error (info, &value, 1, va_end (args));
}
@ -1779,6 +1804,16 @@ xcf_save_prop (XcfInfo *info,
}
break;
case FILTER_PROP_CONFIG:
{
GimpConfig *config = g_value_get_object (&filter_value);
gchar *value = gimp_config_serialize_to_string (config, NULL);
xcf_write_string_check_error (info, (gchar **) &value, 1, va_end (args));
g_free (value);
}
break;
default:
break;
}