libgimpconfig: add support for GeglColor config properties.

GeglColor properties are serialized this way:
(propname "encoding" bpp pixel-data profile-size profile-data)
This commit is contained in:
Jehan 2023-11-15 02:28:34 +01:00
parent 4d0df90e26
commit cd32b3bffa
2 changed files with 173 additions and 2 deletions

View File

@ -101,6 +101,9 @@ static GTokenType gimp_config_deserialize_parasite_value (GValue *value,
static GTokenType gimp_config_deserialize_bytes (GValue *value,
GParamSpec *prop_spec,
GScanner *scanner);
static GTokenType gimp_config_deserialize_color (GValue *value,
GParamSpec *prop_spec,
GScanner *scanner);
static GTokenType gimp_config_deserialize_any (GValue *value,
GParamSpec *prop_spec,
GScanner *scanner);
@ -302,8 +305,9 @@ gimp_config_deserialize_property (GimpConfig *config,
}
else
{
if (G_VALUE_HOLDS_OBJECT (&value) &&
G_VALUE_TYPE (&value) != G_TYPE_FILE)
if (G_VALUE_HOLDS_OBJECT (&value) &&
G_VALUE_TYPE (&value) != G_TYPE_FILE &&
G_VALUE_TYPE (&value) != GEGL_TYPE_COLOR)
{
token = gimp_config_deserialize_object (&value,
config, prop_spec,
@ -396,6 +400,10 @@ gimp_config_deserialize_value (GValue *value,
{
return gimp_config_deserialize_bytes (value, prop_spec, scanner);
}
else if (prop_spec->value_type == GEGL_TYPE_COLOR)
{
return gimp_config_deserialize_color (value, prop_spec, scanner);
}
/* This fallback will only work for value_types that
* can be transformed from a string value.
@ -1084,6 +1092,131 @@ gimp_config_deserialize_bytes (GValue *value,
return G_TOKEN_RIGHT_PAREN;
}
static GTokenType
gimp_config_deserialize_color (GValue *value,
GParamSpec *prop_spec,
GScanner *scanner)
{
GTokenType token;
token = g_scanner_peek_next_token (scanner);
if (token == G_TOKEN_IDENTIFIER)
{
g_scanner_get_next_token (scanner);
if (g_ascii_strcasecmp (scanner->value.v_identifier, "null") != 0)
/* Do not fail the whole color parsing. Just output to stderr and assume
* a NULL color property.
*/
g_printerr ("%s: expected NULL identifier for color property '%s', got '%s'. "
"Assuming NULL instead.\n",
G_STRFUNC, prop_spec->name, scanner->value.v_identifier);
g_value_set_object (value, NULL);
}
else if (token == G_TOKEN_STRING)
{
const Babl *format;
const Babl *space = NULL;
GeglColor *color;
gchar *encoding;
guint8 *data;
gint data_length;
gint profile_data_length;
if (! gimp_scanner_parse_string (scanner, &encoding))
return G_TOKEN_STRING;
if (! babl_format_exists (encoding))
{
g_scanner_error (scanner,
"%s: format \"%s\" for color property '%s' is not a valid babl format.",
G_STRFUNC, encoding, prop_spec->name);
g_free (encoding);
return G_TOKEN_NONE;
}
format = babl_format (encoding);
g_free (encoding);
if (! gimp_scanner_parse_int (scanner, &data_length))
return G_TOKEN_INT;
if (data_length != babl_format_get_bytes_per_pixel (format))
{
g_scanner_error (scanner,
"%s: format \"%s\" expects %d bpp but color property '%s' was stored with %d bpp.",
G_STRFUNC, babl_get_name (format),
babl_format_get_bytes_per_pixel (format),
prop_spec->name, data_length);
return G_TOKEN_NONE;
}
if (! gimp_scanner_parse_data (scanner, data_length, &data))
return G_TOKEN_STRING;
if (! gimp_scanner_parse_int (scanner, &profile_data_length))
{
g_free (data);
return G_TOKEN_INT;
}
if (profile_data_length > 0)
{
GimpColorProfile *profile;
guint8 *profile_data;
GError *error = NULL;
if (! gimp_scanner_parse_data (scanner, profile_data_length, &profile_data))
{
g_free (data);
return G_TOKEN_STRING;
}
profile = gimp_color_profile_new_from_icc_profile (profile_data, profile_data_length, &error);
if (profile)
{
space = gimp_color_profile_get_space (profile,
GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
&error);
if (! space)
{
g_scanner_error (scanner,
"%s: failed to create Babl space for color property '%s' from profile: %s\n",
G_STRFUNC, prop_spec->name, error->message);
g_clear_error (&error);
}
g_object_unref (profile);
}
else
{
g_scanner_error (scanner,
"%s: invalid profile data for color property '%s': %s",
G_STRFUNC, prop_spec->name, error->message);
g_error_free (error);
}
format = babl_format_with_space (babl_format_get_encoding (format), space);
g_free (profile_data);
}
color = gegl_color_new (NULL);
gegl_color_set_pixel (color, format, data);
g_value_take_object (value, color);
g_free (data);
}
else
{
return G_TOKEN_INT;
}
return G_TOKEN_RIGHT_PAREN;
}
static GTokenType
gimp_config_deserialize_any (GValue *value,
GParamSpec *prop_spec,

View File

@ -296,6 +296,44 @@ gimp_config_serialize_property (GimpConfig *config,
gimp_config_writer_printf (writer, "%s", "NULL");
}
success = TRUE;
gimp_config_writer_close (writer);
}
else if (GIMP_VALUE_HOLDS_COLOR (&value))
{
GeglColor *color = g_value_get_object (&value);
gimp_config_writer_open (writer, param_spec->name);
if (color)
{
const gchar *encoding;
const Babl *format = gegl_color_get_format (color);
GBytes *bytes = gegl_color_get_bytes (color, format);
gconstpointer data;
gsize data_length;
guint8 *profile_data;
int profile_length = 0;
encoding = babl_format_get_encoding (format);
gimp_config_writer_string (writer, encoding);
data = g_bytes_get_data (bytes, &data_length);
gimp_config_writer_printf (writer, "%lu", data_length);
gimp_config_writer_data (writer, data_length, data);
profile_data = (guint8 *) babl_space_get_icc (babl_format_get_space (format),
&profile_length);
gimp_config_writer_printf (writer, "%u", profile_length);
if (profile_data)
gimp_config_writer_data (writer, profile_length, profile_data);
}
else
{
gimp_config_writer_printf (writer, "%s", "NULL");
}
success = TRUE;
gimp_config_writer_close (writer);
}