diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c index 31492e4e9c..43764c4337 100644 --- a/app/xcf/xcf-load.c +++ b/app/xcf/xcf-load.c @@ -2590,6 +2590,114 @@ xcf_load_effect_props (XcfInfo *info, } break; + case FILTER_PROP_COLOR: + { + GeglColor *color = gegl_color_new (NULL); + const Babl *format; + gchar *encoding; + guint8 *data = NULL; + gint data_length; + gint profile_data_length; + + g_value_init (&filter_prop_value, GEGL_TYPE_COLOR); + + xcf_read_string (info, &encoding, 1); + if (! babl_format_exists (encoding)) + { + gimp_message (info->gimp, G_OBJECT (info->progress), + GIMP_MESSAGE_WARNING, + "XCF Warning: format \"%s\" for " + "property '%s' of filter '%s' is " + "invalid. The color was discarded.", + encoding, filter->operation_name, + filter_prop_name); + + g_free (encoding); + valid_prop_value = FALSE; + break; + } + + format = babl_format (encoding); + g_free (encoding); + + xcf_read_int32 (info, (guint32 *) &data_length, 1); + if (data_length != babl_format_get_bytes_per_pixel (format)) + { + gimp_message (info->gimp, G_OBJECT (info->progress), + GIMP_MESSAGE_WARNING, + "XCF Warning: format \"%s\" for " + "property '%s' of filter '%s' expected " + "%d bpp, but color was serialized as %d " + "bpp. The color was discarded.", + babl_get_name (format), filter->operation_name, + filter_prop_name, + babl_format_get_bytes_per_pixel (format), + data_length); + + valid_prop_value = FALSE; + break; + } + + data = g_new (guint8, data_length); + xcf_read_int8 (info, data, data_length); + + xcf_read_int32 (info, (guint32 *) &profile_data_length, 1); + if (profile_data_length > 0) + { + const Babl *space = NULL; + GimpColorProfile *profile; + guint8 *profile_data; + GError *error = NULL; + + profile_data = g_new (guint8, profile_data_length); + xcf_read_int8 (info, profile_data, profile_data_length); + 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) + { + gimp_message (info->gimp, G_OBJECT (info->progress), + GIMP_MESSAGE_WARNING, + "XCF Warning: failed to create " + "Babl space for serialized color " + "from profile"); + + g_free (data); + valid_prop_value = FALSE; + break; + } + g_object_unref (profile); + } + else + { + gimp_message (info->gimp, G_OBJECT (info->progress), + GIMP_MESSAGE_WARNING, + "XCF Warning: Invalid profile for " + "serialized color."); + + valid_prop_value = FALSE; + break; + } + + format = babl_format_with_space (babl_format_get_encoding (format), space); + g_free (profile_data); + } + + gegl_color_set_pixel (color, format, data); + g_value_set_object (&filter_prop_value, color); + + g_free (data); + g_object_unref (color); + } + break; + default: gimp_message (info->gimp, G_OBJECT (info->progress), GIMP_MESSAGE_WARNING, diff --git a/app/xcf/xcf-private.h b/app/xcf/xcf-private.h index 1387721eef..ddeb187853 100644 --- a/app/xcf/xcf-private.h +++ b/app/xcf/xcf-private.h @@ -109,6 +109,7 @@ typedef enum FILTER_PROP_ENUM = 5, FILTER_PROP_CONFIG = 6, FILTER_PROP_UINT = 7, + FILTER_PROP_COLOR = 8, } FilterPropType; typedef struct _XcfInfo XcfInfo; diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c index ea9a44daeb..924d03d61e 100644 --- a/app/xcf/xcf-save.c +++ b/app/xcf/xcf-save.c @@ -880,6 +880,10 @@ xcf_save_effect_props (XcfInfo *info, filter_type = FILTER_PROP_INT; break; + case G_TYPE_UINT: + filter_type = FILTER_PROP_UINT; + break; + case G_TYPE_BOOLEAN: filter_type = FILTER_PROP_BOOL; break; @@ -902,9 +906,9 @@ xcf_save_effect_props (XcfInfo *info, { filter_type = FILTER_PROP_ENUM; } - else if (g_type_is_a (G_VALUE_TYPE (&value), G_TYPE_UINT)) + else if (g_type_is_a (G_VALUE_TYPE (&value), GEGL_TYPE_COLOR)) { - filter_type = FILTER_PROP_UINT; + filter_type = FILTER_PROP_COLOR; } else { @@ -1809,6 +1813,69 @@ xcf_save_prop (XcfInfo *info, } break; + case FILTER_PROP_COLOR: + { + GeglColor *color = g_value_get_object (&filter_value); + + if (color) + { + const gchar *encoding; + const Babl *format = gegl_color_get_format (color); + const Babl *space; + GBytes *bytes; + gconstpointer data; + gsize data_length; + int profile_length = 0; + + if (babl_format_is_palette (format)) + { + guint8 pixel[40]; + GeglColor *palette_color; + + /* As a special case, we don't want to serialize + * palette colors, because they are just too much + * dependent on external data and cannot be + * deserialized back safely. So we convert them first. + */ + palette_color = gegl_color_duplicate (color); + + format = babl_format_with_space ("R'G'B'A u8", format); + gegl_color_get_pixel (palette_color, format, pixel); + gegl_color_set_pixel (color, format, pixel); + + g_object_unref (palette_color); + } + + encoding = babl_format_get_encoding (format); + xcf_write_string_check_error (info, (gchar **) &encoding, 1, va_end (args)); + + bytes = gegl_color_get_bytes (color, format); + data = (guint8 *) g_bytes_get_data (bytes, &data_length); + g_bytes_unref (bytes); + + xcf_write_int32_check_error (info, (guint32 *) &data_length, 1, ;); + xcf_write_int8_check_error (info, (const guint8 *) data, data_length, ;); + + space = babl_format_get_space (format); + if (space != babl_space ("sRGB")) + { + guint8 *profile_data; + + profile_data = (guint8 *) babl_space_get_icc (babl_format_get_space (format), + &profile_length); + xcf_write_int32_check_error (info, (guint32 *) &profile_length, 1, ;); + + if (profile_data) + xcf_write_int8_check_error (info, (guint8 *) &profile_data, profile_length, ;); + } + else + { + xcf_write_int32_check_error (info, (guint32 *) &profile_length, 1, ;); + } + } + } + break; + case FILTER_PROP_CONFIG: { GimpConfig *config = g_value_get_object (&filter_value);