Commit 3cff8419 authored by Sven Neumann's avatar Sven Neumann Committed by Sven Neumann

Jens Lautenbacher <jtl@gimp.org>

2000-12-18  Sven Neumann  <sven@gimp.org>
	    Jens Lautenbacher <jtl@gimp.org>

	* app/Makefile.am

	* app/gimpbrushlistP.h
	* app/gimpbrushpipeP.h
	* app/gimpobjectP.h: removed these three files

	* app/parasitelistP.h
	* app/channels_dialog.c
	* app/docindex.c
	* app/gimpdrawable.c
	* app/gimpdrawableP.h
	* app/gimpimage.c
	* app/gimpimageP.h
	* app/gimplist.[ch]
	* app/gimpobject.c
	* app/gimpobject.h
	* app/gimpsetP.h: changed according to header removal

	* app/airbrush.c
	* app/brush_select.[ch]
	* app/brushes_cmds.c
	* app/gimpbrush.[ch]
	* app/gimpbrushgenerated.[ch]
	* app/gimpbrushlist.[ch]
	* app/gimpbrushpipe.[ch]
	* app/gimpcontextpreview.c
	* app/paint_core.c
	* app/paintbrush.c
	* app/pencil.c
	* tools/pdbgen/pdb/brushes.pdb: Big Brushes Cleanup.

	The GimpBrush* object hierarchy and the file formats were broken by
	"design". This made it overly difficult to read and write pixmap
	brushes and brush pipes, leading to the situation that The GIMP was
	not able to read it's very own file formats. Since the GimpBrush
	format did support arbitrary color depths, the introduction of a
	file format for pixmap brushes was unnecessary.

	The GimpBrushPixmap object is dead. GimpBrush has an additional
	pixmap temp_buf and handles pixmap brushes transparently. The file
	format of pixmap brushes is not any longer a grayscale brush plus
	a pattern, but a simple brush with RGBA data. The old brushes can
	still be loaded, but the .gpb format is deprecated.

	GimpBrushPipe derives from GimpBrush. The fileformat is still a text
	header, followed by a number of brushes, but those brushes are stored
	in the new GimpBrush format (no pattern anymore). The pipe does not
	care about the depth of the contained GimpBrushes, so we get
	grayscale BrushPipes for free. Since the brush loader still loads the
	old format, old .gih files can also still be loaded.

	Since the brushes in the GimpBrushPipe do not any longer contain a
	pointer to the pipe object, we do only temporarily switch brushes
	in the paint_core routines. This is not very elegant, but the best
	we can do without a major redesign.

	* app/patterns.[ch]: changed the loader to work with a filedescriptor
	instead of a filehandle to make it work with the new brush loading
	code.

	* plug-ins/common/.cvsignore
	* plug-ins/common/Makefile.am
	* plug-ins/common/plugin-defs.pl
	* plug-ins/common/gih.c: new plug-in that saves GIH files in the
	new format (loader will follow soon)

	* plug-ins/common/gpb.c: removed since Pixmap Brushes are no longer
	supported as a special file format.

	* plug-ins/common/gbr.c: load and save brushes in the new brush format
	which allows RGBA brushes too.

	* plug-ins/common/pat.c: load and save grayscale patterns too
parent 333bfaf5
2000-12-18 Sven Neumann <sven@gimp.org>
Jens Lautenbacher <jtl@gimp.org>
* app/Makefile.am
* app/gimpbrushlistP.h
* app/gimpbrushpipeP.h
* app/gimpobjectP.h: removed these three files
* app/parasitelistP.h
* app/channels_dialog.c
* app/docindex.c
* app/gimpdrawable.c
* app/gimpdrawableP.h
* app/gimpimage.c
* app/gimpimageP.h
* app/gimplist.[ch]
* app/gimpobject.c
* app/gimpobject.h
* app/gimpsetP.h: changed according to header removal
* app/airbrush.c
* app/brush_select.[ch]
* app/brushes_cmds.c
* app/gimpbrush.[ch]
* app/gimpbrushgenerated.[ch]
* app/gimpbrushlist.[ch]
* app/gimpbrushpipe.[ch]
* app/gimpcontextpreview.c
* app/paint_core.c
* app/paintbrush.c
* app/pencil.c
* tools/pdbgen/pdb/brushes.pdb: Big Brushes Cleanup.
The GimpBrush* object hierarchy and the file formats were broken by
"design". This made it overly difficult to read and write pixmap
brushes and brush pipes, leading to the situation that The GIMP was
not able to read it's very own file formats. Since the GimpBrush
format did support arbitrary color depths, the introduction of a
file format for pixmap brushes was unnecessary.
The GimpBrushPixmap object is dead. GimpBrush has an additional
pixmap temp_buf and handles pixmap brushes transparently. The file
format of pixmap brushes is not any longer a grayscale brush plus
a pattern, but a simple brush with RGBA data. The old brushes can
still be loaded, but the .gpb format is deprecated.
GimpBrushPipe derives from GimpBrush. The fileformat is still a text
header, followed by a number of brushes, but those brushes are stored
in the new GimpBrush format (no pattern anymore). The pipe does not
care about the depth of the contained GimpBrushes, so we get
grayscale BrushPipes for free. Since the brush loader still loads the
old format, old .gih files can also still be loaded.
Since the brushes in the GimpBrushPipe do not any longer contain a
pointer to the pipe object, we do only temporarily switch brushes
in the paint_core routines. This is not very elegant, but the best
we can do without a major redesign.
* app/patterns.[ch]: changed the loader to work with a filedescriptor
instead of a filehandle to make it work with the new brush loading
code.
* plug-ins/common/.cvsignore
* plug-ins/common/Makefile.am
* plug-ins/common/plugin-defs.pl
* plug-ins/common/gih.c: new plug-in that saves GIH files in the
new format (loader will follow soon)
* plug-ins/common/gpb.c: removed since Pixmap Brushes are no longer
supported as a special file format.
* plug-ins/common/gbr.c: load and save brushes in the new brush format
which allows RGBA brushes too.
* plug-ins/common/pat.c: load and save grayscale patterns too
2000-12-18 Michael Natterer <mitch@gimp.org>
* plug-ins/common/gee.c: Using "env" instead of "environ" caused
......
......@@ -14,7 +14,6 @@ libgimpim_a_SOURCES = \
gimpimageP.h \
gimpobject.c \
gimpobject.h \
gimpobjectP.h \
gimppreviewcache.h \
gimppreviewcache.c \
gimpset.c \
......@@ -180,10 +179,8 @@ gimp_SOURCES = \
gimpbrushgenerated.h \
gimpbrushlist.c \
gimpbrushlist.h \
gimpbrushlistP.h \
gimpbrushpipe.c \
gimpbrushpipe.h \
gimpbrushpipeP.h \
gimpcontext.c \
gimpcontext.h \
gimpcontextpreview.c \
......
......@@ -26,7 +26,6 @@
#include "airbrush.h"
#include "drawable.h"
#include "gdisplay.h"
#include "gimpbrushpipe.h"
#include "gradient.h"
#include "gimage.h"
#include "gimpui.h"
......@@ -330,7 +329,7 @@ airbrush_motion (PaintCore *paint_core,
color_pixels (temp_buf_data (area), col,
area->width * area->height, area->bytes);
}
else if (GIMP_IS_BRUSH_PIXMAP (paint_core->brush))
else if (paint_core->brush && paint_core->brush->pixmap)
{
mode = INCREMENTAL;
paint_core_color_area_with_pixmap (paint_core, gimage, drawable, area,
......
......@@ -32,7 +32,6 @@
#include "gimpbrushgenerated.h"
#include "gimpbrushlist.h"
#include "gimpbrushpipe.h"
#include "gimpbrushpipeP.h"
#include "gimpcontext.h"
#include "gimpdnd.h"
#include "gimplist.h"
......@@ -953,9 +952,9 @@ draw_brush_popup (GtkPreview *preview,
buf = g_new (guchar, 3 * width);
memset (buf, 255, 3 * width);
if (GIMP_IS_BRUSH_PIXMAP (brush))
if (gimp_brush_get_pixmap (brush))
{
guchar *pixmap = temp_buf_data (GIMP_BRUSH_PIXMAP (brush)->pixmap_mask);
guchar *pixmap = temp_buf_data (gimp_brush_get_pixmap (brush));
for (y = 0; y < offset_y; y++)
gtk_preview_draw_row (preview, buf, 0, y, width);
......@@ -1070,10 +1069,10 @@ brush_popup_timeout (gpointer data)
/* decide where to put the popup */
width = brush->mask->width;
height = brush->mask->height;
if (GIMP_IS_REALLY_A_BRUSH_PIPE (brush))
if (GIMP_IS_BRUSH_PIPE (brush))
{
GimpBrushPipe *pipe = GIMP_BRUSH_PIPE (brush);
GimpBrush *tmp_brush;
GimpBrush *tmp_brush;
gint i;
for (i = 1; i < pipe->nbrushes; i++)
......@@ -1100,7 +1099,7 @@ brush_popup_timeout (gpointer data)
draw_brush_popup (GTK_PREVIEW (bsp->brush_preview), brush, width, height);
gtk_widget_queue_draw (bsp->brush_preview);
if (GIMP_IS_REALLY_A_BRUSH_PIPE (brush) && bsp->popup_anim_timeout_tag == 0)
if (GIMP_IS_BRUSH_PIPE (brush) && bsp->popup_anim_timeout_tag == 0)
{
static popup_timeout_args_t timeout_args;
......@@ -1222,9 +1221,8 @@ display_brush (BrushSelect *bsp,
cell_width = bsp->cell_width - 2 * MARGIN_WIDTH;
cell_height = bsp->cell_height - 2 * MARGIN_HEIGHT;
mask_buf = brush->mask;
if (GIMP_IS_BRUSH_PIXMAP (brush))
pixmap_buf = GIMP_BRUSH_PIXMAP (brush)->pixmap_mask;
mask_buf = gimp_brush_get_mask (brush);
pixmap_buf = gimp_brush_get_pixmap (brush);
if (mask_buf->width > cell_width || mask_buf->height > cell_height)
{
......@@ -1234,7 +1232,7 @@ display_brush (BrushSelect *bsp,
mask_buf = brush_scale_mask (mask_buf,
(gdouble)(mask_buf->width) / MAX (ratio_x, ratio_y) + 0.5,
(gdouble)(mask_buf->height) / MAX (ratio_x, ratio_y) + 0.5);
if (GIMP_IS_BRUSH_PIXMAP (brush))
if (pixmap_buf)
{
/* TODO: the scale function should scale the pixmap
and the mask in one run */
......@@ -1257,9 +1255,11 @@ display_brush (BrushSelect *bsp,
mask = temp_buf_data (mask_buf) + (ystart - offset_y) * mask_buf->width;
buf = g_new (guchar, 3 * cell_width);
if (GIMP_IS_BRUSH_PIXMAP (brush))
if (pixmap_buf)
{
guchar *pixmap = temp_buf_data (pixmap_buf) + (ystart - offset_y) * mask_buf->width * 3;
guchar *pixmap =
temp_buf_data (pixmap_buf) + (ystart - offset_y) * mask_buf->width * 3;
for (i = ystart; i < yend; i++)
{
b = buf;
......@@ -1303,12 +1303,13 @@ display_brush (BrushSelect *bsp,
if (scale)
{
temp_buf_free (mask_buf);
if (GIMP_IS_BRUSH_PIXMAP (brush))
if (pixmap_buf)
temp_buf_free (pixmap_buf);
for (i = 0; i < indicator_height; i++, offset_y++)
{
if (offset_y > 0 && offset_y < bsp->preview->allocation.height)
(GIMP_IS_REALLY_A_BRUSH_PIPE (brush)) ?
(GIMP_IS_BRUSH_PIPE (brush)) ?
gtk_preview_draw_row (GTK_PREVIEW (bsp->preview),
scale_pipe_indicator_bits[i][0],
offset_x, offset_y, indicator_width) :
......@@ -1317,7 +1318,7 @@ display_brush (BrushSelect *bsp,
offset_x, offset_y, indicator_width);
}
}
else if (GIMP_IS_REALLY_A_BRUSH_PIPE (brush))
else if (GIMP_IS_BRUSH_PIPE (brush))
{
for (i = 0; i < indicator_height; i++, offset_y++)
{
......@@ -1617,7 +1618,7 @@ brush_select_events (GtkWidget *widget,
/* Show the brush popup window if the brush is too large */
if (brush->mask->width > bsp->cell_width - 2 * MARGIN_WIDTH ||
brush->mask->height > bsp->cell_height - 2 * MARGIN_HEIGHT ||
GIMP_IS_REALLY_A_BRUSH_PIPE (brush))
GIMP_IS_BRUSH_PIPE (brush))
{
brush_popup_open (bsp, bevent->x, bevent->y, brush);
}
......@@ -1808,19 +1809,21 @@ static void
brush_select_new_brush_callback (GtkWidget *widget,
gpointer data)
{
GimpBrushGenerated *brush;
GimpBrush *brush;
BrushSelect *bsp;
bsp = (BrushSelect *) data;
brush = gimp_brush_generated_new (10, .5, 0.0, 1.0);
gimp_brush_list_add (brush_list, GIMP_BRUSH (brush));
if (brush)
{
gimp_brush_list_add (brush_list, brush);
gimp_context_set_brush (bsp->context, GIMP_BRUSH (brush));
gimp_context_set_brush (bsp->context, brush);
if (brush_edit_generated_dialog)
brush_edit_generated_set_brush (brush_edit_generated_dialog,
GIMP_BRUSH (brush));
if (brush_edit_generated_dialog)
brush_edit_generated_set_brush (brush_edit_generated_dialog, brush);
}
brush_select_edit_brush_callback (widget, data);
}
......
......@@ -21,6 +21,7 @@
#include "gimpbrush.h"
#include "gimpcontext.h"
typedef struct _BrushSelect BrushSelect;
......
......@@ -24,7 +24,7 @@
#include "apptypes.h"
#include "gimpbrush.h"
#include "gimpbrushlistP.h"
#include "gimpbrushlist.h"
#include "gimpcontext.h"
#include "gimplist.h"
......
......@@ -31,6 +31,7 @@
#include "gimage.h"
#include "gimage_mask.h"
#include "gimpdnd.h"
#include "gimppreviewcache.h"
#include "gimprc.h"
#include "gimpui.h"
#include "layers_dialogP.h"
......
......@@ -22,15 +22,41 @@
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>
#ifdef G_OS_WIN32
#include <io.h>
#endif
#ifndef _O_BINARY
#define _O_BINARY 0
#endif
#include <gtk/gtk.h>
#include <stdio.h>
#include "apptypes.h"
#include "libgimp/gimpvector.h"
#include "brush_header.h"
#include "pattern_header.h"
#include "gimpbrush.h"
#include "gimpbrushlist.h"
#include "gimpsignal.h"
#include "gimprc.h"
#include "brush_header.h"
#include "config.h"
#include "paint_core.h"
#include "temp_buf.h"
#include "libgimp/gimpintl.h"
enum
......@@ -66,7 +92,7 @@ static void
gimp_brush_class_init (GimpBrushClass *klass)
{
GtkObjectClass *object_class;
GtkType type;
GtkType type;
object_class = GTK_OBJECT_CLASS (klass);
......@@ -93,12 +119,15 @@ gimp_brush_init (GimpBrush *brush)
{
brush->filename = NULL;
brush->name = NULL;
brush->spacing = 20;
brush->mask = NULL;
brush->x_axis.x = 15.0;
brush->x_axis.y = 0.0;
brush->y_axis.x = 0.0;
brush->y_axis.y = 15.0;
brush->mask = NULL;
brush->pixmap = NULL;
}
......@@ -127,14 +156,32 @@ gimp_brush_get_type (void)
}
GimpBrush *
gimp_brush_new (gchar *filename)
gimp_brush_load (gchar *filename)
{
GimpBrush *brush = GIMP_BRUSH (gtk_type_new (gimp_brush_get_type ()));
GimpBrush *brush;
gint fd;
if (gimp_brush_load (brush, filename))
return brush;
g_return_val_if_fail (filename != NULL, NULL);
return NULL;
fd = open (filename, O_RDONLY | _O_BINARY);
if (fd == -1)
return NULL;
brush = gimp_brush_load_brush (fd, filename);
close (fd);
brush->filename = g_strdup (filename);
/* Swap the brush to disk (if we're being stingy with memory) */
if (stingy_memory_use)
{
temp_buf_swap (brush->mask);
if (brush->pixmap)
temp_buf_swap (brush->pixmap);
}
return brush;
}
static GimpBrush *
......@@ -158,6 +205,15 @@ gimp_brush_get_mask (GimpBrush *brush)
return brush->mask;
}
TempBuf *
gimp_brush_get_pixmap (GimpBrush *brush)
{
g_return_val_if_fail (brush != NULL, NULL);
g_return_val_if_fail (GIMP_IS_BRUSH (brush), NULL);
return brush->pixmap;
}
gchar *
gimp_brush_get_name (GimpBrush *brush)
{
......@@ -203,125 +259,145 @@ gimp_brush_set_spacing (GimpBrush *brush,
brush->spacing = spacing;
}
gboolean
gimp_brush_load (GimpBrush *brush,
gchar *filename)
GimpBrush *
gimp_brush_load_brush (gint fd,
gchar *filename)
{
FILE *fp;
brush->filename = g_strdup (filename);
/* Open the requested file */
if (! (fp = fopen (filename, "rb")))
{
gtk_object_sink (GTK_OBJECT (brush));
return FALSE;
}
if (! gimp_brush_load_brush (brush, fp, filename))
{
return FALSE;
}
GimpBrush *brush;
GPattern *pattern;
gint bn_size;
BrushHeader header;
gchar *name;
gint i;
/* Clean up */
fclose (fp);
/* Swap the brush to disk (if we're being stingy with memory) */
if (stingy_memory_use)
temp_buf_swap (brush->mask);
return TRUE;
}
gboolean
gimp_brush_load_brush (GimpBrush *brush,
FILE *fp,
gchar *filename)
{
gint bn_size;
guchar buf [sizeof (BrushHeader)];
BrushHeader header;
guint *hp;
gint i;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (fd != -1, NULL);
/* Read in the header size */
if ((fread (buf, 1, sizeof (BrushHeader), fp)) < sizeof (BrushHeader))
{
fclose (fp);
gtk_object_sink (GTK_OBJECT (brush));
return FALSE;
}
if (read (fd, &header, sizeof (header)) != sizeof (header))
return NULL;
/* rearrange the bytes in each unsigned int */
hp = (guint *) &header;
for (i = 0; i < (sizeof (BrushHeader) / 4); i++)
hp [i] = ((buf [i * 4] << 24) + (buf [i * 4 + 1] << 16) +
(buf [i * 4 + 2] << 8) + (buf [i * 4 + 3]));
header.header_size = g_ntohl (header.header_size);
header.version = g_ntohl (header.version);
header.width = g_ntohl (header.width);
header.height = g_ntohl (header.height);
header.bytes = g_ntohl (header.bytes);
header.magic_number = g_ntohl (header.magic_number);
header.spacing = g_ntohl (header.spacing);
/* Check for correct file format */
if (header.magic_number != GBRUSH_MAGIC)
/* It looks as if version 1 did not have the same magic number. (neo) */
if (header.version != 1 &&
(header.magic_number != GBRUSH_MAGIC || header.version != 2))
{
if (header.version != 1)
{
fclose (fp);
gtk_object_sink (GTK_OBJECT (brush));
return FALSE;
}
g_message (_("Unknown brush format version #%d in \"%s\"."),
header.version, filename);
return NULL;
}
if (header.version == 1)
{
/* If this is a version 1 brush, set the fp back 8 bytes */
fseek (fp, -8, SEEK_CUR);
lseek (fd, -8, SEEK_CUR);
header.header_size += 8;
/* spacing is not defined in version 1 */
header.spacing = 25;
}
/* Read in the brush name */
if ((bn_size = (header.header_size - sizeof (BrushHeader))))
if ((bn_size = (header.header_size - sizeof (header))))
{
brush->name = g_new (gchar, bn_size);
if ((fread (brush->name, 1, bn_size, fp)) < bn_size)
name = g_new (gchar, bn_size);
if ((read (fd, name, bn_size)) < bn_size)
{
g_message (_("Error in GIMP brush file...aborting."));
fclose (fp);
gtk_object_sink (GTK_OBJECT (brush));
return FALSE;
g_message (_("Error in GIMP brush file \"%s\"."), filename);
g_free (name);
return NULL;
}
}
else
{
brush->name = g_strdup (_("Unnamed"));
name = g_strdup (_("Unnamed"));
}
switch (header.version)
switch (header.bytes)
{
case 1:
case 2:
/* Get a new brush mask */
brush->mask = temp_buf_new (header.width, header.height, header.bytes,
brush = GIMP_BRUSH (gtk_type_new (gimp_brush_get_type ()));
brush->mask = temp_buf_new (header.width, header.height, 1,
0, 0, NULL);
brush->spacing = header.spacing;
/* set up spacing axis */
brush->x_axis.x = header.width / 2.0;
brush->x_axis.y = 0.0;
brush->y_axis.x = 0.0;
brush->y_axis.y = header.height / 2.0;
/* Read the brush mask data */
if ((fread (temp_buf_data (brush->mask),
1, header.width * header.height, fp)) <
if (read (fd,
temp_buf_data (brush->mask), header.width * header.height) <
header.width * header.height)
g_message (_("GIMP brush file appears to be truncated."));
{
g_message (_("GIMP brush file appears to be truncated: \"%s\"."),
filename);
g_free (name);
gtk_object_unref (GTK_OBJECT (brush));
return NULL;
}
/* For backwards-compatibility, check if a pattern follows.
The obsolete .gpb format did it this way. */
pattern = pattern_load (fd, filename);
if (pattern)
{
if (pattern->mask && pattern->mask->bytes == 3)
{
brush->pixmap = pattern->mask;
pattern->mask = NULL;
}
pattern_free (pattern);
}
else
{
/* rewind to make brush pipe loader happy */
if (lseek (fd, - sizeof (PatternHeader), SEEK_CUR) < 0)
{
g_message (_("GIMP brush file appears to be corrupted: \"%s\"."),
filename);
g_free (name);
gtk_object_unref (GTK_OBJECT (brush));
return NULL;
}
}
break;
case 4:
brush = GIMP_BRUSH (gtk_type_new (gimp_brush_get_type ()));
brush->mask = temp_buf_new (header.width, header.height, 1, 0, 0, NULL);
brush->pixmap = temp_buf_new (header.width, header.height, 3, 0, 0, NULL);
for (i = 0; i < header.width * header.height; i++)
{
if (read (fd, temp_buf_data (brush->pixmap)
+ i * 3, 3) != 3 ||
read (fd, temp_buf_data (brush->mask) + i, 1) != 1)
{
g_message (_("GIMP brush file appears to be truncated: \"%s\"."),
filename);
g_free (name);
gtk_object_unref (GTK_OBJECT (brush));
return NULL;
}
}
break;
default:
g_message (_("Unknown brush format version #%d in \"%s\"\n"),
header.version, filename);
fclose (fp);
gtk_object_sink (GTK_OBJECT (brush));
return FALSE;
g_message ("Unsupported brush depth: %d\n in file \"%s\"\nGIMP Brushes must be GRAY or RGBA\n",
header.bytes, filename);
g_free (name);
return NULL;
}
return TRUE;
brush->name = name;
brush->spacing = header.spacing;
brush->x_axis.x = header.width / 2.0;