gimp/app/patterns.c
Sven Neumann 3cff8419db 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
2000-12-18 15:14:08 +00:00

307 lines
7 KiB
C

/* The GIMP -- an image manipulation program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "config.h"
#include <stdio.h>
#include <stdlib.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
#ifdef HAVE_DIRENT_H
#include <dirent.h>
#endif
#include <glib.h>
#include "datafiles.h"
#include "patterns.h"
#include "pattern_header.h"
#include "gimpcontext.h"
#include "gimprc.h"
#include "libgimp/gimpintl.h"
/* global variables */
GPattern *active_pattern = NULL;
GSList *pattern_list = NULL;
gint num_patterns = 0;
/* static variables */
static GPattern *standard_pattern = NULL;
/* local function prototypes */
static GPattern * pattern_load_real (gint fd,
gchar *filename,
gboolean quiet);
static void load_pattern (gchar *filename);
static void pattern_free_func (gpointer data,
gpointer dummy);
static gint pattern_compare_func (gconstpointer second,
gconstpointer first);
/* public functions */
void
patterns_init (gboolean no_data)
{
GSList *list;
if (pattern_list)
patterns_free ();
if (pattern_path != NULL && !no_data)
datafiles_read_directories (pattern_path, load_pattern, 0);
/* assign indexes to the loaded patterns */
for (list = pattern_list; list; list = g_slist_next (list))
{
/* Set the pattern index */
((GPattern *) list->data)->index = num_patterns++;
}
gimp_context_refresh_patterns ();
}
void
patterns_free (void)
{
if (pattern_list)
{
g_slist_foreach (pattern_list, pattern_free_func, NULL);
g_slist_free (pattern_list);
}
num_patterns = 0;
pattern_list = NULL;
}
GPattern *
patterns_get_standard_pattern (void)
{
if (! standard_pattern)
{
guchar *data;
gint row, col;
standard_pattern = g_new (GPattern, 1);
standard_pattern->filename = NULL;
standard_pattern->name = g_strdup ("Standard");
standard_pattern->index = -1; /* not part of the pattern list */
standard_pattern->mask = temp_buf_new (32, 32, 3, 0, 0, NULL);
data = temp_buf_data (standard_pattern->mask);
for (row = 0; row < standard_pattern->mask->height; row++)
for (col = 0; col < standard_pattern->mask->width; col++)
{
memset (data, (col % 2) && (row % 2) ? 255 : 0, 3);
data += 3;
}
}
return standard_pattern;
}
GPattern *
pattern_list_get_pattern_by_index (GSList *list,
gint index)
{
GPattern *pattern = NULL;
list = g_slist_nth (list, index);
if (list)
pattern = (GPattern *) list->data;
return pattern;
}
GPattern *
pattern_list_get_pattern (GSList *list,
gchar *name)
{
GPattern *pattern;
for (; list; list = g_slist_next (list))
{
pattern = (GPattern *) list->data;
if (!strcmp (pattern->name, name))
return pattern;
}
return NULL;
}
GPattern *
pattern_load (gint fd,
gchar *filename)
{
return pattern_load_real (fd, filename, TRUE);
}
static GPattern *
pattern_load_real (gint fd,
gchar *filename,
gboolean quiet)
{
GPattern *pattern;
PatternHeader header;
gint bn_size;
gchar *name;
g_return_val_if_fail (filename != NULL, NULL);
g_return_val_if_fail (fd != -1, NULL);
/* Read in the header size */
if (read (fd, &header, sizeof (header)) != sizeof (header))
return NULL;
/* rearrange the bytes in each unsigned int */
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);
/* Check for correct file format */
if (header.magic_number != GPATTERN_MAGIC || header.version != 1 ||
header.header_size <= sizeof (header))
{
if (!quiet)
g_message (_("Unknown pattern format version #%d in \"%s\"."),
header.version, filename);
return NULL;
}
/* Check for supported bit depths */
if (header.bytes != 1 && header.bytes != 3)
{
g_message ("Unsupported pattern depth: %d\n in file \"%s\"\nGIMP Patterns must be GRAY or RGB\n",
header.bytes, filename);
return NULL;
}
/* Read in the brush name */
if ((bn_size = (header.header_size - sizeof (header))))
{
name = g_new (gchar, bn_size);
if ((read (fd, name, bn_size)) < bn_size)
{
g_message (_("Error in GIMP pattern file \"%s\"."), filename);
g_free (name);
return NULL;
}
}
else
{
name = g_strdup (_("Unnamed"));
}
pattern = g_new0 (GPattern, 1);
pattern->mask = temp_buf_new (header.width, header.height, header.bytes,
0, 0, NULL);
if (read (fd, temp_buf_data (pattern->mask),
header.width * header.height * header.bytes) < header.width * header.height * header.bytes)
{
g_message (_("GIMP pattern file appears to be truncated: \"%s\"."),
filename);
pattern_free (pattern);
return NULL;
}
pattern->name = name;
return pattern;
}
void
pattern_free (GPattern *pattern)
{
if (pattern->mask)
temp_buf_free (pattern->mask);
if (pattern->filename)
g_free (pattern->filename);
if (pattern->name)
g_free (pattern->name);
g_free (pattern);
}
/* private functions */
static void
pattern_free_func (gpointer data,
gpointer dummy)
{
pattern_free ((GPattern *) data);
}
static gint
pattern_compare_func (gconstpointer first,
gconstpointer second)
{
return strcmp (((const GPattern *) first)->name,
((const GPattern *) second)->name);
}
static void
load_pattern (gchar *filename)
{
GPattern *pattern;
gint fd;
g_return_if_fail (filename != NULL);
fd = open (filename, O_RDONLY | _O_BINARY);
if (fd == -1)
return;
pattern = pattern_load_real (fd, filename, FALSE);
if (!pattern)
return;
pattern->filename = g_strdup (filename);
/* Swap the pattern to disk (if we're being stingy with memory) */
if (stingy_memory_use)
temp_buf_swap (pattern->mask);
pattern_list = g_slist_insert_sorted (pattern_list, pattern,
pattern_compare_func);
}