libgimpconfig: Save legacy XCF grid colors...
...in GimpRGB format. Resolves #14754 GimpGrid properties are saved and loaded in XCFs as GimpParasites. When we converted from GimpRGB to GeglColor for the fgcolor and bgcolor properties, we caused those properties to be lost when saving a 2.10 and below compatible XCF in GIMP 3.0+. This patch adds new gimp_config_get_xcf_version () and gimp_config_set_xcf_version () API to libgimpconfig's interface. This allows us to pass the intended XCF version to the parasite serialization process, and save as either GeglColor or GimpRGB compatible formats based on that value.
This commit is contained in:
parent
4a63666c8e
commit
5753ac75b4
5 changed files with 178 additions and 59 deletions
|
|
@ -556,6 +556,9 @@ xcf_save_image_props (XcfInfo *info,
|
|||
{
|
||||
GimpGrid *grid = gimp_image_get_grid (image);
|
||||
|
||||
/* Set the XCF version so that the grid colors are written as GimpRGB
|
||||
* values when saving in legacy (2.10 and below) XCF formats */
|
||||
gimp_config_set_xcf_version (GIMP_CONFIG (grid), info->file_version);
|
||||
grid_parasite = gimp_grid_to_parasite (grid);
|
||||
gimp_parasite_list_add (private->parasites, grid_parasite);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -40,6 +40,16 @@
|
|||
#include "libgimp/libgimp-intl.h"
|
||||
|
||||
|
||||
typedef struct _GimpConfigInterfacePrivate GimpConfigInterfacePrivate;
|
||||
|
||||
struct _GimpConfigInterfacePrivate
|
||||
{
|
||||
guint xcf_version;
|
||||
};
|
||||
|
||||
#define GIMP_CONFIG_INTERFACE_GET_PRIVATE(obj) (gimp_config_iface_get_private ((GimpConfigInterface *) (obj)))
|
||||
|
||||
|
||||
/*
|
||||
* GimpConfigIface:
|
||||
*
|
||||
|
|
@ -49,23 +59,26 @@
|
|||
|
||||
/* local function prototypes */
|
||||
|
||||
static void gimp_config_iface_default_init (GimpConfigInterface *iface);
|
||||
static void gimp_config_iface_base_init (GimpConfigInterface *iface);
|
||||
static GimpConfigInterfacePrivate * gimp_config_iface_get_private (GimpConfigInterface *iface);
|
||||
static void gimp_config_iface_private_finalize (GimpConfigInterfacePrivate *private);
|
||||
|
||||
static gboolean gimp_config_iface_serialize (GimpConfig *config,
|
||||
GimpConfigWriter *writer,
|
||||
gpointer data);
|
||||
static gboolean gimp_config_iface_deserialize (GimpConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data);
|
||||
static GimpConfig * gimp_config_iface_duplicate (GimpConfig *config);
|
||||
static gboolean gimp_config_iface_equal (GimpConfig *a,
|
||||
GimpConfig *b);
|
||||
static void gimp_config_iface_reset (GimpConfig *config);
|
||||
static gboolean gimp_config_iface_copy (GimpConfig *src,
|
||||
GimpConfig *dest,
|
||||
GParamFlags flags);
|
||||
static void gimp_config_iface_default_init (GimpConfigInterface *iface);
|
||||
static void gimp_config_iface_base_init (GimpConfigInterface *iface);
|
||||
|
||||
static gboolean gimp_config_iface_serialize (GimpConfig *config,
|
||||
GimpConfigWriter *writer,
|
||||
gpointer data);
|
||||
static gboolean gimp_config_iface_deserialize (GimpConfig *config,
|
||||
GScanner *scanner,
|
||||
gint nest_level,
|
||||
gpointer data);
|
||||
static GimpConfig * gimp_config_iface_duplicate (GimpConfig *config);
|
||||
static gboolean gimp_config_iface_equal (GimpConfig *a,
|
||||
GimpConfig *b);
|
||||
static void gimp_config_iface_reset (GimpConfig *config);
|
||||
static gboolean gimp_config_iface_copy (GimpConfig *src,
|
||||
GimpConfig *dest,
|
||||
GParamFlags flags);
|
||||
|
||||
|
||||
/* private functions */
|
||||
|
|
@ -266,6 +279,37 @@ gimp_config_iface_copy (GimpConfig *src,
|
|||
return gimp_config_sync (G_OBJECT (src), G_OBJECT (dest), flags);
|
||||
}
|
||||
|
||||
static GimpConfigInterfacePrivate *
|
||||
gimp_config_iface_get_private (GimpConfigInterface *iface)
|
||||
{
|
||||
GimpConfigInterfacePrivate *private;
|
||||
|
||||
static GQuark private_key = 0;
|
||||
|
||||
if (! private_key)
|
||||
private_key = g_quark_from_static_string ("gimp-config-iface-private");
|
||||
|
||||
private = g_object_get_qdata ((GObject *) iface, private_key);
|
||||
|
||||
if (! private)
|
||||
{
|
||||
private = g_slice_new0 (GimpConfigInterfacePrivate);
|
||||
|
||||
private->xcf_version = G_MAXUINT32;
|
||||
|
||||
g_object_set_qdata_full ((GObject *) iface, private_key, private,
|
||||
(GDestroyNotify) gimp_config_iface_private_finalize);
|
||||
}
|
||||
|
||||
return private;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_config_iface_private_finalize (GimpConfigInterfacePrivate *private)
|
||||
{
|
||||
g_slice_free (GimpConfigInterfacePrivate, private);
|
||||
}
|
||||
|
||||
|
||||
/* public functions */
|
||||
|
||||
|
|
@ -402,7 +446,7 @@ gimp_config_serialize_to_string (GimpConfig *config,
|
|||
|
||||
g_return_val_if_fail (GIMP_IS_CONFIG (config), NULL);
|
||||
|
||||
str = g_string_new (NULL);
|
||||
str = g_string_new (NULL);
|
||||
writer = gimp_config_writer_new_from_string (str);
|
||||
|
||||
GIMP_CONFIG_GET_IFACE (config)->serialize (config, writer, data);
|
||||
|
|
@ -837,3 +881,49 @@ gimp_config_copy (GimpConfig *src,
|
|||
|
||||
return changed;
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_config_get_xcf_version:
|
||||
* @config: a #GObject that implements the #GimpConfigInterface.
|
||||
*
|
||||
* Returns the current XCF version of the @config.
|
||||
*
|
||||
* Returns: the XCF version associated with the @config.
|
||||
*
|
||||
* Since: 3.2
|
||||
**/
|
||||
guint
|
||||
gimp_config_get_xcf_version (GimpConfig *config)
|
||||
{
|
||||
GimpConfigInterfacePrivate *private;
|
||||
|
||||
g_return_val_if_fail (GIMP_IS_CONFIG (config), G_MAXUINT32);
|
||||
|
||||
private = GIMP_CONFIG_INTERFACE_GET_PRIVATE (config);
|
||||
|
||||
return private->xcf_version;
|
||||
}
|
||||
|
||||
/**
|
||||
* gimp_config_set_xcf_version:
|
||||
* @config: a #GObject that implements the #GimpConfigInterface.
|
||||
* @xcf_version: a mask of GParamFlags
|
||||
*
|
||||
* Sets the current XCF version of the @config. This information can be used
|
||||
* to adjust how properties are serialized depending on the version of the XCF
|
||||
* that it is being saved to.
|
||||
*
|
||||
* Since: 3.2
|
||||
**/
|
||||
void
|
||||
gimp_config_set_xcf_version (GimpConfig *config,
|
||||
guint xcf_version)
|
||||
{
|
||||
GimpConfigInterfacePrivate *private;
|
||||
|
||||
g_return_if_fail (GIMP_IS_CONFIG (config));
|
||||
|
||||
private = GIMP_CONFIG_INTERFACE_GET_PRIVATE (config);
|
||||
|
||||
private->xcf_version = xcf_version;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,6 +129,10 @@ gboolean gimp_config_copy (GimpConfig *src,
|
|||
GimpConfig *dest,
|
||||
GParamFlags flags);
|
||||
|
||||
guint gimp_config_get_xcf_version (GimpConfig *config);
|
||||
void gimp_config_set_xcf_version (GimpConfig *config,
|
||||
guint xcf_version);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
|
|
|
|||
|
|
@ -309,61 +309,81 @@ gimp_config_serialize_property (GimpConfig *config,
|
|||
|
||||
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;
|
||||
guint xcf_version = gimp_config_get_xcf_version (config);
|
||||
|
||||
gimp_config_writer_open (writer, "color");
|
||||
|
||||
if (babl_format_is_palette (format))
|
||||
/* If XCF version is before GIMP 3.0, then colors should be saved
|
||||
* in legacy GimpRGB format for backwards compatibility */
|
||||
if (xcf_version >= 14)
|
||||
{
|
||||
guint8 pixel[40];
|
||||
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;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
free_color = TRUE;
|
||||
color = gegl_color_duplicate (color);
|
||||
gimp_config_writer_open (writer, "color");
|
||||
|
||||
format = babl_format_with_space ("R'G'B'A u8", format);
|
||||
gegl_color_get_pixel (color, format, pixel);
|
||||
gegl_color_set_pixel (color, format, pixel);
|
||||
}
|
||||
if (babl_format_is_palette (format))
|
||||
{
|
||||
guint8 pixel[40];
|
||||
|
||||
encoding = babl_format_get_encoding (format);
|
||||
gimp_config_writer_string (writer, encoding);
|
||||
/* 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.
|
||||
*/
|
||||
free_color = TRUE;
|
||||
color = gegl_color_duplicate (color);
|
||||
|
||||
bytes = gegl_color_get_bytes (color, format);
|
||||
data = g_bytes_get_data (bytes, &data_length);
|
||||
format = babl_format_with_space ("R'G'B'A u8", format);
|
||||
gegl_color_get_pixel (color, format, pixel);
|
||||
gegl_color_set_pixel (color, format, pixel);
|
||||
}
|
||||
|
||||
gimp_config_writer_printf (writer, "%" G_GSIZE_FORMAT, data_length);
|
||||
gimp_config_writer_data (writer, data_length, data);
|
||||
encoding = babl_format_get_encoding (format);
|
||||
gimp_config_writer_string (writer, encoding);
|
||||
|
||||
space = babl_format_get_space (format);
|
||||
if (space != babl_space ("sRGB"))
|
||||
{
|
||||
guint8 *profile_data;
|
||||
bytes = gegl_color_get_bytes (color, format);
|
||||
data = g_bytes_get_data (bytes, &data_length);
|
||||
|
||||
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);
|
||||
gimp_config_writer_printf (writer, "%" G_GSIZE_FORMAT,
|
||||
data_length);
|
||||
gimp_config_writer_data (writer, data_length, data);
|
||||
|
||||
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);
|
||||
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, "%u", profile_length);
|
||||
}
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
gimp_config_writer_close (writer);
|
||||
}
|
||||
else
|
||||
{
|
||||
gimp_config_writer_printf (writer, "%u", profile_length);
|
||||
gdouble rgba[4];
|
||||
|
||||
gegl_color_get_pixel (color, babl_format ("R'G'B'A double"), rgba);
|
||||
|
||||
gimp_config_writer_printf (writer,
|
||||
"(color-rgba %f %f %f %f)",
|
||||
rgba[0], rgba[1], rgba[2],
|
||||
rgba[3]);
|
||||
}
|
||||
|
||||
g_bytes_unref (bytes);
|
||||
|
||||
gimp_config_writer_close (writer);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ EXPORTS
|
|||
gimp_config_duplicate
|
||||
gimp_config_error_quark
|
||||
gimp_config_get_type
|
||||
gimp_config_get_xcf_version
|
||||
gimp_config_is_equal_to
|
||||
gimp_config_param_spec_duplicate
|
||||
gimp_config_path_expand
|
||||
|
|
@ -54,6 +55,7 @@ EXPORTS
|
|||
gimp_config_serialize_to_stream
|
||||
gimp_config_serialize_to_string
|
||||
gimp_config_serialize_value
|
||||
gimp_config_set_xcf_version
|
||||
gimp_config_string_append_escaped
|
||||
gimp_config_sync
|
||||
gimp_config_type_register
|
||||
|
|
|
|||
Loading…
Reference in a new issue