app, plug-ins: move brush pipe saving from the file-gih plug-in to the core

As with .gbr and .pat, only the actual saving code, not the export
logic and GUI.
This commit is contained in:
Michael Natterer 2019-03-03 19:42:22 +01:00
parent 861106a0b3
commit cc7e07fecb
3 changed files with 249 additions and 378 deletions

View file

@ -50,9 +50,9 @@
static GimpImage * file_gih_pipe_to_image (Gimp *gimp,
GimpBrushPipe *pipe);
static GimpBrushPipe * file_gih_image_to_pipe (GimpImage *image,
GimpDrawable *drawable,
const gchar *name,
gdouble spacing);
gdouble spacing,
const gchar *paramstring);
/* public functions */
@ -125,10 +125,10 @@ file_gih_save_invoker (GimpProcedure *procedure,
{
GimpValueArray *return_vals;
GimpImage *image;
GimpDrawable *drawable;
GimpBrushPipe *pipe;
const gchar *uri;
const gchar *name;
const gchar *params;
GFile *file;
gint spacing;
gboolean success;
@ -136,14 +136,14 @@ file_gih_save_invoker (GimpProcedure *procedure,
gimp_set_busy (gimp);
image = gimp_value_get_image (gimp_value_array_index (args, 1), gimp);
drawable = gimp_value_get_drawable (gimp_value_array_index (args, 2), gimp);
uri = g_value_get_string (gimp_value_array_index (args, 3));
spacing = g_value_get_int (gimp_value_array_index (args, 5));
name = g_value_get_string (gimp_value_array_index (args, 6));
params = g_value_get_string (gimp_value_array_index (args, 7));
file = g_file_new_for_uri (uri);
pipe = file_gih_image_to_pipe (image, drawable, name, spacing);
pipe = file_gih_image_to_pipe (image, name, spacing, params);
gimp_data_set_file (GIMP_DATA (pipe), file, TRUE, TRUE);
@ -236,108 +236,101 @@ file_gih_pipe_to_image (Gimp *gimp,
static GimpBrushPipe *
file_gih_image_to_pipe (GimpImage *image,
GimpDrawable *drawable,
const gchar *name,
gdouble spacing)
gdouble spacing,
const gchar *paramstring)
{
#if 0
GimpBrush *brush;
GeglBuffer *buffer;
GimpTempBuf *mask;
GimpTempBuf *pixmap = NULL;
gint width;
gint height;
GimpBrushPipe *pipe;
GimpPixPipeParams params;
GList *layers;
GList *list;
GList *brushes = NULL;
gint image_width;
gint image_height;
gint i;
buffer = gimp_drawable_get_buffer (drawable);
width = gimp_item_get_width (GIMP_ITEM (drawable));
height = gimp_item_get_height (GIMP_ITEM (drawable));
brush = g_object_new (GIMP_TYPE_BRUSH,
pipe = g_object_new (GIMP_TYPE_BRUSH_PIPE,
"name", name,
"mime-type", "image/x-gimp-gih",
"spacing", spacing,
NULL);
mask = gimp_temp_buf_new (width, height, babl_format ("Y u8"));
gimp_pixpipe_params_init (&params);
gimp_pixpipe_params_parse (paramstring, &params);
if (gimp_drawable_is_gray (drawable))
image_width = gimp_image_get_width (image);
image_height = gimp_image_get_height (image);
layers = gimp_image_get_layer_iter (image);
for (list = layers; list; list = g_list_next (list))
{
guchar *m = gimp_temp_buf_get_data (mask);
gint i;
GimpLayer *layer = list->data;
gint width;
gint height;
gint offset_x;
gint offset_y;
gint row;
if (gimp_drawable_has_alpha (drawable))
width = gimp_item_get_width (GIMP_ITEM (layer));
height = gimp_item_get_height (GIMP_ITEM (layer));
gimp_item_get_offset (GIMP_ITEM (layer), &offset_x, &offset_y);
for (row = 0; row < params.rows; row++)
{
GeglBufferIterator *iter;
GimpRGB white;
gint y, ynext;
gint thisy, thish;
gint col;
gimp_rgba_set_uchar (&white, 255, 255, 255, 255);
y = (row * image_height) / params.rows;
ynext = ((row + 1) * image_height / params.rows);
iter = gegl_buffer_iterator_new (buffer, NULL, 0,
babl_format ("Y'A u8"),
GEGL_ACCESS_READ, GEGL_ABYSS_NONE,
1);
/* Assume layer is offset to positive direction in x and y.
* That's reasonable, as otherwise all of the layer
* won't be visible.
* thisy and thisx are in the drawable's coordinate space.
*/
thisy = MAX (0, y - offset_y);
thish = (ynext - offset_y) - thisy;
thish = MIN (thish, height - thisy);
while (gegl_buffer_iterator_next (iter))
for (col = 0; col < params.cols; col++)
{
guint8 *data = (guint8 *) iter->items[0].data;
gint j;
GimpBrush *brush;
gint x, xnext;
gint thisx, thisw;
for (j = 0; j < iter->length; j++)
{
GimpRGB gray;
gint x, y;
gint dest;
x = (col * image_width / params.cols);
xnext = ((col + 1) * image_width / params.cols);
thisx = MAX (0, x - offset_x);
thisw = (xnext - offset_x) - thisx;
thisw = MIN (thisw, width - thisx);
gimp_rgba_set_uchar (&gray,
data[0], data[0], data[0],
data[1]);
brush = file_gbr_drawable_to_brush (GIMP_DRAWABLE (layer),
GEGL_RECTANGLE (thisx, thisy,
thisw, thish),
gimp_object_get_name (layer),
spacing);
gimp_rgb_composite (&gray, &white,
GIMP_RGB_COMPOSITE_BEHIND);
x = iter->items[0].roi.x + j % iter->items[0].roi.width;
y = iter->items[0].roi.y + j / iter->items[0].roi.width;
dest = y * width + x;
gimp_rgba_get_uchar (&gray, &m[dest], NULL, NULL, NULL);
data += 2;
brushes = g_list_prepend (brushes, brush);
}
}
}
else
{
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, width, height), 1.0,
babl_format ("Y' u8"), m,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
}
/* invert */
for (i = 0; i < width * height; i++)
m[i] = 255 - m[i];
}
else
{
pixmap = gimp_temp_buf_new (width, height, babl_format ("R'G'B' u8"));
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, width, height), 1.0,
babl_format ("R'G'B' u8"),
gimp_temp_buf_get_data (pixmap),
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
gegl_buffer_get (buffer, GEGL_RECTANGLE (0, 0, width, height), 1.0,
babl_format ("A u8"),
gimp_temp_buf_get_data (mask),
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
}
brush->priv->mask = mask;
brush->priv->pixmap = pixmap;
return brush;
#endif
return NULL;
brushes = g_list_reverse (brushes);
pipe->n_brushes = g_list_length (brushes);
pipe->brushes = g_new0 (GimpBrush *, pipe->n_brushes);
for (list = brushes, i = 0; list; list = g_list_next (list), i++)
pipe->brushes[i] = list->data;
g_list_free (brushes);
gimp_pixpipe_params_free (&params);
gimp_brush_pipe_set_params (pipe, paramstring);
return pipe;
}

View file

@ -222,11 +222,9 @@ file_data_init (Gimp *gimp)
"Loads GIMP animated brushes",
"This procedure loads a GIMP brush "
"pipe as an image.",
"Jens Lautenbacher, Sven Neumann, "
"Michael Natterer",
"Jens Lautenbacher, Sven Neumann, "
"Michael Natterer",
"1995-2019",
"Tor Lillqvist, Michael Natterer",
"Tor Lillqvist, Michael Natterer",
"1999-2019",
NULL);
gimp_procedure_add_argument (procedure,
@ -262,6 +260,99 @@ file_data_init (Gimp *gimp)
gimp_plug_in_manager_add_procedure (gimp->plug_in_manager, proc);
g_object_unref (procedure);
/* file-gih-save-internal */
file = g_file_new_for_path ("file-gih-save-internal");
procedure = gimp_plug_in_procedure_new (GIMP_PLUGIN, file);
g_object_unref (file);
procedure->proc_type = GIMP_INTERNAL;
procedure->marshal_func = file_gih_save_invoker;
proc = GIMP_PLUG_IN_PROCEDURE (procedure);
proc->menu_label = g_strdup (N_("GIMP brush (animated)"));
gimp_plug_in_procedure_set_icon (proc, GIMP_ICON_TYPE_ICON_NAME,
(const guint8 *) "gimp-brush",
strlen ("gimp-brush") + 1);
#if 0
/* do not register as file procedure */
gimp_plug_in_procedure_set_image_types (proc, "RGB*, GRAY*, INDEXED*");
gimp_plug_in_procedure_set_file_proc (proc, "gih", "", NULL);
gimp_plug_in_procedure_set_mime_types (proc, "image/x-gimp-gih");
gimp_plug_in_procedure_set_handles_uri (proc);
#endif
gimp_object_set_static_name (GIMP_OBJECT (procedure),
"file-gih-save-internal");
gimp_procedure_set_static_strings (procedure,
"file-gih-save-internal",
"Exports Gimp animated brush file (.gih)",
"Exports Gimp animated brush file (.gih)",
"Tor Lillqvist, Michael Natterer",
"Tor Lillqvist, Michael Natterer",
"1999-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_image_id ("image",
"Image",
"Input image",
gimp, FALSE,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_drawable_id ("drawable",
"Drawable",
"Active drawable "
"of input image",
gimp, FALSE,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_string ("uri",
"URI",
"The URI of the file "
"to export",
FALSE, 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 export",
FALSE, FALSE, TRUE,
NULL,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_int32 ("spacing",
"spacing",
"Spacing of the brush",
1, 1000, 10,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_string ("name",
"name",
"The name of the "
"brush",
FALSE, FALSE, TRUE,
"GIMP Brush",
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_string ("params",
"params",
"The pipe's parameters",
FALSE, FALSE, TRUE,
NULL,
GIMP_PARAM_READWRITE));
gimp_plug_in_manager_add_procedure (gimp->plug_in_manager, proc);
g_object_unref (procedure);
/* file-pat-load */
file = g_file_new_for_path ("file-pat-load");
procedure = gimp_plug_in_procedure_new (GIMP_PLUGIN, file);

View file

@ -41,15 +41,10 @@
#include "config.h"
#include <stdlib.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include <libgimpbase/gimpparasiteio.h>
#include "app/core/gimpbrush-header.h"
#include "app/core/gimppattern-header.h"
#include "libgimp/stdplugins-intl.h"
@ -96,18 +91,10 @@ static void run (const gchar *name,
GimpParam **return_vals);
static gboolean gih_save_dialog (gint32 image_ID);
static gboolean gih_save_one_brush (GOutputStream *output,
gint32 drawable_ID,
GeglRectangle *rect,
const gchar *name,
GError **error);
static gboolean gih_save_image (GFile *file,
gint32 image_ID,
gint32 orig_image_ID,
gint32 drawable_ID,
GError **error);
/* private variables */
const GimpPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
@ -116,9 +103,6 @@ const GimpPlugInInfo PLUG_IN_INFO =
run, /* run_proc */
};
/* private variables */
static BrushInfo info =
{
"GIMP Brush Pipe",
@ -198,12 +182,11 @@ run (const gchar *name,
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
gint32 image_ID;
gint32 drawable_ID;
gint i;
GimpExportReturn export = GIMP_EXPORT_CANCEL;
GError *error = NULL;
gint i;
INIT_I18N();
gegl_init (NULL, NULL);
run_mode = param[0].data.d_int32;
@ -216,8 +199,7 @@ run (const gchar *name,
if (strcmp (name, SAVE_PROC) == 0)
{
GFile *file;
GimpParasite *name_parasite;
GimpParasite *pipe_parasite;
GimpParasite *parasite;
gint32 orig_image_ID;
image_ID = param[1].data.d_int32;
@ -247,17 +229,17 @@ run (const gchar *name,
/* Possibly retrieve data */
gimp_get_data (SAVE_PROC, &info);
name_parasite = gimp_image_get_parasite (orig_image_ID,
parasite = gimp_image_get_parasite (orig_image_ID,
"gimp-brush-pipe-name");
if (name_parasite)
if (parasite)
{
strncpy (info.description,
gimp_parasite_data (name_parasite),
gimp_parasite_data (parasite),
MIN (sizeof (info.description),
gimp_parasite_data_size (name_parasite)));
gimp_parasite_data_size (parasite)));
info.description[sizeof (info.description) - 1] = '\0';
gimp_parasite_free (name_parasite);
gimp_parasite_free (parasite);
}
else
{
@ -292,13 +274,13 @@ run (const gchar *name,
gihparams.cellwidth = gimp_image_width (image_ID) / gihparams.cols;
gihparams.cellheight = gimp_image_height (image_ID) / gihparams.rows;
pipe_parasite = gimp_image_get_parasite (orig_image_ID,
parasite = gimp_image_get_parasite (orig_image_ID,
"gimp-brush-pipe-parameters");
if (pipe_parasite)
if (parasite)
{
gimp_pixpipe_params_parse (gimp_parasite_data (pipe_parasite),
gimp_pixpipe_params_parse (gimp_parasite_data (parasite),
&gihparams);
gimp_parasite_free (pipe_parasite);
gimp_parasite_free (parasite);
}
/* Force default rank to same as number of cells if there is
@ -347,28 +329,67 @@ run (const gchar *name,
break;
case GIMP_RUN_WITH_LAST_VALS:
pipe_parasite = gimp_image_get_parasite (orig_image_ID,
parasite = gimp_image_get_parasite (orig_image_ID,
"gimp-brush-pipe-parameters");
if (pipe_parasite)
if (parasite)
{
gimp_pixpipe_params_parse (gimp_parasite_data (pipe_parasite),
gimp_pixpipe_params_parse (gimp_parasite_data (parasite),
&gihparams);
gimp_parasite_free (pipe_parasite);
gimp_parasite_free (parasite);
}
break;
}
if (status == GIMP_PDB_SUCCESS)
{
if (gih_save_image (file, image_ID, orig_image_ID, drawable_ID,
&error))
GimpParam *save_retvals;
gint n_save_retvals;
gchar *paramstring;
paramstring = gimp_pixpipe_params_build (&gihparams);
save_retvals =
gimp_run_procedure ("file-gih-save-internal",
&n_save_retvals,
GIMP_PDB_INT32, GIMP_RUN_NONINTERACTIVE,
GIMP_PDB_IMAGE, image_ID,
GIMP_PDB_DRAWABLE, drawable_ID,
GIMP_PDB_STRING, param[3].data.d_string,
GIMP_PDB_STRING, param[4].data.d_string,
GIMP_PDB_INT32, info.spacing,
GIMP_PDB_STRING, info.description,
GIMP_PDB_STRING, paramstring,
GIMP_PDB_END);
if (save_retvals[0].data.d_status == GIMP_PDB_SUCCESS)
{
gimp_set_data (SAVE_PROC, &info, sizeof (info));
parasite = gimp_parasite_new ("gimp-brush-pipe-name",
GIMP_PARASITE_PERSISTENT,
strlen (info.description) + 1,
info.description);
gimp_image_attach_parasite (orig_image_ID, parasite);
gimp_parasite_free (parasite);
parasite = gimp_parasite_new ("gimp-brush-pipe-parameters",
GIMP_PARASITE_PERSISTENT,
strlen (paramstring) + 1,
paramstring);
gimp_image_attach_parasite (orig_image_ID, parasite);
gimp_parasite_free (parasite);
}
else
{
g_set_error (&error, 0, 0,
"Running procedure 'file-gih-save-internal' "
"failed: %s",
gimp_get_pdb_error ());
status = GIMP_PDB_EXECUTION_ERROR;
}
g_free (paramstring);
}
gimp_pixpipe_params_free (&gihparams);
@ -771,237 +792,3 @@ gih_save_dialog (gint32 image_ID)
return run;
}
static gboolean
gih_save_one_brush (GOutputStream *output,
gint32 drawable_ID,
GeglRectangle *rect,
const gchar *name,
GError **error)
{
GeglBuffer *buffer;
const Babl *format;
GimpBrushHeader bh;
guchar *data;
GimpImageType drawable_type;
gint bpp;
gint y;
buffer = gimp_drawable_get_buffer (drawable_ID);
drawable_type = gimp_drawable_type (drawable_ID);
if (! name)
name = _("Unnamed");
switch (drawable_type)
{
case GIMP_GRAY_IMAGE:
case GIMP_GRAYA_IMAGE: /* alpha channel is ignored */
format = babl_format ("Y' u8");
break;
case GIMP_RGB_IMAGE: /* alpha channel is added */
case GIMP_RGBA_IMAGE:
format = babl_format ("R'G'B'A u8");
break;
default:
g_return_val_if_reached (FALSE);
break;
}
bpp = babl_format_get_bytes_per_pixel (format);
bh.header_size = g_htonl (sizeof (bh) + strlen (name) + 1);
bh.version = g_htonl (2);
bh.width = g_htonl (rect->width);
bh.height = g_htonl (rect->height);
bh.bytes = g_htonl (bpp);
bh.magic_number = g_htonl (GIMP_BRUSH_MAGIC);
bh.spacing = g_htonl (info.spacing);
if (! g_output_stream_write_all (output, &bh, sizeof (bh),
NULL, NULL, error))
{
return FALSE;
}
if (! g_output_stream_write_all (output, name, strlen (name) + 1,
NULL, NULL, error))
{
return FALSE;
}
data = g_malloc (rect->width * bpp);
for (y = 0; y < rect->height; y++)
{
gint x;
gegl_buffer_get (buffer,
GEGL_RECTANGLE (rect->x, rect->y + y, rect->width, 1),
1.0, format, data,
GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_NONE);
switch (bpp)
{
case 1: /* GRAY */
for (x = 0; x < rect->width; x++)
data[x] = 255 - data[x];
}
if (! g_output_stream_write_all (output, data, rect->width * bpp,
NULL, NULL, error))
{
g_free (data);
return FALSE;
}
}
g_free (data);
g_object_unref (buffer);
return TRUE;
}
static gboolean
gih_save_image (GFile *file,
gint32 image_ID,
gint32 orig_image_ID,
gint32 drawable_ID,
GError **error)
{
GOutputStream *output;
GimpParasite *name_parasite;
GimpParasite *pipe_parasite;
gchar *header;
gchar *parstring;
gint32 *layer_ID;
gint nlayers, layer;
gint row, col;
gint imagew, imageh;
gint offsetx, offsety;
gint k;
if (gihparams.ncells < 1)
return FALSE;
imagew = gimp_image_width (image_ID);
imageh = gimp_image_height (image_ID);
gimp_progress_init_printf (_("Exporting '%s'"),
g_file_get_parse_name (file));
output = G_OUTPUT_STREAM (g_file_replace (file,
NULL, FALSE, G_FILE_CREATE_NONE,
NULL, error));
if (! output)
return FALSE;
parstring = gimp_pixpipe_params_build (&gihparams);
header = g_strdup_printf ("%s\n%d %s\n",
info.description, gihparams.ncells, parstring);
if (! g_output_stream_write_all (output, header, strlen (header),
NULL, NULL, error))
{
GCancellable *cancellable = g_cancellable_new ();
g_cancellable_cancel (cancellable);
g_output_stream_close (output, cancellable, NULL);
g_object_unref (cancellable);
g_free (parstring);
g_free (header);
g_object_unref (output);
return FALSE;
}
g_free (header);
name_parasite = gimp_parasite_new ("gimp-brush-pipe-name",
GIMP_PARASITE_PERSISTENT,
strlen (info.description) + 1,
info.description);
gimp_image_attach_parasite (orig_image_ID, name_parasite);
gimp_parasite_free (name_parasite);
pipe_parasite = gimp_parasite_new ("gimp-brush-pipe-parameters",
GIMP_PARASITE_PERSISTENT,
strlen (parstring) + 1, parstring);
gimp_image_attach_parasite (orig_image_ID, pipe_parasite);
gimp_parasite_free (pipe_parasite);
g_free (parstring);
layer_ID = gimp_image_get_layers (image_ID, &nlayers);
for (layer = 0, k = 0; layer < nlayers; layer++)
{
gchar *name = gimp_item_get_name (layer_ID[layer]);
gint width = gimp_drawable_width (layer_ID[layer]);
gint height = gimp_drawable_height (layer_ID[layer]);
gimp_drawable_offsets (layer_ID[layer], &offsetx, &offsety);
for (row = 0; row < gihparams.rows; row++)
{
gint y, ynext;
gint thisy, thish;
y = (row * imageh) / gihparams.rows;
ynext = ((row + 1) * imageh / gihparams.rows);
/* Assume layer is offset to positive direction in x and y.
* That's reasonable, as otherwise all of the layer
* won't be visible.
* thisy and thisx are in the drawable's coordinate space.
*/
thisy = MAX (0, y - offsety);
thish = (ynext - offsety) - thisy;
thish = MIN (thish, height - thisy);
for (col = 0; col < gihparams.cols; col++)
{
gint x, xnext;
gint thisx, thisw;
x = (col * imagew / gihparams.cols);
xnext = ((col + 1) * imagew / gihparams.cols);
thisx = MAX (0, x - offsetx);
thisw = (xnext - offsetx) - thisx;
thisw = MIN (thisw, width - thisx);
if (! gih_save_one_brush (output, layer_ID[layer],
GEGL_RECTANGLE (thisx, thisy,
thisw, thish),
name, error))
{
GCancellable *cancellable = g_cancellable_new ();
g_cancellable_cancel (cancellable);
g_output_stream_close (output, cancellable, NULL);
g_object_unref (cancellable);
g_object_unref (output);
return FALSE;
}
k++;
gimp_progress_update ((gdouble) k / gihparams.ncells);
}
}
g_free (name);
}
g_free (layer_ID);
g_object_unref (output);
gimp_progress_update (1.0);
return TRUE;
}