gimp/plug-ins/common/file-gih.c

825 lines
28 KiB
C

/* Plug-in to load and export .gih (GIMP Brush Pipe) files.
*
* Copyright (C) 1999 Tor Lillqvist
* Copyright (C) 2000 Jens Lautenbacher, Sven Neumann
*
* 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/>.
*/
/* Example of how to call file-gih-export from script-fu:
(let ((ranks (cons-array 1 'byte)))
(aset ranks 0 12)
(file-gih-export 1
img
"foo.gih"
"foo.gih"
100
"test brush"
125
125
3
4
1
ranks
1
'("random")))
*/
#include "config.h"
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include <libgimpbase/gimpparasiteio.h>
#include "libgimp/stdplugins-intl.h"
#define EXPORT_PROC "file-gih-export"
#define PLUG_IN_BINARY "file-gih"
#define PLUG_IN_ROLE "gimp-file-gih"
typedef struct
{
GtkWidget *rank_entry[GIMP_PIXPIPE_MAXDIM];
GtkWidget *mode_entry[GIMP_PIXPIPE_MAXDIM];
} SizeAdjustmentData;
typedef struct _Gih Gih;
typedef struct _GihClass GihClass;
struct _Gih
{
GimpPlugIn parent_instance;
};
struct _GihClass
{
GimpPlugInClass parent_class;
};
#define GIH_TYPE (gih_get_type ())
#define GIH(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIH_TYPE, Gih))
GType gih_get_type (void) G_GNUC_CONST;
static GList * gih_query_procedures (GimpPlugIn *plug_in);
static GimpProcedure * gih_create_procedure (GimpPlugIn *plug_in,
const gchar *name);
static GimpValueArray * gih_export (GimpProcedure *procedure,
GimpRunMode run_mode,
GimpImage *image,
GFile *file,
GimpMetadata *metadata,
GimpProcedureConfig *config,
gpointer run_data);
static void gih_remove_guides (GimpProcedureConfig *config,
GimpImage *image);
static void gih_cell_width_notify (GimpProcedureConfig *config,
const GParamSpec *pspec,
GimpProcedureDialog *dialog);
static gboolean gih_save_dialog (GimpImage *image,
GimpProcedure *procedure,
GimpProcedureConfig *config);
G_DEFINE_TYPE (Gih, gih, GIMP_TYPE_PLUG_IN)
GIMP_MAIN (GIH_TYPE)
DEFINE_STD_SET_I18N
static const gchar * const selection_modes[] = { "incremental",
"angular",
"random",
"velocity",
"pressure",
"xtilt",
"ytilt" };
static void
gih_class_init (GihClass *klass)
{
GimpPlugInClass *plug_in_class = GIMP_PLUG_IN_CLASS (klass);
plug_in_class->query_procedures = gih_query_procedures;
plug_in_class->create_procedure = gih_create_procedure;
plug_in_class->set_i18n = STD_SET_I18N;
}
static void
gih_init (Gih *gih)
{
}
static GList *
gih_query_procedures (GimpPlugIn *plug_in)
{
return g_list_append (NULL, g_strdup (EXPORT_PROC));
}
static GimpProcedure *
gih_create_procedure (GimpPlugIn *plug_in,
const gchar *name)
{
GimpProcedure *procedure = NULL;
if (! strcmp (name, EXPORT_PROC))
{
procedure = gimp_export_procedure_new (plug_in, name,
GIMP_PDB_PROC_TYPE_PLUGIN,
FALSE, gih_export, NULL, NULL);
gimp_procedure_set_image_types (procedure, "RGB*, GRAY*");
gimp_procedure_set_menu_label (procedure, _("GIMP brush (animated)"));
gimp_procedure_set_icon_name (procedure, GIMP_ICON_BRUSH);
gimp_procedure_set_documentation (procedure,
_("Exports images in GIMP Brush Pipe "
"format"),
_("This plug-in exports an image in "
"the GIMP brush pipe format. For a "
"colored brush pipe, RGBA layers are "
"used, otherwise the layers should be "
"grayscale masks. The image can be "
"multi-layered, and additionally the "
"layers can be divided into a "
"rectangular array of brushes."),
EXPORT_PROC);
gimp_procedure_set_attribution (procedure,
"Tor Lillqvist",
"Tor Lillqvist",
"1999");
gimp_file_procedure_set_mime_types (GIMP_FILE_PROCEDURE (procedure),
"image/x-gimp-gih");
gimp_file_procedure_set_format_name (GIMP_FILE_PROCEDURE (procedure),
_("Brush Pipe"));
gimp_file_procedure_set_extensions (GIMP_FILE_PROCEDURE (procedure),
"gih");
gimp_file_procedure_set_handles_remote (GIMP_FILE_PROCEDURE (procedure),
TRUE);
gimp_procedure_add_int_argument (procedure, "spacing",
_("Spacing (_percent)"),
_("Spacing of the brush"),
1, 1000, 20,
GIMP_PARAM_READWRITE);
gimp_procedure_add_string_argument (procedure, "description",
_("_Description"),
_("Short description of the GIH brush pipe"),
"GIMP Brush Pipe",
GIMP_PARAM_READWRITE);
gimp_procedure_add_int_argument (procedure, "cell-width",
_("Cell _width"),
_("Width of the brush cells in pixels"),
1, 1000, 1,
GIMP_PARAM_READWRITE);
gimp_procedure_add_int_argument (procedure, "cell-height",
_("Cell _height"),
_("Height of the brush cells in pixels"),
1, 1000, 1,
GIMP_PARAM_READWRITE);
gimp_procedure_add_int_argument (procedure, "num-cells",
_("_Number of cells"),
_("Number of cells to cut up"),
1, 1000, 1,
GIMP_PARAM_READWRITE);
gimp_procedure_add_bytes_argument (procedure, "ranks",
_("_Rank"),
_("Ranks of the dimensions"),
GIMP_PARAM_READWRITE);
gimp_procedure_add_string_array_argument (procedure, "selection-modes",
_("Selection modes"),
_("Selection modes"),
GIMP_PARAM_READWRITE);
/* Auxiliary arguments. Only useful for the GUI, to pass info around. */
gimp_procedure_add_string_aux_argument (procedure, "info-text",
_("Display as"),
_("Describe how the layers will be split"),
"", GIMP_PARAM_READWRITE);
gimp_procedure_add_int_aux_argument (procedure, "dimension",
_("D_imension"),
_("How many dimensions the animated brush has"),
1, 1000, 1,
GIMP_PARAM_READWRITE);
gimp_procedure_add_int32_array_aux_argument (procedure, "guides",
"Guides",
"Guides to show how the layers will be split in cells",
GIMP_PARAM_READWRITE);
}
return procedure;
}
static GimpValueArray *
gih_export (GimpProcedure *procedure,
GimpRunMode run_mode,
GimpImage *image,
GFile *file,
GimpMetadata *metadata,
GimpProcedureConfig *config,
gpointer run_data)
{
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
GimpExportReturn export = GIMP_EXPORT_IGNORE;
GList *layers = NULL;
gint n_drawables;
GimpParasite *parasite;
GimpImage *orig_image;
GError *error = NULL;
GimpPixPipeParams gihparams = { 0, };
gchar *description = NULL;
gint spacing;
GBytes *rank_bytes;
const guint8 *rank;
gchar **selection;
orig_image = image;
if (run_mode == GIMP_RUN_INTERACTIVE)
{
GParamSpec *spec;
gint image_width;
gint image_height;
gint cell_width;
gint cell_height;
gimp_pixpipe_params_init (&gihparams);
/* Possibly retrieve data */
parasite = gimp_image_get_parasite (orig_image,
"gimp-brush-pipe-name");
if (parasite)
{
gchar *parasite_data;
guint32 parasite_size;
parasite_data = (gchar *) gimp_parasite_get_data (parasite, &parasite_size);
g_object_set (config, "description", parasite_data , NULL);
gimp_parasite_free (parasite);
}
else
{
gchar *name = g_path_get_basename (gimp_file_get_utf8_name (file));
if (g_str_has_suffix (name, ".gih"))
name[strlen (name) - 4] = '\0';
if (strlen (name))
g_object_set (config, "description", name, NULL);
g_free (name);
}
parasite = gimp_image_get_parasite (orig_image,
"gimp-brush-pipe-parameters");
if (parasite)
{
gchar *parasite_data;
guint32 parasite_size;
parasite_data = (gchar *) gimp_parasite_get_data (parasite,
&parasite_size);
parasite_data = g_strndup (parasite_data, parasite_size);
gimp_pixpipe_params_parse (parasite_data, &gihparams);
g_object_set (config,
"num-cells", gihparams.ncells,
"dimension", gihparams.dim,
"selection-modes", gihparams.selection,
NULL);
if (gihparams.dim > 0)
{
GBytes *ranks = NULL;
guint8 rank_int[gihparams.dim];
for (gint i = 0; i < gihparams.dim; i++)
rank_int[i] = (guint8) gihparams.rank[i];
ranks =
g_bytes_new (rank_int, sizeof (guint8) * gihparams.dim);
g_object_set (config, "ranks", ranks, NULL);
g_bytes_unref (ranks);
}
gimp_parasite_free (parasite);
g_free (parasite_data);
}
g_object_get (config,
"cell-width", &cell_width,
"cell-height", &cell_height,
NULL);
image_width = gimp_image_get_width (image);
image_height = gimp_image_get_height (image);
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "cell-width");
G_PARAM_SPEC_INT (spec)->default_value = image_width;
G_PARAM_SPEC_INT (spec)->maximum = image_width;
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "cell-height");
G_PARAM_SPEC_INT (spec)->default_value = image_height;
G_PARAM_SPEC_INT (spec)->maximum = image_height;
if (cell_width == 1 && cell_height == 1)
{
g_object_set (config,
"cell-width", image_width,
"cell-height", image_height,
NULL);
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "num-cells");
G_PARAM_SPEC_INT (spec)->maximum = 1;
}
gimp_ui_init (PLUG_IN_BINARY);
if (! gih_save_dialog (image, procedure, config))
{
status = GIMP_PDB_CANCEL;
goto out;
}
}
export = gimp_export_image (&image,
GIMP_EXPORT_CAN_HANDLE_RGB |
GIMP_EXPORT_CAN_HANDLE_GRAY |
GIMP_EXPORT_CAN_HANDLE_ALPHA |
GIMP_EXPORT_CAN_HANDLE_LAYERS);
layers = gimp_image_list_layers (image);
n_drawables = g_list_length (layers);
g_object_get (config,
"spacing", &spacing,
"description", &description,
"cell-width", &gihparams.cellwidth,
"cell-height", &gihparams.cellheight,
"num-cells", &gihparams.ncells,
"ranks", &rank_bytes,
"selection-modes", &selection,
NULL);
gihparams.cols = gimp_image_get_width (image) / gihparams.cellwidth;
gihparams.rows = gimp_image_get_height (image) / gihparams.cellheight;
rank = g_bytes_get_data (rank_bytes, NULL);
gihparams.dim = g_bytes_get_size (rank_bytes);
for (gint i = 0; i < gihparams.dim; i++)
{
gihparams.rank[i] = rank[i];
gihparams.selection[i] = g_strdup (selection[i]);
}
g_strfreev (selection);
g_bytes_unref (rank_bytes);
if (status == GIMP_PDB_SUCCESS)
{
GimpProcedure *procedure;
GimpValueArray *save_retvals;
GimpDrawable **drawables = NULL;
GimpObjectArray *drawables_array;
GList *iter;
gint i;
gchar *paramstring;
paramstring = gimp_pixpipe_params_build (&gihparams);
drawables = g_new (GimpDrawable *, n_drawables);
for (iter = layers, i = 0; iter; iter = iter->next, i++)
drawables[i] = iter->data;
drawables_array = gimp_object_array_new (GIMP_TYPE_DRAWABLE, (GObject **) drawables,
n_drawables, FALSE);
procedure = gimp_pdb_lookup_procedure (gimp_get_pdb (),
"file-gih-export-internal");
save_retvals = gimp_procedure_run (procedure,
"image", image,
"num-drawables", n_drawables,
"drawables", drawables_array,
"file", file,
"spacing", spacing,
"name", description,
"params", paramstring,
NULL);
g_free (drawables);
gimp_object_array_free (drawables_array);
if (GIMP_VALUES_GET_ENUM (save_retvals, 0) == GIMP_PDB_SUCCESS)
{
parasite = gimp_parasite_new ("gimp-brush-pipe-name",
GIMP_PARASITE_PERSISTENT,
strlen (description) + 1,
description);
gimp_image_attach_parasite (orig_image, parasite);
gimp_parasite_free (parasite);
gimp_image_detach_parasite (image, "gimp-brush-pipe-parameters");
}
else
{
g_set_error (&error, 0, 0,
"Running procedure 'file-gih-export-internal' "
"failed: %s",
gimp_pdb_get_last_error (gimp_get_pdb ()));
status = GIMP_PDB_EXECUTION_ERROR;
}
g_free (paramstring);
}
gimp_pixpipe_params_free (&gihparams);
g_free (description);
out:
if (export == GIMP_EXPORT_EXPORT)
gimp_image_delete (image);
g_list_free (layers);
return gimp_procedure_new_return_values (procedure, status, error);
}
/* export routines */
static void
gih_remove_guides (GimpProcedureConfig *config,
GimpImage *image)
{
GimpArray *array;
g_object_get (config, "guides", &array, NULL);
if (array != NULL)
{
gint32 *guides = (gint32 *) array->data;
gint n_guides = array->length / 4;
for (gint i = 0; i < n_guides; i++)
gimp_image_delete_guide (image, guides[i]);
}
g_clear_pointer (&array, gimp_array_free);
g_object_set (config, "guides", NULL, NULL);
}
static void
gih_cell_width_notify (GimpProcedureConfig *config,
const GParamSpec *pspec,
GimpProcedureDialog *dialog)
{
GimpImage *image;
GParamSpec *spec;
gchar *info_text;
gchar *grid_text = NULL;
const gchar *width_warning = _("Width Mismatch!");
gchar *height_warning = _("Height Mismatch!");
GtkWidget *widget;
GtkAdjustment *rank0;
gint dimension;
gint cell_width;
gint image_width;
gint n_horiz_cells;
gint n_vert_cells;
gint cell_height;
gint image_height;
gint n_vert_guides;
gint n_horiz_guides;
gint old_max_cells;
gint max_cells;
gint num_cells;
image = g_object_get_data (G_OBJECT (dialog), "image");
rank0 = g_object_get_data (G_OBJECT (dialog), "rank0");
g_object_get (config,
"cell-width", &cell_width,
"cell-height", &cell_height,
"num-cells", &num_cells,
"dimension", &dimension,
NULL);
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "cell-width");
image_width = G_PARAM_SPEC_INT (spec)->maximum;
n_horiz_cells = image_width / cell_width;
n_vert_guides = n_horiz_cells - 1;
if (cell_width * n_horiz_cells == image_width)
width_warning = NULL;
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "cell-height");
image_height = G_PARAM_SPEC_INT (spec)->maximum;
n_vert_cells = image_height / cell_height;
n_horiz_guides = n_vert_cells - 1;
if (cell_height * n_vert_cells == image_height)
height_warning = NULL;
/* TRANSLATORS: \xc3\x97 is the UTF-8 encoding for the multiplication sign. */
if (n_horiz_guides + n_vert_guides > 0)
grid_text = g_strdup_printf (_("Displays as a %d \xc3\x97 %d grid on each layer"),
n_horiz_cells, n_vert_cells);
info_text = g_strdup_printf ("%s%s%s%s%s",
grid_text != NULL ? grid_text : "",
grid_text != NULL && width_warning != NULL ? " / " : "",
width_warning != NULL ? width_warning : "",
(grid_text != NULL || width_warning != NULL) && height_warning != NULL ? " / " : "",
height_warning != NULL ? height_warning : "");
spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), "num-cells");
old_max_cells = G_PARAM_SPEC_INT (spec)->maximum;
max_cells = n_horiz_cells * n_vert_cells;
if (num_cells == old_max_cells)
num_cells = max_cells;
else
num_cells = MIN (max_cells, num_cells);
G_PARAM_SPEC_INT (spec)->maximum = max_cells;
widget = gimp_procedure_dialog_get_widget (dialog, "num-cells", G_TYPE_NONE);
g_object_set (widget, "upper", (gdouble) max_cells, NULL);
gimp_label_spin_set_increments (GIMP_LABEL_SPIN (widget), 1.0, 1.0);
gih_remove_guides (config, image);
widget = gimp_procedure_dialog_get_widget (dialog, "info-text", G_TYPE_NONE);
gtk_widget_set_visible (widget, (strlen (info_text) > 0));
if (n_horiz_guides + n_vert_guides > 0)
{
gint32 *guides = NULL;
GValue value = G_VALUE_INIT;
guides = g_new0 (gint32, n_horiz_guides + n_vert_guides);
for (gint i = 0; i < n_vert_guides; i++)
guides[i] = gimp_image_add_vguide (image, cell_width * (i + 1));
for (gint i = 0; i < n_horiz_guides; i++)
guides[n_vert_guides + i] = gimp_image_add_hguide (image, cell_height * (i + 1));
g_value_init (&value, GIMP_TYPE_INT32_ARRAY);
gimp_value_set_int32_array (&value, guides, n_horiz_guides + n_vert_guides);
g_object_set_property (G_OBJECT (config), "guides", &value);
g_free (guides);
}
g_object_set (config,
"info-text", info_text,
"num-cells", num_cells,
NULL);
if (rank0 != NULL && dimension == 1)
gtk_adjustment_set_value (rank0, num_cells);
g_free (info_text);
g_free (grid_text);
}
static void
gih_selection_mode_changed (GtkWidget *widget,
gpointer data)
{
gint index;
index = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
g_free (*((gchar **) data));
*((gchar **) data) = g_strdup (selection_modes [index]);
}
static void
gih_dimension_notify (GimpProcedureConfig *config,
const GParamSpec *pspec,
SizeAdjustmentData *data)
{
gint dimension;
gint i;
g_object_get (config, "dimension", &dimension, NULL);
for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
{
gtk_widget_set_sensitive (data->rank_entry[i], i < dimension);
gtk_widget_set_sensitive (data->mode_entry[i], i < dimension);
}
}
static gboolean
gih_save_dialog (GimpImage *image,
GimpProcedure *procedure,
GimpProcedureConfig *config)
{
GtkWidget *dialog;
GtkWidget *dimgrid;
GtkWidget *label;
GtkAdjustment *adjustment;
GtkWidget *spinbutton;
GtkWidget *cb;
gint i;
SizeAdjustmentData cellw_adjust;
SizeAdjustmentData cellh_adjust;
gchar **selection;
GBytes *rank_bytes = NULL;
guint8 rank[GIMP_PIXPIPE_MAXDIM];
gint num_cells;
gint dimension;
gboolean run;
dialog = gimp_export_procedure_dialog_new (GIMP_EXPORT_PROCEDURE (procedure),
GIMP_PROCEDURE_CONFIG (config),
image);
gtk_widget_set_halign (gimp_procedure_dialog_get_label (GIMP_PROCEDURE_DIALOG (dialog),
"info-text", NULL, TRUE, FALSE),
GTK_ALIGN_START);
gimp_procedure_dialog_fill (GIMP_PROCEDURE_DIALOG (dialog),
"description", "spacing",
"cell-width", "cell-height", "num-cells",
"info-text", "dimension", NULL);
g_object_set_data (G_OBJECT (dialog), "image", image);
g_signal_connect (config, "notify::cell-width",
G_CALLBACK (gih_cell_width_notify),
dialog);
g_signal_connect (config, "notify::cell-height",
G_CALLBACK (gih_cell_width_notify),
dialog);
gih_cell_width_notify (config, NULL, GIMP_PROCEDURE_DIALOG (dialog));
g_signal_connect (config, "notify::dimension",
G_CALLBACK (gih_dimension_notify),
&cellw_adjust);
/*
* Ranks / Selection: ______ ______ ______ ______ ______
*/
g_object_get (config,
"selection-modes", &selection,
"ranks", &rank_bytes,
"num-cells", &num_cells,
NULL);
if (selection == NULL || g_strv_length (selection) != GIMP_PIXPIPE_MAXDIM)
{
GStrvBuilder *builder = g_strv_builder_new ();
gint old_len;
old_len = (selection == NULL ? 0 : g_strv_length (selection));
for (i = 0; i < MIN (old_len, GIMP_PIXPIPE_MAXDIM); i++)
g_strv_builder_add (builder, selection[i]);
for (i = old_len; i < GIMP_PIXPIPE_MAXDIM; i++)
g_strv_builder_add (builder, "random");
g_strfreev (selection);
selection = g_strv_builder_end (builder);
g_strv_builder_unref (builder);
}
if (rank_bytes == NULL)
{
dimension = 1;
rank[0] = 1;
for (i = 1; i < GIMP_PIXPIPE_MAXDIM; i++)
rank[i] = 0;
}
else
{
const guint8 *stored;
stored = g_bytes_get_data (rank_bytes, NULL);
dimension = g_bytes_get_size (rank_bytes);
for (i = 0; i < dimension; i++)
rank[i] = stored[i];
for (i = dimension; i < GIMP_PIXPIPE_MAXDIM; i++)
rank[i] = 1;
}
g_bytes_unref (rank_bytes);
dimension = MAX (dimension, 1);
dimgrid = gtk_grid_new ();
gtk_grid_set_column_spacing (GTK_GRID (dimgrid), 4);
label = gtk_label_new (_("Ranks:"));
gtk_grid_attach (GTK_GRID (dimgrid), label, 0, 0, 1, 1);
gtk_widget_show (label);
for (i = 0; i < GIMP_PIXPIPE_MAXDIM; i++)
{
gsize j;
adjustment = gtk_adjustment_new (rank[i], 1, 100, 1, 1, 0);
if (i == 0)
g_object_set_data (G_OBJECT (dialog), "rank0", adjustment);
spinbutton = gimp_spin_button_new (adjustment, 1.0, 0);
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (spinbutton), TRUE);
gtk_grid_attach (GTK_GRID (dimgrid), spinbutton, 1, i, 1, 1);
gtk_widget_show (spinbutton);
if (i >= dimension)
gtk_widget_set_sensitive (spinbutton, FALSE);
g_signal_connect (adjustment, "value-changed",
G_CALLBACK (gimp_int_adjustment_update),
&rank[i]);
cellw_adjust.rank_entry[i] = cellh_adjust.rank_entry[i] = spinbutton;
cb = gtk_combo_box_text_new ();
for (j = 0; j < G_N_ELEMENTS (selection_modes); j++)
gtk_combo_box_text_append_text (GTK_COMBO_BOX_TEXT (cb),
selection_modes[j]);
gtk_combo_box_set_active (GTK_COMBO_BOX (cb), 2); /* random */
for (j = 0; j < G_N_ELEMENTS (selection_modes); j++)
if (!strcmp (selection[i], selection_modes[j]))
{
gtk_combo_box_set_active (GTK_COMBO_BOX (cb), j);
break;
}
gtk_grid_attach (GTK_GRID (dimgrid), cb, 2, i, 1, 1);
gtk_widget_show (cb);
if (i >= dimension)
gtk_widget_set_sensitive (cb, FALSE);
g_signal_connect (GTK_COMBO_BOX (cb), "changed",
G_CALLBACK (gih_selection_mode_changed),
&selection[i]);
cellw_adjust.mode_entry[i] = cellh_adjust.mode_entry[i] = cb;
}
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
dimgrid, TRUE, TRUE, 0);
gtk_widget_show (dimgrid);
run = gimp_procedure_dialog_run (GIMP_PROCEDURE_DIALOG (dialog));
g_object_get (config, "dimension", &dimension, NULL);
rank_bytes = g_bytes_new (rank, sizeof (guint8) * dimension);
g_object_set (config,
"selection-modes", selection,
"ranks", rank_bytes,
NULL);
gih_remove_guides (config, image);
gtk_widget_destroy (dialog);
g_strfreev (selection);
g_bytes_unref (rank_bytes);
return run;
}