plug-ins/common/gbr.c store the brush/pattern's name in a parasite

2004-01-22  Michael Natterer  <mitch@gimp.org>

	* plug-ins/common/gbr.c
	* plug-ins/common/pat.c: store the brush/pattern's name in a
	parasite attached to the image. The parasite overrides the
	RUN_WITH_LAST_VALS logic if it exists. Consistently set the
	description as the layer's name, but ignore the layer's name
	when saving because it may have been modified by exporting.
	Fixes bug #131450.

	Misc. cleanup/fixes: Don't assume that strncpy() nul-terminates
	the buffer, use sizeof() instead of magic numbers, sanitize
	descriptions using gimp_any_to_utf8(), always use strncpy()
	instead of strcpy().

	* devel-docs/parasites.txt: document the "gimp-brush-name" and
	"gimp-pattern-name" parasites.
This commit is contained in:
Michael Natterer 2004-01-22 14:04:45 +00:00 committed by Michael Natterer
parent 16353371f0
commit 7d93951d3b
4 changed files with 211 additions and 89 deletions

View File

@ -1,3 +1,21 @@
2004-01-22 Michael Natterer <mitch@gimp.org>
* plug-ins/common/gbr.c
* plug-ins/common/pat.c: store the brush/pattern's name in a
parasite attached to the image. The parasite overrides the
RUN_WITH_LAST_VALS logic if it exists. Consistently set the
description as the layer's name, but ignore the layer's name
when saving because it may have been modified by exporting.
Fixes bug #131450.
Misc. cleanup/fixes: Don't assume that strncpy() nul-terminates
the buffer, use sizeof() instead of magic numbers, sanitize
descriptions using gimp_any_to_utf8(), always use strncpy()
instead of strcpy().
* devel-docs/parasites.txt: document the "gimp-brush-name" and
"gimp-pattern-name" parasites.
2004-01-22 Tor Lillqvist <tml@iki.fi> 2004-01-22 Tor Lillqvist <tml@iki.fi>
* gimptool-win32.c.in (get_prefix): Use GIMP_APP_VERSION. * gimptool-win32.c.in (get_prefix): Use GIMP_APP_VERSION.

View File

@ -37,6 +37,12 @@ Global data follows no strict rules.
human-readable text in UTF-8 encoding. A trailing \0 might human-readable text in UTF-8 encoding. A trailing \0 might
be included and is not part of the comment. be included and is not part of the comment.
"gimp-brush-name" (IMAGE, PERSISTENT)
A string in UTF-8 encoding specifying the name of a GIMP brush.
Currently, the gbr plug-in uses this parasite when loading and
saving .gbr files. A trailing \0 might be included and is not
part of the name.
"gimp-brush-pipe-parameters" (IMAGE, PERSISTENT) "gimp-brush-pipe-parameters" (IMAGE, PERSISTENT)
This is all very preliminary: This is all very preliminary:
@ -82,6 +88,12 @@ Global data follows no strict rules.
does not know how to handle the image grid, it keeps the grid does not know how to handle the image grid, it keeps the grid
information intact. information intact.
"gimp-pattern-name" (IMAGE, PERSISTENT)
A string in UTF-8 encoding specifying the name of a GIMP pattern.
Currently, the pat plug-in uses this parasite when loading and
saving .pat files. A trailing \0 might be included and is not
part of the name.
"gimp-text-layer" (LAYER, PERSISTENT) "gimp-text-layer" (LAYER, PERSISTENT)
The associated GimpText object serialized to a string. For The associated GimpText object serialized to a string. For
convenience the string is terminated by a trailing '\0'. convenience the string is terminated by a trailing '\0'.

View File

@ -50,24 +50,15 @@
#include "libgimp/stdplugins-intl.h" #include "libgimp/stdplugins-intl.h"
/* Declare local data types
*/
typedef struct typedef struct
{ {
gchar description[256]; gchar description[256];
gint spacing; gint spacing;
} t_info; } BrushInfo;
t_info info =
{ /* Initialize to this, change if non-interactive later */
"GIMP Brush",
10
};
/* Declare some local functions. /* local function prototypes */
*/
static void query (void); static void query (void);
static void run (const gchar *name, static void run (const gchar *name,
gint nparams, gint nparams,
@ -76,11 +67,11 @@ static void run (const gchar *name,
GimpParam **return_vals); GimpParam **return_vals);
static gint32 load_image (const gchar *filename); static gint32 load_image (const gchar *filename);
static gint save_image (const gchar *filename, static gboolean save_image (const gchar *filename,
gint32 image_ID, gint32 image_ID,
gint32 drawable_ID); gint32 drawable_ID);
static gint save_dialog (void); static gboolean save_dialog (void);
static void entry_callback (GtkWidget *widget, static void entry_callback (GtkWidget *widget,
gpointer data); gpointer data);
@ -94,6 +85,15 @@ GimpPlugInInfo PLUG_IN_INFO =
}; };
/* private variables */
BrushInfo info =
{
"GIMP Brush",
10
};
MAIN () MAIN ()
static void static void
@ -196,10 +196,14 @@ run (const gchar *name,
} }
else if (strcmp (name, "file_gbr_save") == 0) else if (strcmp (name, "file_gbr_save") == 0)
{ {
GimpParasite *parasite;
gint32 orig_image_ID;
image_ID = param[1].data.d_int32; image_ID = param[1].data.d_int32;
drawable_ID = param[2].data.d_int32; drawable_ID = param[2].data.d_int32;
/* eventually export the image */ orig_image_ID = image_ID;
switch (run_mode) switch (run_mode)
{ {
case GIMP_RUN_INTERACTIVE: case GIMP_RUN_INTERACTIVE:
@ -214,23 +218,34 @@ run (const gchar *name,
values[0].data.d_status = GIMP_PDB_CANCEL; values[0].data.d_status = GIMP_PDB_CANCEL;
return; return;
} }
/* Possibly retrieve data */
gimp_get_data ("file_gbr_save", &info);
break; break;
default: default:
break; break;
} }
parasite = gimp_image_parasite_find (orig_image_ID, "gimp-brush-name");
if (parasite)
{
gchar *name = g_strndup (gimp_parasite_data (parasite),
gimp_parasite_data_size (parasite));
gimp_parasite_free (parasite);
strncpy (info.description, name, sizeof (info.description));
info.description[sizeof (info.description) - 1] = '\0';
}
switch (run_mode) switch (run_mode)
{ {
case GIMP_RUN_INTERACTIVE: case GIMP_RUN_INTERACTIVE:
/* Possibly retrieve data */
strncpy (info.description, gimp_drawable_get_name (drawable_ID), 256);
gimp_get_data ("file_gbr_save", &info);
if (! save_dialog ()) if (! save_dialog ())
status = GIMP_PDB_CANCEL; status = GIMP_PDB_CANCEL;
break; break;
case GIMP_RUN_NONINTERACTIVE: case GIMP_RUN_NONINTERACTIVE:
/* FIXME - need a real GIMP_RUN_NONINTERACTIVE */
if (nparams != 7) if (nparams != 7)
{ {
status = GIMP_PDB_CALLING_ERROR; status = GIMP_PDB_CALLING_ERROR;
@ -238,12 +253,13 @@ run (const gchar *name,
else else
{ {
info.spacing = (param[5].data.d_int32); info.spacing = (param[5].data.d_int32);
strncpy (info.description, param[6].data.d_string, 256); strncpy (info.description, param[6].data.d_string,
sizeof (info.description));
info.description[sizeof (info.description) - 1] = '\0';
} }
break; break;
case GIMP_RUN_WITH_LAST_VALS: default:
gimp_get_data ("file_gbr_save", &info);
break; break;
} }
@ -251,7 +267,7 @@ run (const gchar *name,
{ {
if (save_image (param[3].data.d_string, image_ID, drawable_ID)) if (save_image (param[3].data.d_string, image_ID, drawable_ID))
{ {
gimp_set_data ("file_gbr_save", &info, sizeof(info)); gimp_set_data ("file_gbr_save", &info, sizeof (info));
} }
else else
{ {
@ -261,6 +277,18 @@ run (const gchar *name,
if (export == GIMP_EXPORT_EXPORT) if (export == GIMP_EXPORT_EXPORT)
gimp_image_delete (image_ID); gimp_image_delete (image_ID);
if (info.description && strlen (info.description))
{
gimp_image_attach_new_parasite (orig_image_ID, "gimp-brush-name",
GIMP_PARASITE_PERSISTENT,
strlen (info.description) + 1,
info.description);
}
else
{
gimp_image_parasite_detach (orig_image_ID, "gimp-brush-name");
}
} }
else else
{ {
@ -274,7 +302,7 @@ static gint32
load_image (const gchar *filename) load_image (const gchar *filename)
{ {
gchar *temp; gchar *temp;
gchar *name = NULL; gchar *name;
gint fd; gint fd;
BrushHeader bh; BrushHeader bh;
guchar *brush_buf = NULL; guchar *brush_buf = NULL;
@ -301,7 +329,7 @@ load_image (const gchar *filename)
gimp_progress_init (temp); gimp_progress_init (temp);
g_free (temp); g_free (temp);
if (read (fd, &bh, sizeof (bh)) != sizeof (bh)) if (read (fd, &bh, sizeof (BrushHeader)) != sizeof (BrushHeader))
{ {
close (fd); close (fd);
return -1; return -1;
@ -340,7 +368,8 @@ load_image (const gchar *filename)
/* fallthrough */ /* fallthrough */
case 2: case 2:
if (bh.magic_number == GBRUSH_MAGIC && bh.header_size > sizeof (bh)) if (bh.magic_number == GBRUSH_MAGIC &&
bh.header_size > sizeof (BrushHeader))
break; break;
default: default:
@ -349,17 +378,23 @@ load_image (const gchar *filename)
return -1; return -1;
} }
if ((bn_size = (bh.header_size - sizeof (bh))) > 0) if ((bn_size = (bh.header_size - sizeof (BrushHeader))) > 0)
{ {
name = g_new (gchar, bn_size); temp = g_new (gchar, bn_size);
if ((read (fd, name, bn_size)) < bn_size)
if ((read (fd, temp, bn_size)) < bn_size)
{ {
g_message (_("Error in GIMP brush file '%s'"), g_message (_("Error in GIMP brush file '%s'"),
gimp_filename_to_utf8 (filename)); gimp_filename_to_utf8 (filename));
close (fd); close (fd);
g_free (name); g_free (temp);
return -1; return -1;
} }
name = gimp_any_to_utf8 (temp, -1,
_("Invalid UTF-8 string in brush file '%s'."),
gimp_filename_to_utf8 (filename));
g_free (temp);
} }
else else
{ {
@ -379,7 +414,6 @@ load_image (const gchar *filename)
return -1; return -1;
} }
switch (bh.bytes) switch (bh.bytes)
{ {
case 1: case 1:
@ -389,7 +423,7 @@ load_image (const gchar *filename)
/* For backwards-compatibility, check if a pattern follows. /* For backwards-compatibility, check if a pattern follows.
The obsolete .gpb format did it this way. */ The obsolete .gpb format did it this way. */
if (read (fd, &ph, sizeof(ph)) == sizeof(ph)) if (read (fd, &ph, sizeof (PatternHeader)) == sizeof(PatternHeader))
{ {
/* rearrange the bytes in each unsigned int */ /* rearrange the bytes in each unsigned int */
ph.header_size = g_ntohl (ph.header_size); ph.header_size = g_ntohl (ph.header_size);
@ -401,11 +435,12 @@ load_image (const gchar *filename)
if (ph.magic_number == GPATTERN_MAGIC && if (ph.magic_number == GPATTERN_MAGIC &&
ph.version == 1 && ph.version == 1 &&
ph.header_size > sizeof (ph) && ph.header_size > sizeof (PatternHeader) &&
ph.bytes == 3 && ph.bytes == 3 &&
ph.width == bh.width && ph.width == bh.width &&
ph.height == bh.height && ph.height == bh.height &&
lseek (fd, ph.header_size - sizeof (ph), SEEK_CUR) > 0) lseek (fd, ph.header_size - sizeof (PatternHeader),
SEEK_CUR) > 0)
{ {
guchar *plain_brush = brush_buf; guchar *plain_brush = brush_buf;
gint i; gint i;
@ -488,8 +523,11 @@ load_image (const gchar *filename)
image_ID = gimp_image_new (bh.width, bh.height, base_type); image_ID = gimp_image_new (bh.width, bh.height, base_type);
gimp_image_set_filename (image_ID, filename); gimp_image_set_filename (image_ID, filename);
layer_ID = gimp_layer_new (image_ID, name, gimp_image_attach_new_parasite (image_ID, "gimp-brush-name",
bh.width, bh.height, GIMP_PARASITE_PERSISTENT,
strlen (name) + 1, name);
layer_ID = gimp_layer_new (image_ID, name, bh.width, bh.height,
image_type, 100, GIMP_NORMAL_MODE); image_type, 100, GIMP_NORMAL_MODE);
gimp_image_add_layer (image_ID, layer_ID, 0); gimp_image_add_layer (image_ID, layer_ID, 0);
@ -515,7 +553,7 @@ load_image (const gchar *filename)
return image_ID; return image_ID;
} }
static gint static gboolean
save_image (const gchar *filename, save_image (const gchar *filename,
gint32 image_ID, gint32 image_ID,
gint32 drawable_ID) gint32 drawable_ID)
@ -551,11 +589,9 @@ save_image (const gchar *filename,
g_free (temp); g_free (temp);
drawable = gimp_drawable_get (drawable_ID); drawable = gimp_drawable_get (drawable_ID);
gimp_pixel_rgn_init (&pixel_rgn, drawable,
0, 0, drawable->width, drawable->height,
FALSE, FALSE);
bh.header_size = g_htonl (sizeof (bh) + strlen (info.description) + 1); bh.header_size = g_htonl (sizeof (BrushHeader) +
strlen (info.description) + 1);
bh.version = g_htonl (2); bh.version = g_htonl (2);
bh.width = g_htonl (drawable->width); bh.width = g_htonl (drawable->width);
bh.height = g_htonl (drawable->height); bh.height = g_htonl (drawable->height);
@ -563,20 +599,25 @@ save_image (const gchar *filename,
bh.magic_number = g_htonl (GBRUSH_MAGIC); bh.magic_number = g_htonl (GBRUSH_MAGIC);
bh.spacing = g_htonl (info.spacing); bh.spacing = g_htonl (info.spacing);
if (write (fd, &bh, sizeof (bh)) != sizeof (bh)) if (write (fd, &bh, sizeof (BrushHeader)) != sizeof (BrushHeader))
{ {
close (fd); close (fd);
return FALSE; return FALSE;
} }
if (write (fd, info.description, strlen(info.description) + 1) != if (write (fd, info.description, strlen (info.description) + 1) !=
strlen (info.description) + 1) strlen (info.description) + 1)
{ {
close(fd); close (fd);
return FALSE; return FALSE;
} }
gimp_pixel_rgn_init (&pixel_rgn, drawable,
0, 0, drawable->width, drawable->height,
FALSE, FALSE);
buffer = g_malloc (drawable->width * drawable->bpp); buffer = g_malloc (drawable->width * drawable->bpp);
for (line = 0; line < drawable->height; line++) for (line = 0; line < drawable->height; line++)
{ {
gimp_pixel_rgn_get_row (&pixel_rgn, buffer, 0, line, drawable->width); gimp_pixel_rgn_get_row (&pixel_rgn, buffer, 0, line, drawable->width);
@ -587,13 +628,14 @@ save_image (const gchar *filename,
buffer[x] = 255 - buffer[x]; buffer[x] = 255 - buffer[x];
} }
if (write (fd, buffer, if (write (fd, buffer, drawable->width * drawable->bpp) !=
drawable->width * drawable->bpp) != drawable->width * drawable->bpp) drawable->width * drawable->bpp)
{ {
g_free (buffer); g_free (buffer);
close (fd); close (fd);
return FALSE; return FALSE;
} }
gimp_progress_update ((gdouble) line / (gdouble) drawable->height); gimp_progress_update ((gdouble) line / (gdouble) drawable->height);
} }
@ -603,7 +645,7 @@ save_image (const gchar *filename,
return TRUE; return TRUE;
} }
static gint static gboolean
save_dialog (void) save_dialog (void)
{ {
GtkWidget *dlg; GtkWidget *dlg;
@ -664,5 +706,7 @@ static void
entry_callback (GtkWidget *widget, entry_callback (GtkWidget *widget,
gpointer data) gpointer data)
{ {
strncpy (info.description, gtk_entry_get_text (GTK_ENTRY (widget)), 256); strncpy (info.description, gtk_entry_get_text (GTK_ENTRY (widget)),
sizeof (info.description));
info.description[sizeof (info.description) - 1] = '\0';
} }

View File

@ -22,6 +22,8 @@
#include <libgimp/gimp.h> #include <libgimp/gimp.h>
#include <libgimp/gimpui.h> #include <libgimp/gimpui.h>
#include "app/core/gimppattern-header.h"
#include "libgimp/stdplugins-intl.h" #include "libgimp/stdplugins-intl.h"
@ -33,8 +35,6 @@
#define _O_BINARY 0 #define _O_BINARY 0
#endif #endif
#include "app/core/gimppattern-header.h"
/* local function prototypes */ /* local function prototypes */
@ -62,6 +62,7 @@ GimpPlugInInfo PLUG_IN_INFO =
run, /* run_proc */ run, /* run_proc */
}; };
/* private variables */ /* private variables */
static gchar description[256] = "GIMP Pattern"; static gchar description[256] = "GIMP Pattern";
@ -170,10 +171,14 @@ run (const gchar *name,
} }
else if (strcmp (name, "file_pat_save") == 0) else if (strcmp (name, "file_pat_save") == 0)
{ {
GimpParasite *parasite;
gint32 orig_image_ID;
image_ID = param[1].data.d_int32; image_ID = param[1].data.d_int32;
drawable_ID = param[2].data.d_int32; drawable_ID = param[2].data.d_int32;
/* eventually export the image */ orig_image_ID = image_ID;
switch (run_mode) switch (run_mode)
{ {
case GIMP_RUN_INTERACTIVE: case GIMP_RUN_INTERACTIVE:
@ -188,16 +193,29 @@ run (const gchar *name,
values[0].data.d_status = GIMP_PDB_CANCEL; values[0].data.d_status = GIMP_PDB_CANCEL;
return; return;
} }
/* Possibly retrieve data */
gimp_get_data ("file_pat_save", description);
break; break;
default: default:
break; break;
} }
parasite = gimp_image_parasite_find (orig_image_ID, "gimp-pattern-name");
if (parasite)
{
gchar *name = g_strndup (gimp_parasite_data (parasite),
gimp_parasite_data_size (parasite));
gimp_parasite_free (parasite);
strncpy (description, name, sizeof (description));
description[sizeof (description) - 1] = '\0';
}
switch (run_mode) switch (run_mode)
{ {
case GIMP_RUN_INTERACTIVE: case GIMP_RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data ("file_pat_save", description);
if (!save_dialog ()) if (!save_dialog ())
status = GIMP_PDB_CANCEL; status = GIMP_PDB_CANCEL;
break; break;
@ -209,12 +227,13 @@ run (const gchar *name,
} }
else else
{ {
strcpy (description, param[5].data.d_string); strncpy (description, param[5].data.d_string,
sizeof (description));
description[sizeof (description) - 1] = '\0';
} }
break; break;
case GIMP_RUN_WITH_LAST_VALS: default:
gimp_get_data ("file_pat_save", description);
break; break;
} }
@ -222,7 +241,7 @@ run (const gchar *name,
{ {
if (save_image (param[3].data.d_string, image_ID, drawable_ID)) if (save_image (param[3].data.d_string, image_ID, drawable_ID))
{ {
gimp_set_data ("file_pat_save", description, 256); gimp_set_data ("file_pat_save", description, sizeof (description));
} }
else else
{ {
@ -232,6 +251,18 @@ run (const gchar *name,
if (export == GIMP_EXPORT_EXPORT) if (export == GIMP_EXPORT_EXPORT)
gimp_image_delete (image_ID); gimp_image_delete (image_ID);
if (description && strlen (description))
{
gimp_image_attach_new_parasite (orig_image_ID, "gimp-pattern-name",
GIMP_PARASITE_PERSISTENT,
strlen (description) + 1,
description);
}
else
{
gimp_image_parasite_detach (orig_image_ID, "gimp-pattern-name");
}
} }
else else
{ {
@ -247,6 +278,7 @@ load_image (const gchar *filename)
gchar *temp; gchar *temp;
gint fd; gint fd;
PatternHeader ph; PatternHeader ph;
gchar *name;
guchar *buffer; guchar *buffer;
gint32 image_ID; gint32 image_ID;
gint32 layer_ID; gint32 layer_ID;
@ -292,12 +324,21 @@ load_image (const gchar *filename)
return -1; return -1;
} }
if (lseek (fd, ph.header_size - sizeof (PatternHeader), SEEK_CUR) != ph.header_size) temp = g_new (gchar, ph.header_size - sizeof (PatternHeader));
if (read (fd, temp, ph.header_size - sizeof (PatternHeader)) !=
ph.header_size - sizeof (PatternHeader))
{ {
g_free (temp);
close (fd); close (fd);
return -1; return -1;
} }
name = gimp_any_to_utf8 (temp, -1,
_("Invalid UTF-8 string in pattern file '%s'."),
gimp_filename_to_utf8 (filename));
g_free (temp);
/* Now there's just raw data left. */ /* Now there's just raw data left. */
/* /*
@ -331,13 +372,19 @@ load_image (const gchar *filename)
image_ID = gimp_image_new (ph.width, ph.height, base_type); image_ID = gimp_image_new (ph.width, ph.height, base_type);
gimp_image_set_filename (image_ID, filename); gimp_image_set_filename (image_ID, filename);
layer_ID = gimp_layer_new (image_ID, _("Background"), ph.width, ph.height, gimp_image_attach_new_parasite (image_ID, "gimp-pattern-name",
GIMP_PARASITE_PERSISTENT,
strlen (name) + 1, name);
layer_ID = gimp_layer_new (image_ID, name, ph.width, ph.height,
image_type, 100, GIMP_NORMAL_MODE); image_type, 100, GIMP_NORMAL_MODE);
gimp_image_add_layer (image_ID, layer_ID, 0); gimp_image_add_layer (image_ID, layer_ID, 0);
g_free (name);
drawable = gimp_drawable_get (layer_ID); drawable = gimp_drawable_get (layer_ID);
gimp_pixel_rgn_init (&pixel_rgn, drawable, 0, 0, gimp_pixel_rgn_init (&pixel_rgn, drawable,
drawable->width, drawable->height, 0, 0, drawable->width, drawable->height,
TRUE, FALSE); TRUE, FALSE);
buffer = g_malloc (ph.width * ph.bytes); buffer = g_malloc (ph.width * ph.bytes);
@ -488,6 +535,7 @@ static void
entry_callback (GtkWidget *widget, entry_callback (GtkWidget *widget,
gpointer data) gpointer data)
{ {
if (data == description) strncpy (description, gtk_entry_get_text (GTK_ENTRY (widget)),
strncpy (description, gtk_entry_get_text (GTK_ENTRY (widget)), 256); sizeof (description));
description[sizeof (description) - 1] = '\0';
} }