app, plug-ins: start consolidating brush and pattern loading/saving code

We currently have brush and pattern I/O code in both the core and
plug-ins. This commit starts removing plug-in code in favor of having
one copy of the code in the core, much like XCF loading and saving is
implemented.

Add app/file-data/ module with file procedure registering code, for
now just with an implementation of file-gbr-load.

Remove the file-gbr-load code from the file-gbr plug-in.
This commit is contained in:
Michael Natterer
2019-02-11 12:45:06 +01:00
parent 619f999280
commit a4e77e57f6
11 changed files with 458 additions and 378 deletions

View File

@ -28,6 +28,7 @@ SUBDIRS = \
plug-in \ plug-in \
xcf \ xcf \
file \ file \
file-data \
pdb \ pdb \
widgets \ widgets \
propgui \ propgui \
@ -159,6 +160,7 @@ gimpconsoleldadd = \
vectors/libappvectors.a \ vectors/libappvectors.a \
core/libappcore.a \ core/libappcore.a \
file/libappfile.a \ file/libappfile.a \
file-data/libappfile-data.a \
text/libapptext.a \ text/libapptext.a \
paint/libapppaint.a \ paint/libapppaint.a \
operations/libappoperations.a \ operations/libappoperations.a \

View File

@ -41,6 +41,7 @@
#include "paint/gimp-paint.h" #include "paint/gimp-paint.h"
#include "xcf/xcf.h" #include "xcf/xcf.h"
#include "file-data/file-data.h"
#include "gimp.h" #include "gimp.h"
#include "gimp-contexts.h" #include "gimp-contexts.h"
@ -284,6 +285,7 @@ gimp_constructed (GObject *object)
gimp->pdb = gimp_pdb_new (gimp); gimp->pdb = gimp_pdb_new (gimp);
xcf_init (gimp); xcf_init (gimp);
file_data_init (gimp);
/* create user and default context */ /* create user and default context */
gimp_contexts_init (gimp); gimp_contexts_init (gimp);
@ -390,6 +392,7 @@ gimp_finalize (GObject *object)
g_clear_object (&gimp->tool_info_list); g_clear_object (&gimp->tool_info_list);
} }
file_data_exit (gimp);
xcf_exit (gimp); xcf_exit (gimp);
g_clear_object (&gimp->pdb); g_clear_object (&gimp->pdb);

7
app/file-data/.gitignore vendored Normal file
View File

@ -0,0 +1,7 @@
/Makefile
/Makefile.in
/.deps
/.libs
/*.lo
/libappfile-data.a
/libappfile-data.la

20
app/file-data/Makefile.am Normal file
View File

@ -0,0 +1,20 @@
## Process this file with automake to produce Makefile.in
AM_CPPFLAGS = \
-DG_LOG_DOMAIN=\"Gimp-File-Data\" \
-I$(top_builddir) \
-I$(top_srcdir) \
-I$(top_builddir)/app \
-I$(top_srcdir)/app \
$(CAIRO_CFLAGS) \
$(GEGL_CFLAGS) \
$(GDK_PIXBUF_CFLAGS) \
-I$(includedir)
noinst_LIBRARIES = libappfile-data.a
libappfile_data_a_SOURCES = \
file-data.c \
file-data.h \
file-data-gbr.c \
file-data-gbr.h

View File

@ -0,0 +1,240 @@
/* GIMP - The GNU 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libgimpbase/gimpbase.h"
#include "core/core-types.h"
#include "core/gimp.h"
#include "core/gimpbrush.h"
#include "core/gimpbrush-load.h"
#include "core/gimpdrawable.h"
#include "core/gimpimage.h"
#include "core/gimplayer-new.h"
#include "core/gimpparamspecs.h"
#include "core/gimptempbuf.h"
#include "pdb/gimpprocedure.h"
#include "file-data-gbr.h"
#include "gimp-intl.h"
/* local function prototypes */
static GimpImage * file_gbr_brush_to_image (Gimp *gimp,
GimpBrush *brush);
static GimpBrush * file_gbr_image_to_brush (GimpImage *image);
/* public functions */
GimpValueArray *
file_gbr_load_invoker (GimpProcedure *procedure,
Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
const GimpValueArray *args,
GError **error)
{
GimpValueArray *return_vals;
GimpImage *image = NULL;
const gchar *uri;
GFile *file;
GInputStream *input;
GError *my_error = NULL;
gimp_set_busy (gimp);
uri = g_value_get_string (gimp_value_array_index (args, 1));
file = g_file_new_for_uri (uri);
input = G_INPUT_STREAM (g_file_read (file, NULL, &my_error));
if (input)
{
GimpBrush *brush = gimp_brush_load_brush (context, file, input, error);
if (brush)
{
image = file_gbr_brush_to_image (gimp, brush);
g_object_unref (brush);
}
g_object_unref (input);
}
else
{
g_propagate_prefixed_error (error, my_error,
_("Could not open '%s' for reading: "),
gimp_file_get_utf8_name (file));
}
g_object_unref (file);
return_vals = gimp_procedure_get_return_values (procedure, image != NULL,
error ? *error : NULL);
if (image)
gimp_value_set_image (gimp_value_array_index (return_vals, 1), image);
gimp_unset_busy (gimp);
return return_vals;
}
GimpValueArray *
file_gbr_save_invoker (GimpProcedure *procedure,
Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
const GimpValueArray *args,
GError **error)
{
GimpValueArray *return_vals;
GimpImage *image;
GimpBrush *brush;
const gchar *uri;
GFile *file;
gboolean success;
gimp_set_busy (gimp);
image = gimp_value_get_image (gimp_value_array_index (args, 1), gimp);
uri = g_value_get_string (gimp_value_array_index (args, 3));
file = g_file_new_for_uri (uri);
brush = file_gbr_image_to_brush (image);
gimp_data_set_file (GIMP_DATA (brush), file, TRUE, TRUE);
success = gimp_data_save (GIMP_DATA (brush), error);
g_object_unref (brush);
g_object_unref (file);
return_vals = gimp_procedure_get_return_values (procedure, success,
error ? *error : NULL);
gimp_unset_busy (gimp);
return return_vals;
}
/* private functions */
static GimpImage *
file_gbr_brush_to_image (Gimp *gimp,
GimpBrush *brush)
{
GimpImage *image;
GimpLayer *layer;
const Babl *format;
const gchar *name;
GimpImageBaseType base_type;
gboolean alpha;
gint width;
gint height;
GimpTempBuf *mask = gimp_brush_get_mask (brush);
GimpTempBuf *pixmap = gimp_brush_get_pixmap (brush);
GeglBuffer *buffer;
GimpParasite *parasite;
if (pixmap)
{
base_type = GIMP_RGB;
alpha = TRUE;
}
else
{
base_type = GIMP_GRAY;
alpha = FALSE;
}
name = gimp_object_get_name (brush);
width = gimp_temp_buf_get_width (mask);
height = gimp_temp_buf_get_height (mask);
image = gimp_image_new (gimp, width, height, base_type,
GIMP_PRECISION_U8_PERCEPTUAL);
parasite = gimp_parasite_new ("gimp-brush-name",
GIMP_PARASITE_PERSISTENT,
strlen (name) + 1, name);
gimp_image_parasite_attach (image, parasite);
gimp_parasite_free (parasite);
format = gimp_image_get_layer_format (image, alpha);
layer = gimp_layer_new (image, width, height, format, name,
1.0, GIMP_LAYER_MODE_NORMAL);
gimp_image_add_layer (image, layer, NULL, 0, FALSE);
buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
if (pixmap)
{
guchar *pixmap_data;
guchar *mask_data;
guchar *p;
guchar *m;
gint i;
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
babl_format ("R'G'B' u8"),
gimp_temp_buf_get_data (pixmap), GEGL_AUTO_ROWSTRIDE);
pixmap_data = gegl_buffer_linear_open (buffer, NULL, NULL, NULL);
mask_data = gimp_temp_buf_get_data (mask);
for (i = 0, p = pixmap_data, m = mask_data;
i < width * height;
i++, p += 4, m += 1)
{
p[3] = *m;
}
gegl_buffer_linear_close (buffer, pixmap_data);
}
else
{
guchar *mask_data = gimp_temp_buf_get_data (mask);
gint i;
for (i = 0; i < width * height; i++)
mask_data[i] = 255 - mask_data[i];
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, width, height), 0,
babl_format ("Y' u8"),
mask_data, GEGL_AUTO_ROWSTRIDE);
}
return image;
}
static GimpBrush *
file_gbr_image_to_brush (GimpImage *image)
{
return NULL;
}

View File

@ -0,0 +1,37 @@
/* GIMP - The GNU 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FILE_DATA_GBR_H__
#define __FILE_DATA_GBR_H__
GimpValueArray * file_gbr_load_invoker (GimpProcedure *procedure,
Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
const GimpValueArray *args,
GError **error);
GimpValueArray * file_gbr_save_invoker (GimpProcedure *procedure,
Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
const GimpValueArray *args,
GError **error);
#endif /* __FILE_DATA_GBR_H__ */

118
app/file-data/file-data.c Normal file
View File

@ -0,0 +1,118 @@
/* GIMP - The GNU 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libgimpbase/gimpbase.h"
#include "core/core-types.h"
#include "core/gimp.h"
#include "core/gimpparamspecs.h"
#include "plug-in/gimppluginmanager.h"
#include "plug-in/gimppluginprocedure.h"
#include "file-data.h"
#include "file-data-gbr.h"
#include "gimp-intl.h"
void
file_data_init (Gimp *gimp)
{
GimpPlugInProcedure *proc;
GFile *file;
GimpProcedure *procedure;
g_return_if_fail (GIMP_IS_GIMP (gimp));
/* file-gbr-load */
file = g_file_new_for_path ("file-gbr-load");
procedure = gimp_plug_in_procedure_new (GIMP_PLUGIN, file);
g_object_unref (file);
procedure->proc_type = GIMP_INTERNAL;
procedure->marshal_func = file_gbr_load_invoker;
proc = GIMP_PLUG_IN_PROCEDURE (procedure);
proc->menu_label = g_strdup (N_("GIMP brush"));
gimp_plug_in_procedure_set_icon (proc, GIMP_ICON_TYPE_ICON_NAME,
(const guint8 *) "gimp-brush",
strlen ("gimp-brush") + 1);
gimp_plug_in_procedure_set_image_types (proc, NULL);
gimp_plug_in_procedure_set_file_proc (proc, "gbr, gbp", "",
"20, string, GIMP");
gimp_plug_in_procedure_set_mime_types (proc, "image/gimp-x-gbr");
gimp_plug_in_procedure_set_handles_uri (proc);
gimp_object_set_static_name (GIMP_OBJECT (procedure), "file-gbr-load");
gimp_procedure_set_static_strings (procedure,
"file-gbr-load",
"Loads GIMP brushes",
"Loads GIMP brushes (1 or 4 bpp "
"and old .gpb format)",
"Tim Newsome, Jens Lautenbacher, "
"Sven Neumann, Michael Natterer",
"Tim Newsome, Jens Lautenbacher, "
"Sven Neumann, Michael Natterer",
"1995-2019",
NULL);
gimp_procedure_add_argument (procedure,
gimp_param_spec_int32 ("dummy-param",
"Dummy Param",
"Dummy parameter",
G_MININT32, G_MAXINT32, 0,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_string ("uri",
"URI",
"The URI of the file "
"to load",
TRUE, FALSE, TRUE,
NULL,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_string ("raw-uri",
"Raw URI",
"The URI of the file "
"to load",
TRUE, FALSE, TRUE,
NULL,
GIMP_PARAM_READWRITE));
gimp_procedure_add_return_value (procedure,
gimp_param_spec_image_id ("image",
"Image",
"Output image",
gimp, FALSE,
GIMP_PARAM_READWRITE));
gimp_plug_in_manager_add_procedure (gimp->plug_in_manager, proc);
g_object_unref (procedure);
}
void
file_data_exit (Gimp *gimp)
{
g_return_if_fail (GIMP_IS_GIMP (gimp));
}

26
app/file-data/file-data.h Normal file
View File

@ -0,0 +1,26 @@
/* GIMP - The GNU 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 3 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, see <https://www.gnu.org/licenses/>.
*/
#ifndef __FILE_DATA_H__
#define __FILE_DATA_H__
void file_data_init (Gimp *gimp);
void file_data_exit (Gimp *gimp);
#endif /* __FILE_DATA_H__ */

View File

@ -2773,6 +2773,7 @@ app/gegl/Makefile
app/dialogs/Makefile app/dialogs/Makefile
app/display/Makefile app/display/Makefile
app/file/Makefile app/file/Makefile
app/file-data/Makefile
app/gui/Makefile app/gui/Makefile
app/menus/Makefile app/menus/Makefile
app/paint/Makefile app/paint/Makefile

View File

@ -43,7 +43,6 @@
#include "libgimp/stdplugins-intl.h" #include "libgimp/stdplugins-intl.h"
#define LOAD_PROC "file-gbr-load"
#define SAVE_PROC "file-gbr-save" #define SAVE_PROC "file-gbr-save"
#define PLUG_IN_BINARY "file-gbr" #define PLUG_IN_BINARY "file-gbr"
#define PLUG_IN_ROLE "gimp-file-gbr" #define PLUG_IN_ROLE "gimp-file-gbr"
@ -65,8 +64,6 @@ static void run (const gchar *name,
gint *nreturn_vals, gint *nreturn_vals,
GimpParam **return_vals); GimpParam **return_vals);
static gint32 load_image (GFile *file,
GError **error);
static gboolean save_image (GFile *file, static gboolean save_image (GFile *file,
gint32 image_ID, gint32 image_ID,
gint32 drawable_ID, gint32 drawable_ID,
@ -100,17 +97,6 @@ MAIN ()
static void static void
query (void) query (void)
{ {
static const GimpParamDef load_args[] =
{
{ GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
{ GIMP_PDB_STRING, "uri", "The URI of the file to load" },
{ GIMP_PDB_STRING, "raw-uri", "The URI of the file to load" }
};
static const GimpParamDef load_return_vals[] =
{
{ GIMP_PDB_IMAGE, "image", "Output image" }
};
static const GimpParamDef save_args[] = static const GimpParamDef save_args[] =
{ {
{ GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" }, { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
@ -122,28 +108,6 @@ query (void)
{ GIMP_PDB_STRING, "description", "Short description of the brush" } { GIMP_PDB_STRING, "description", "Short description of the brush" }
}; };
gimp_install_procedure (LOAD_PROC,
"Loads GIMP brushes",
"Loads GIMP brushes (1 or 4 bpp and old .gpb format)",
"Tim Newsome, Jens Lautenbacher, Sven Neumann",
"Tim Newsome, Jens Lautenbacher, Sven Neumann",
"1997-2005",
N_("GIMP brush"),
NULL,
GIMP_PLUGIN,
G_N_ELEMENTS (load_args),
G_N_ELEMENTS (load_return_vals),
load_args, load_return_vals);
gimp_plugin_icon_register (LOAD_PROC, GIMP_ICON_TYPE_ICON_NAME,
(const guint8 *) GIMP_ICON_BRUSH);
gimp_register_file_handler_mime (LOAD_PROC, "image/x-gimp-gbr");
gimp_register_file_handler_uri (LOAD_PROC);
gimp_register_magic_load_handler (LOAD_PROC,
"gbr, gpb",
"",
"20, string, GIMP");
gimp_install_procedure (SAVE_PROC, gimp_install_procedure (SAVE_PROC,
"Exports files in the GIMP brush file format", "Exports files in the GIMP brush file format",
"Exports files in the GIMP brush file format", "Exports files in the GIMP brush file format",
@ -189,23 +153,7 @@ run (const gchar *name,
values[0].type = GIMP_PDB_STATUS; values[0].type = GIMP_PDB_STATUS;
values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR; values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
if (strcmp (name, LOAD_PROC) == 0) if (strcmp (name, SAVE_PROC) == 0)
{
image_ID = load_image (g_file_new_for_uri (param[1].data.d_string),
&error);
if (image_ID != -1)
{
*nreturn_vals = 2;
values[1].type = GIMP_PDB_IMAGE;
values[1].data.d_image = image_ID;
}
else
{
status = GIMP_PDB_EXECUTION_ERROR;
}
}
else if (strcmp (name, SAVE_PROC) == 0)
{ {
GFile *file; GFile *file;
GimpParasite *parasite; GimpParasite *parasite;
@ -342,331 +290,6 @@ run (const gchar *name,
values[0].data.d_status = status; values[0].data.d_status = status;
} }
static gint32
load_image (GFile *file,
GError **error)
{
GInputStream *input;
gchar *name;
GimpBrushHeader bh;
guchar *brush_buf = NULL;
gint32 image_ID;
gint32 layer_ID;
GimpParasite *parasite;
GeglBuffer *buffer;
const Babl *format;
GimpImageBaseType base_type;
GimpImageType image_type;
gsize bytes_read;
gsize size;
gint i;
gimp_progress_init_printf (_("Opening '%s'"),
g_file_get_parse_name (file));
input = G_INPUT_STREAM (g_file_read (file, NULL, error));
if (! input)
return -1;
size = G_STRUCT_OFFSET (GimpBrushHeader, magic_number);
if (! g_input_stream_read_all (input, &bh, size,
&bytes_read, NULL, error) ||
bytes_read != size)
{
g_object_unref (input);
return -1;
}
/* rearrange the bytes in each unsigned int */
bh.header_size = g_ntohl (bh.header_size);
bh.version = g_ntohl (bh.version);
bh.width = g_ntohl (bh.width);
bh.height = g_ntohl (bh.height);
bh.bytes = g_ntohl (bh.bytes);
/* Sanitize values */
if ((bh.width == 0) || (bh.width > GIMP_BRUSH_MAX_SIZE) ||
(bh.height == 0) || (bh.height > GIMP_BRUSH_MAX_SIZE) ||
((bh.bytes != 1) && (bh.bytes != 2) && (bh.bytes != 4) &&
(bh.bytes != 18)) ||
(G_MAXSIZE / bh.width / bh.height / MAX (4, bh.bytes) < 1))
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Invalid header data in '%s': width=%lu, height=%lu, "
"bytes=%lu"), g_file_get_parse_name (file),
(gulong) bh.width,
(gulong) bh.height,
(gulong) bh.bytes);
return -1;
}
switch (bh.version)
{
case 1:
/* Version 1 didn't have a magic number and had no spacing */
bh.spacing = 25;
bh.header_size += 8;
if (bh.header_size < sizeof (GimpBrushHeader))
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported brush format"));
g_object_unref (input);
return -1;
}
break;
case 2:
case 3: /* cinepaint brush */
size = sizeof (bh.magic_number) + sizeof (bh.spacing);
if (! g_input_stream_read_all (input,
(guchar *) &bh +
G_STRUCT_OFFSET (GimpBrushHeader,
magic_number), size,
&bytes_read, NULL, error) ||
bytes_read != size)
{
g_object_unref (input);
return -1;
}
bh.magic_number = g_ntohl (bh.magic_number);
bh.spacing = g_ntohl (bh.spacing);
if (bh.version == 3)
{
if (bh.bytes == 18 /* FLOAT16_GRAY_GIMAGE */)
{
bh.bytes = 2;
}
else
{
g_message (_("Unsupported brush format"));
g_object_unref (input);
return -1;
}
}
if (bh.magic_number == GIMP_BRUSH_MAGIC &&
bh.header_size > sizeof (GimpBrushHeader))
break;
default:
g_message (_("Unsupported brush format"));
g_object_unref (input);
return -1;
}
if ((size = (bh.header_size - sizeof (GimpBrushHeader))) > 0)
{
gchar *temp;
if (size > GIMP_BRUSH_MAX_NAME)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Invalid header data in '%s': "
"Brush name is too long: %lu"),
gimp_file_get_utf8_name (file),
(gulong) size);
return -1;
}
temp = g_new0 (gchar, size + 1);
if (! g_input_stream_read_all (input, temp, size,
&bytes_read, NULL, error) ||
bytes_read != size)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Error in GIMP brush file '%s'"),
g_file_get_parse_name (file));
g_object_unref (input);
g_free (temp);
return -1;
}
name = gimp_any_to_utf8 (temp, size - 1,
_("Invalid UTF-8 string in brush file '%s'."),
g_file_get_parse_name (file));
g_free (temp);
}
else
{
name = g_strdup (_("Unnamed"));
}
/* Now there's just raw data left. */
size = (gsize) bh.width * bh.height * bh.bytes;
brush_buf = g_malloc (size);
if (! g_input_stream_read_all (input, brush_buf, size,
&bytes_read, NULL, error) ||
bytes_read != size)
{
g_object_unref (input);
g_free (brush_buf);
g_free (name);
return -1;
}
switch (bh.bytes)
{
case 1:
{
GimpPatternHeader ph;
/* For backwards-compatibility, check if a pattern follows.
* The obsolete .gpb format did it this way.
*/
if (g_input_stream_read_all (input, &ph, sizeof (GimpPatternHeader),
&bytes_read, NULL, NULL) &&
bytes_read == sizeof (GimpPatternHeader))
{
/* rearrange the bytes in each unsigned int */
ph.header_size = g_ntohl (ph.header_size);
ph.version = g_ntohl (ph.version);
ph.width = g_ntohl (ph.width);
ph.height = g_ntohl (ph.height);
ph.bytes = g_ntohl (ph.bytes);
ph.magic_number = g_ntohl (ph.magic_number);
if (ph.magic_number == GIMP_PATTERN_MAGIC &&
ph.version == 1 &&
ph.header_size > sizeof (GimpPatternHeader) &&
ph.bytes == 3 &&
ph.width == bh.width &&
ph.height == bh.height &&
g_input_stream_skip (input,
ph.header_size - sizeof (GimpPatternHeader),
NULL, NULL) ==
ph.header_size - sizeof (GimpPatternHeader))
{
guchar *plain_brush = brush_buf;
gint i;
bh.bytes = 4;
brush_buf = g_malloc ((gsize) bh.width * bh.height * 4);
for (i = 0; i < ph.width * ph.height; i++)
{
if (! g_input_stream_read_all (input,
brush_buf + i * 4, 3,
&bytes_read, NULL, error) ||
bytes_read != 3)
{
g_object_unref (input);
g_free (name);
g_free (plain_brush);
g_free (brush_buf);
return -1;
}
brush_buf[i * 4 + 3] = plain_brush[i];
}
g_free (plain_brush);
}
}
}
break;
case 2:
{
guint16 *buf = (guint16 *) brush_buf;
for (i = 0; i < bh.width * bh.height; i++, buf++)
{
union
{
guint16 u[2];
gfloat f;
} short_float;
#if G_BYTE_ORDER == G_LITTLE_ENDIAN
short_float.u[0] = 0;
short_float.u[1] = GUINT16_FROM_BE (*buf);
#else
short_float.u[0] = GUINT16_FROM_BE (*buf);
short_float.u[1] = 0;
#endif
brush_buf[i] = (guchar) (short_float.f * 255.0 + 0.5);
}
bh.bytes = 1;
}
break;
default:
break;
}
/*
* Create a new image of the proper size and
* associate the filename with it.
*/
switch (bh.bytes)
{
case 1:
base_type = GIMP_GRAY;
image_type = GIMP_GRAY_IMAGE;
format = babl_format ("Y' u8");
break;
case 4:
base_type = GIMP_RGB;
image_type = GIMP_RGBA_IMAGE;
format = babl_format ("R'G'B'A u8");
break;
default:
g_message ("Unsupported brush depth: %d\n"
"GIMP Brushes must be GRAY or RGBA\n",
bh.bytes);
g_free (name);
return -1;
}
image_ID = gimp_image_new (bh.width, bh.height, base_type);
gimp_image_set_filename (image_ID, g_file_get_uri (file));
parasite = gimp_parasite_new ("gimp-brush-name",
GIMP_PARASITE_PERSISTENT,
strlen (name) + 1, name);
gimp_image_attach_parasite (image_ID, parasite);
gimp_parasite_free (parasite);
layer_ID = gimp_layer_new (image_ID, name, bh.width, bh.height,
image_type,
100,
gimp_image_get_default_new_layer_mode (image_ID));
gimp_image_insert_layer (image_ID, layer_ID, -1, 0);
g_free (name);
buffer = gimp_drawable_get_buffer (layer_ID);
/* invert */
if (image_type == GIMP_GRAY_IMAGE)
for (i = 0; i < bh.width * bh.height; i++)
brush_buf[i] = 255 - brush_buf[i];
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, bh.width, bh.height), 0,
format, brush_buf, GEGL_AUTO_ROWSTRIDE);
g_free (brush_buf);
g_object_unref (buffer);
g_object_unref (input);
gimp_progress_update (1.0);
return image_ID;
}
static gboolean static gboolean
save_image (GFile *file, save_image (GFile *file,
gint32 image_ID, gint32 image_ID,

View File

@ -278,6 +278,9 @@ app/file/file-remote.c
app/file/file-save.c app/file/file-save.c
app/file/file-utils.c app/file/file-utils.c
app/file-data/file-data-gbr.c
app/file-data/file-data.c
app/gegl/gimp-babl.c app/gegl/gimp-babl.c
app/gegl/gimp-gegl-enums.c app/gegl/gimp-gegl-enums.c