app: new storage format for the text layer parasite implies XCF version bump.

The new parasite format cannot be loaded by old versions of GIMP. This means we
must bump the XCF version (even though technically we didn't really touch the
XCF format itself because text layers are stored in a hackish way, yet text
layers are just too important nowadays to not care).

Nevertheless if an old XCF with text layers was loaded and the text layers left
untouched, the old parasite will be saved back as-is. Therefore no need to bump
the XCF version in this specific case. Only when we created new text layers or
edited existing ones.
This commit is contained in:
Jehan 2023-09-11 15:58:44 +02:00
parent bd9eb1d8ff
commit 6d5aaa995f
7 changed files with 42 additions and 13 deletions

View File

@ -82,6 +82,8 @@
#include "gimptemplate.h" #include "gimptemplate.h"
#include "gimpundostack.h" #include "gimpundostack.h"
#include "text/gimptextlayer.h"
#include "vectors/gimpvectors.h" #include "vectors/gimpvectors.h"
#include "gimp-log.h" #include "gimp-log.h"
@ -2961,6 +2963,17 @@ gimp_image_get_xcf_version (GimpImage *image,
"GIMP 3.0")); "GIMP 3.0"));
version = MAX (17, version); version = MAX (17, version);
} }
if (GIMP_IS_TEXT_LAYER (layer) &&
/* If we loaded an old XCF and didn't touch the text layers, then we
* just resave the text layer as-is. No need to bump the XCF version.
*/
! GIMP_TEXT_LAYER (layer)->text_parasite_is_old)
{
ADD_REASON (g_strdup_printf (_("Format of font information in text layer was changed in %s"),
"GIMP 3.0"));
version = MAX (19, version);
}
} }
g_list_free (items); g_list_free (items);
@ -3127,6 +3140,7 @@ gimp_image_get_xcf_version (GimpImage *image,
case 16: case 16:
case 17: case 17:
case 18: case 18:
case 19:
if (gimp_version) *gimp_version = 300; if (gimp_version) *gimp_version = 300;
if (version_string) *version_string = "GIMP 3.0"; if (version_string) *version_string = "GIMP 3.0";
break; break;

View File

@ -67,6 +67,7 @@ gimp_text_to_parasite (GimpText *text)
GimpText * GimpText *
gimp_text_from_parasite (const GimpParasite *parasite, gimp_text_from_parasite (const GimpParasite *parasite,
Gimp *gimp, Gimp *gimp,
gboolean *before_xcf_v19,
GError **error) GError **error)
{ {
GimpText *text; GimpText *text;
@ -83,17 +84,17 @@ gimp_text_from_parasite (const GimpParasite *parasite,
parasite_data = (gchar *) gimp_parasite_get_data (parasite, &parasite_data_size); parasite_data = (gchar *) gimp_parasite_get_data (parasite, &parasite_data_size);
if (parasite_data) if (parasite_data)
{ {
gboolean is_old = strstr (parasite_data, "\"GimpFont\"") == NULL;
gboolean has_markup = g_str_has_prefix (parasite_data, "(markup "); gboolean has_markup = g_str_has_prefix (parasite_data, "(markup ");
GimpParasite *new_parasite = NULL; GimpParasite *new_parasite = NULL;
GString *new_data; GString *new_data;
*before_xcf_v19 = (strstr (parasite_data, "\"GimpFont\"") == NULL);
/* This is for backward compatibility with older xcf files. /* This is for backward compatibility with older xcf files.
* font used to be serialized as a string, but now it is serialized/deserialized as * font used to be serialized as a string, but now it is serialized/deserialized as
* GimpFont, so the object Type name is inserted for the GimpFont deserialization function to be called. * GimpFont, so the object Type name is inserted for the GimpFont deserialization function to be called.
* And more importantly, fonts in the markup are extracted into their own fields for deserialization. * And more importantly, fonts in the markup are extracted into their own fields for deserialization.
*/ */
if (is_old) if (*before_xcf_v19)
{ {
new_data = g_string_new (parasite_data); new_data = g_string_new (parasite_data);
g_string_replace (new_data, "\")\n(font", "\")\n(font \"GimpFont\"", 1); g_string_replace (new_data, "\")\n(font", "\")\n(font \"GimpFont\"", 1);

View File

@ -26,6 +26,7 @@ const gchar * gimp_text_parasite_name (void) G_GNUC_CONST;
GimpParasite * gimp_text_to_parasite (GimpText *text); GimpParasite * gimp_text_to_parasite (GimpText *text);
GimpText * gimp_text_from_parasite (const GimpParasite *parasite, GimpText * gimp_text_from_parasite (const GimpParasite *parasite,
Gimp *gimp, Gimp *gimp,
gboolean *before_xcf_v19,
GError **error); GError **error);
const gchar * gimp_text_gdyntext_parasite_name (void) G_GNUC_CONST; const gchar * gimp_text_gdyntext_parasite_name (void) G_GNUC_CONST;

View File

@ -58,6 +58,7 @@ gimp_text_layer_xcf_load_hack (GimpLayer **layer)
const gchar *name; const gchar *name;
GimpText *text = NULL; GimpText *text = NULL;
const GimpParasite *parasite; const GimpParasite *parasite;
gboolean before_xcf_v19 = FALSE;
g_return_val_if_fail (layer != NULL, FALSE); g_return_val_if_fail (layer != NULL, FALSE);
g_return_val_if_fail (GIMP_IS_LAYER (*layer), FALSE); g_return_val_if_fail (GIMP_IS_LAYER (*layer), FALSE);
@ -71,6 +72,7 @@ gimp_text_layer_xcf_load_hack (GimpLayer **layer)
text = gimp_text_from_parasite (parasite, text = gimp_text_from_parasite (parasite,
gimp_item_get_image (GIMP_ITEM (*layer))->gimp, gimp_item_get_image (GIMP_ITEM (*layer))->gimp,
&before_xcf_v19,
&error); &error);
if (error) if (error)
@ -94,7 +96,10 @@ gimp_text_layer_xcf_load_hack (GimpLayer **layer)
parasite = gimp_item_parasite_find (GIMP_ITEM (*layer), name); parasite = gimp_item_parasite_find (GIMP_ITEM (*layer), name);
if (parasite) if (parasite)
text = gimp_text_from_gdyntext_parasite (parasite); {
text = gimp_text_from_gdyntext_parasite (parasite);
before_xcf_v19 = TRUE;
}
} }
if (text) if (text)
@ -102,7 +107,8 @@ gimp_text_layer_xcf_load_hack (GimpLayer **layer)
*layer = gimp_text_layer_from_layer (*layer, text); *layer = gimp_text_layer_from_layer (*layer, text);
/* let the text layer knows what parasite was used to create it */ /* let the text layer knows what parasite was used to create it */
GIMP_TEXT_LAYER (*layer)->text_parasite = name; GIMP_TEXT_LAYER (*layer)->text_parasite = name;
GIMP_TEXT_LAYER (*layer)->text_parasite_is_old = before_xcf_v19;
} }
return (text != NULL); return (text != NULL);

View File

@ -191,9 +191,10 @@ gimp_text_layer_class_init (GimpTextLayerClass *klass)
static void static void
gimp_text_layer_init (GimpTextLayer *layer) gimp_text_layer_init (GimpTextLayer *layer)
{ {
layer->text = NULL; layer->text = NULL;
layer->text_parasite = NULL; layer->text_parasite = NULL;
layer->private = gimp_text_layer_get_instance_private (layer); layer->text_parasite_is_old = FALSE;
layer->private = gimp_text_layer_get_instance_private (layer);
} }
static void static void
@ -300,7 +301,10 @@ gimp_text_layer_duplicate (GimpItem *item,
/* this is just the parasite name, not a pointer to the parasite */ /* this is just the parasite name, not a pointer to the parasite */
if (layer->text_parasite) if (layer->text_parasite)
new_layer->text_parasite = layer->text_parasite; {
new_layer->text_parasite = layer->text_parasite;
new_layer->text_parasite_is_old = layer->text_parasite_is_old;
}
new_layer->private->base_dir = layer->private->base_dir; new_layer->private->base_dir = layer->private->base_dir;
} }
@ -617,7 +621,8 @@ gimp_text_layer_text_changed (GimpTextLayer *layer)
*/ */
gimp_item_parasite_detach (GIMP_ITEM (layer), layer->text_parasite, gimp_item_parasite_detach (GIMP_ITEM (layer), layer->text_parasite,
FALSE); FALSE);
layer->text_parasite = NULL; layer->text_parasite = NULL;
layer->text_parasite_is_old = FALSE;
} }
if (layer->text->box_mode == GIMP_TEXT_BOX_DYNAMIC) if (layer->text->box_mode == GIMP_TEXT_BOX_DYNAMIC)

View File

@ -41,10 +41,11 @@ struct _GimpTextLayer
GimpLayer layer; GimpLayer layer;
GimpText *text; GimpText *text;
const gchar *text_parasite; /* parasite name that this text was set from, const gchar *text_parasite; /* parasite name that this text was set from,
* and that should be removed when the text * and that should be removed when the text
* is changed. * is changed.
*/ */
gboolean text_parasite_is_old; /* Format before XCF 19. */
gboolean auto_rename; gboolean auto_rename;
gboolean modified; gboolean modified;

View File

@ -87,6 +87,7 @@ static GimpXcfLoaderFunc * const xcf_loaders[] =
xcf_load_image, /* version 16 */ xcf_load_image, /* version 16 */
xcf_load_image, /* version 17 */ xcf_load_image, /* version 17 */
xcf_load_image, /* version 18 */ xcf_load_image, /* version 18 */
xcf_load_image, /* version 19 */
}; };