diff --git a/app/file-data/file-data-gih.c b/app/file-data/file-data-gih.c index b07b57d743..039491add6 100644 --- a/app/file-data/file-data-gih.c +++ b/app/file-data/file-data-gih.c @@ -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,25 +125,25 @@ 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; 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)); + image = gimp_value_get_image (gimp_value_array_index (args, 1), 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); @@ -235,109 +235,102 @@ file_gih_pipe_to_image (Gimp *gimp, } static GimpBrushPipe * -file_gih_image_to_pipe (GimpImage *image, - GimpDrawable *drawable, - const gchar *name, - gdouble spacing) +file_gih_image_to_pipe (GimpImage *image, + const gchar *name, + 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)); + pipe = g_object_new (GIMP_TYPE_BRUSH_PIPE, + "name", name, + "mime-type", "image/x-gimp-gih", + "spacing", spacing, + NULL); - brush = g_object_new (GIMP_TYPE_BRUSH, - "name", name, - "mime-type", "image/x-gimp-gih", - "spacing", spacing, - NULL); + gimp_pixpipe_params_init (¶ms); + gimp_pixpipe_params_parse (paramstring, ¶ms); - mask = gimp_temp_buf_new (width, height, babl_format ("Y u8")); + image_width = gimp_image_get_width (image); + image_height = gimp_image_get_height (image); - if (gimp_drawable_is_gray (drawable)) + 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); } + brushes = g_list_reverse (brushes); - brush->priv->mask = mask; - brush->priv->pixmap = pixmap; + pipe->n_brushes = g_list_length (brushes); + pipe->brushes = g_new0 (GimpBrush *, pipe->n_brushes); - return brush; -#endif + for (list = brushes, i = 0; list; list = g_list_next (list), i++) + pipe->brushes[i] = list->data; - return NULL; + g_list_free (brushes); + + gimp_pixpipe_params_free (¶ms); + + gimp_brush_pipe_set_params (pipe, paramstring); + + return pipe; } diff --git a/app/file-data/file-data.c b/app/file-data/file-data.c index 9468cc0855..411d2cadba 100644 --- a/app/file-data/file-data.c +++ b/app/file-data/file-data.c @@ -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); diff --git a/plug-ins/common/file-gih.c b/plug-ins/common/file-gih.c index 26c31bf8ea..29ca08c8ed 100644 --- a/plug-ins/common/file-gih.c +++ b/plug-ins/common/file-gih.c @@ -41,15 +41,10 @@ #include "config.h" -#include - #include #include #include -#include "app/core/gimpbrush-header.h" -#include "app/core/gimppattern-header.h" - #include "libgimp/stdplugins-intl.h" @@ -88,26 +83,18 @@ typedef struct /* local function prototypes */ -static void query (void); -static void run (const gchar *name, - gint nparams, - const GimpParam *param, - gint *nreturn_vals, - GimpParam **return_vals); +static void query (void); +static void run (const gchar *name, + gint nparams, + const GimpParam *param, + gint *nreturn_vals, + 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); +static gboolean gih_save_dialog (gint32 image_ID); +/* 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, - "gimp-brush-pipe-name"); - if (name_parasite) + parasite = gimp_image_get_parasite (orig_image_ID, + "gimp-brush-pipe-name"); + 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, - "gimp-brush-pipe-parameters"); - if (pipe_parasite) + parasite = gimp_image_get_parasite (orig_image_ID, + "gimp-brush-pipe-parameters"); + 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, - "gimp-brush-pipe-parameters"); - if (pipe_parasite) + parasite = gimp_image_get_parasite (orig_image_ID, + "gimp-brush-pipe-parameters"); + 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; -}