Commit a0ae31d3 authored by Michael Natterer's avatar Michael Natterer 😴

plug-ins, pdb: remove the edge-dog plug-in and add a PDB compat procedure

This is not for 2.10 because the result of the GEGL op looks different,
but without doubt more correct.
parent 798d5571
......@@ -28,7 +28,7 @@
#include "internal-procs.h"
/* 739 procedures registered total */
/* 740 procedures registered total */
void
internal_procs_init (GimpPDB *pdb)
......
......@@ -1440,6 +1440,85 @@ plug_in_displace_polar_invoker (GimpProcedure *procedure,
error ? *error : NULL);
}
static GimpValueArray *
plug_in_dog_invoker (GimpProcedure *procedure,
Gimp *gimp,
GimpContext *context,
GimpProgress *progress,
const GimpValueArray *args,
GError **error)
{
gboolean success = TRUE;
GimpImage *image;
GimpDrawable *drawable;
gdouble inner;
gdouble outer;
gboolean normalize;
gboolean invert;
image = gimp_value_get_image (gimp_value_array_index (args, 1), gimp);
drawable = gimp_value_get_drawable (gimp_value_array_index (args, 2), gimp);
inner = g_value_get_double (gimp_value_array_index (args, 3));
outer = g_value_get_double (gimp_value_array_index (args, 4));
normalize = g_value_get_boolean (gimp_value_array_index (args, 5));
invert = g_value_get_boolean (gimp_value_array_index (args, 6));
if (success)
{
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
GIMP_PDB_ITEM_CONTENT, error) &&
gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
{
GeglNode *node;
if (normalize || invert)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_MISC,
C_("undo-type", "DoG Edge Detect"));
node = gegl_node_new_child (NULL,
"operation", "gegl:difference-of-gaussians",
"radius1", inner * 0.32,
"radius2", outer * 0.32,
NULL);
node = wrap_in_gamma_cast (node, drawable);
gimp_drawable_apply_operation (drawable, progress,
C_("undo-type", "DoG Edge Detect"),
node);
g_object_unref (node);
if (normalize)
{
node = gegl_node_new_child (NULL,
"operation", "gegl:stretch-contrast",
"keep-colors", TRUE,
"perceptual", TRUE,
NULL);
gimp_drawable_apply_operation (drawable, progress,
C_("undo-type", "Normalize"),
node);
g_object_unref (node);
}
if (invert)
gimp_drawable_apply_operation_by_name (drawable, progress,
C_("undo-type", "Invert"),
"gegl:invert-gamma",
NULL);
if (normalize || invert)
gimp_image_undo_group_end (image);
}
else
success = FALSE;
}
return gimp_procedure_get_return_values (procedure, success,
error ? *error : NULL);
}
static GimpValueArray *
plug_in_edge_invoker (GimpProcedure *procedure,
Gimp *gimp,
......@@ -5589,6 +5668,66 @@ register_plug_in_compat_procs (GimpPDB *pdb)
gimp_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
/*
* gimp-plug-in-dog
*/
procedure = gimp_procedure_new (plug_in_dog_invoker);
gimp_object_set_static_name (GIMP_OBJECT (procedure),
"plug-in-dog");
gimp_procedure_set_static_strings (procedure,
"plug-in-dog",
"Edge detection with control of edge thickness",
"Applies two Gaussian blurs to the drawable, and subtracts the results. This is robust and widely used method for detecting edges.",
"Compatibility procedure. Please see 'gegl:difference-of-gaussians' for credits.",
"Compatibility procedure. Please see 'gegl:difference-of-gaussians' for credits.",
"2015",
NULL);
gimp_procedure_add_argument (procedure,
g_param_spec_enum ("run-mode",
"run mode",
"The run mode",
GIMP_TYPE_RUN_MODE,
GIMP_RUN_INTERACTIVE,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_image_id ("image",
"image",
"Input image (unused)",
pdb->gimp, FALSE,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
gimp_param_spec_drawable_id ("drawable",
"drawable",
"Input drawable",
pdb->gimp, FALSE,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
g_param_spec_double ("inner",
"inner",
"Radius of inner gaussian blur in pixels",
0.0, 10.0, 0.0,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
g_param_spec_double ("outer",
"outer",
"Radius of outer gaussian blur in pixels",
0.0, 10.0, 0.0,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
g_param_spec_boolean ("normalize",
"normalize",
"Normalize",
FALSE,
GIMP_PARAM_READWRITE));
gimp_procedure_add_argument (procedure,
g_param_spec_boolean ("invert",
"invert",
"Invert",
FALSE,
GIMP_PARAM_READWRITE));
gimp_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
/*
* gimp-plug-in-edge
*/
......
......@@ -1255,6 +1255,90 @@ CODE
);
}
sub plug_in_dog {
$blurb = 'Edge detection with control of edge thickness';
$help = <<'HELP';
Applies two Gaussian blurs to the drawable, and subtracts the results.
This is robust and widely used method for detecting edges.
HELP
&std_pdb_compat('gegl:difference-of-gaussians');
$date = '2015';
@inargs = (
{ name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
desc => 'The run mode' },
{ name => 'image', type => 'image',
desc => 'Input image (unused)' },
{ name => 'drawable', type => 'drawable',
desc => 'Input drawable' },
{ name => 'inner', type => '0.0 <= float <= 10.0',
desc => 'Radius of inner gaussian blur in pixels' },
{ name => 'outer', type => '0.0 <= float <= 10.0',
desc => 'Radius of outer gaussian blur in pixels' },
{ name => 'normalize', type => 'boolean',
desc => 'Normalize' },
{ name => 'invert', type => 'boolean',
desc => 'Invert' }
);
%invoke = (
code => <<'CODE'
{
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
GIMP_PDB_ITEM_CONTENT, error) &&
gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
{
GeglNode *node;
if (normalize || invert)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_MISC,
C_("undo-type", "DoG Edge Detect"));
node = gegl_node_new_child (NULL,
"operation", "gegl:difference-of-gaussians",
"radius1", inner * 0.32,
"radius2", outer * 0.32,
NULL);
node = wrap_in_gamma_cast (node, drawable);
gimp_drawable_apply_operation (drawable, progress,
C_("undo-type", "DoG Edge Detect"),
node);
g_object_unref (node);
if (normalize)
{
node = gegl_node_new_child (NULL,
"operation", "gegl:stretch-contrast",
"keep-colors", TRUE,
"perceptual", TRUE,
NULL);
gimp_drawable_apply_operation (drawable, progress,
C_("undo-type", "Normalize"),
node);
g_object_unref (node);
}
if (invert)
gimp_drawable_apply_operation_by_name (drawable, progress,
C_("undo-type", "Invert"),
"gegl:invert-gamma",
NULL);
if (normalize || invert)
gimp_image_undo_group_end (image);
}
else
success = FALSE;
}
CODE
);
}
sub plug_in_edge {
$blurb = 'Several simple methods for detecting edges';
......@@ -4980,6 +5064,7 @@ CODE
plug_in_diffraction
plug_in_displace
plug_in_displace_polar
plug_in_dog
plug_in_edge
plug_in_engrave
plug_in_exchange
......
......@@ -40,8 +40,6 @@
/despeckle.exe
/destripe
/destripe.exe
/edge-dog
/edge-dog.exe
/emboss
/emboss.exe
/file-aa
......
......@@ -65,7 +65,6 @@ decompose_libexecdir = $(gimpplugindir)/plug-ins/decompose
depth_merge_libexecdir = $(gimpplugindir)/plug-ins/depth-merge
despeckle_libexecdir = $(gimpplugindir)/plug-ins/despeckle
destripe_libexecdir = $(gimpplugindir)/plug-ins/destripe
edge_dog_libexecdir = $(gimpplugindir)/plug-ins/edge-dog
emboss_libexecdir = $(gimpplugindir)/plug-ins/emboss
file_aa_libexecdir = $(gimpplugindir)/plug-ins/file-aa
file_cel_libexecdir = $(gimpplugindir)/plug-ins/file-cel
......@@ -153,7 +152,6 @@ decompose_libexec_PROGRAMS = decompose
depth_merge_libexec_PROGRAMS = depth-merge
despeckle_libexec_PROGRAMS = despeckle
destripe_libexec_PROGRAMS = destripe
edge_dog_libexec_PROGRAMS = edge-dog
emboss_libexec_PROGRAMS = emboss
file_aa_libexec_PROGRAMS = $(FILE_AA)
file_cel_libexec_PROGRAMS = file-cel
......@@ -577,23 +575,6 @@ destripe_LDADD = \
$(INTLLIBS) \
$(destripe_RC)
edge_dog_SOURCES = \
edge-dog.c
edge_dog_LDADD = \
$(libgimpui) \
$(libgimpwidgets) \
$(libgimpmodule) \
$(libgimp) \
$(libgimpmath) \
$(libgimpconfig) \
$(libgimpcolor) \
$(libgimpbase) \
$(GTK_LIBS) \
$(RT_LIBS) \
$(INTLLIBS) \
$(edge_dog_RC)
emboss_SOURCES = \
emboss.c
......
/* 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/>.
*/
/*
* Gimp plug-in dog.c: (C) 2004 William Skaggs
*
* Edge detection using the "Difference of Gaussians" method.
* Finds edges by doing two Gaussian blurs with different radius, and
* subtracting the results. Blurring is done using code taken from
* gauss_rle.c (as of Gimp 2.1, incorporated into gauss.c).
*/
#include "config.h"
#include <string.h>
#include <libgimp/gimp.h>
#include <libgimp/gimpui.h>
#include "libgimp/stdplugins-intl.h"
#define PLUG_IN_PROC "plug-in-dog"
#define PLUG_IN_BINARY "edge-dog"
#define PLUG_IN_ROLE "gimp-edge-dog"
typedef struct
{
gdouble inner;
gdouble outer;
gboolean normalize;
gboolean invert;
} DoGValues;
/* Declare local functions.
*/
static void query (void);
static void run (const gchar *name,
gint nparams,
const GimpParam *param,
gint *nreturn_vals,
GimpParam **return_vals);
static gint dog_dialog (gint32 image_ID,
GimpDrawable *drawable);
static void gauss_rle (GimpDrawable *drawable,
gdouble radius,
gint pass,
gboolean show_progress);
static void compute_difference (GimpDrawable *drawable,
GimpDrawable *drawable1,
GimpDrawable *drawable2,
guchar *maxval);
static void normalize_invert (GimpDrawable *drawable,
gboolean normalize,
guint maxval,
gboolean invert);
static void dog (gint32 image_ID,
GimpDrawable *drawable,
gdouble inner,
gdouble outer,
gboolean show_progress);
static void preview_update_preview (GimpPreview *preview,
GimpDrawable *drawable);
static void change_radius_callback (GtkWidget *widget,
gpointer data);
/*
* Gaussian blur helper functions
*/
static gint * make_curve (gdouble sigma,
gint *length);
static void run_length_encode (guchar *src,
gint *dest,
gint bytes,
gint width);
const GimpPlugInInfo PLUG_IN_INFO =
{
NULL, /* init_proc */
NULL, /* quit_proc */
query, /* query_proc */
run, /* run_proc */
};
static DoGValues dogvals =
{
3.0, /* inner radius */
1.0, /* outer radius */
TRUE, /* normalize */
TRUE /* invert */
};
MAIN ()
static void
query (void)
{
static const GimpParamDef args[] =
{
{ GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
{ GIMP_PDB_IMAGE, "image", "Input image" },
{ GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
{ GIMP_PDB_FLOAT, "inner", "Radius of inner gaussian blur (in pixels, > 0.0)" },
{ GIMP_PDB_FLOAT, "outer", "Radius of outer gaussian blur (in pixels, > 0.0)" },
{ GIMP_PDB_INT32, "normalize", "Normalize { TRUE, FALSE }" },
{ GIMP_PDB_INT32, "invert", "Invert { TRUE, FALSE }" }
};
gimp_install_procedure (PLUG_IN_PROC,
N_("Edge detection with control of edge thickness"),
"Applies two Gaussian blurs to the drawable, and "
"subtracts the results. This is robust and widely "
"used method for detecting edges.",
"Spencer Kimball, Peter Mattis, Sven Neumann, William Skaggs",
"Spencer Kimball, Peter Mattis, Sven Neumann, William Skaggs",
"1995-2004",
N_("_Difference of Gaussians (legacy)..."),
"RGB*, GRAY*",
GIMP_PLUGIN,
G_N_ELEMENTS (args), 0,
args, NULL);
gimp_plugin_menu_register (PLUG_IN_PROC, "<Image>/Filters/Edge-Detect");
}
static void
run (const gchar *name,
gint nparams,
const GimpParam *param,
gint *nreturn_vals,
GimpParam **return_vals)
{
static GimpParam values[2];
gint32 image_ID;
GimpDrawable *drawable;
GimpRunMode run_mode;
GimpPDBStatusType status = GIMP_PDB_SUCCESS;
GError *error = NULL;
run_mode = param[0].data.d_int32;
INIT_I18N ();
*nreturn_vals = 1;
*return_vals = values;
values[0].type = GIMP_PDB_STATUS;
values[0].data.d_status = status;
if (! gimp_item_is_layer (param[2].data.d_drawable))
{
g_set_error (&error, 0, 0, "%s",
_("Can operate on layers only "
"(but was called on channel or mask)."));
status = GIMP_PDB_EXECUTION_ERROR;
}
if (status == GIMP_PDB_SUCCESS)
{
/* Get the specified image and drawable */
image_ID = param[1].data.d_image;
drawable = gimp_drawable_get (param[2].data.d_drawable);
/* set the tile cache size so that the gaussian blur works well */
gimp_tile_cache_ntiles (2 *
(MAX (drawable->width, drawable->height) /
gimp_tile_width () + 1));
if (strcmp (name, PLUG_IN_PROC) == 0)
{
switch (run_mode)
{
case GIMP_RUN_INTERACTIVE:
/* Possibly retrieve data */
gimp_get_data (PLUG_IN_PROC, &dogvals);
/* First acquire information with a dialog */
if (! dog_dialog (image_ID, drawable))
return;
break;
case GIMP_RUN_NONINTERACTIVE:
/* Make sure all the arguments are there! */
if (nparams != 7)
status = GIMP_PDB_CALLING_ERROR;
if (status == GIMP_PDB_SUCCESS)
{
dogvals.inner = param[3].data.d_float;
dogvals.outer = param[4].data.d_float;
dogvals.normalize = param[5].data.d_int32;
dogvals.invert = param[6].data.d_int32;
if (dogvals.inner <= 0.0 || dogvals.outer <= 0.0)
status = GIMP_PDB_CALLING_ERROR;
}
break;
case GIMP_RUN_WITH_LAST_VALS:
/* Possibly retrieve data */
gimp_get_data (PLUG_IN_PROC, &dogvals);
break;
default:
break;
}
}
else
{
status = GIMP_PDB_CALLING_ERROR;
}
}
if (status == GIMP_PDB_SUCCESS)
{
/* Make sure that the drawable is gray or RGB color */
if (gimp_drawable_is_rgb (drawable->drawable_id) ||
gimp_drawable_is_gray (drawable->drawable_id))
{
gimp_progress_init (_("DoG Edge Detect"));
/* run the Difference of Gaussians */
gimp_image_undo_group_start (image_ID);
dog (image_ID, drawable, dogvals.inner, dogvals.outer, TRUE);
gimp_image_undo_group_end (image_ID);
gimp_progress_update (1.0);
/* Store data */
if (run_mode == GIMP_RUN_INTERACTIVE)
gimp_set_data (PLUG_IN_PROC, &dogvals, sizeof (DoGValues));
if (run_mode != GIMP_RUN_NONINTERACTIVE)
gimp_displays_flush ();
}
else
{
status = GIMP_PDB_EXECUTION_ERROR;
*nreturn_vals = 2;
values[1].type = GIMP_PDB_STRING;
values[1].data.d_string = _("Cannot operate on indexed color images.");
}
gimp_drawable_detach (drawable);
}
if (status != GIMP_PDB_SUCCESS && error)
{
*nreturn_vals = 2;
values[1].type = GIMP_PDB_STRING;
values[1].data.d_string = error->message;
}
values[0].data.d_status = status;
}
static gint
dog_dialog (gint32 image_ID,
GimpDrawable *drawable)
{
GtkWidget *dialog;
GtkWidget *frame;
GtkWidget *button;
GtkWidget *main_vbox;
GtkWidget *preview;
GtkWidget *coord;
GimpUnit unit;
gdouble xres;
gdouble yres;
gboolean run;
gimp_ui_init (PLUG_IN_BINARY, FALSE);
dialog = gimp_dialog_new (_("DoG Edge Detect"), PLUG_IN_ROLE,
NULL, 0,
gimp_standard_help_func, PLUG_IN_PROC,
_("_Cancel"), GTK_RESPONSE_CANCEL,
_("_OK"), GTK_RESPONSE_OK,
NULL);
gimp_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
GTK_RESPONSE_OK,
GTK_RESPONSE_CANCEL,
-1);
gimp_window_set_transient (GTK_WINDOW (dialog));
main_vbox = gtk_box_new (GTK_ORIENTATION_VERTICAL, 12);
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 12);
gtk_box_pack_start (GTK_BOX (gtk_dialog_get_content_area (GTK_DIALOG (dialog))),
main_vbox, TRUE, TRUE, 0);
gtk_widget_show (main_vbox);
preview = gimp_drawable_preview_new_from_drawable_id (drawable->drawable_id);
gtk_box_pack_start (GTK_BOX (main_vbox), preview, FALSE, FALSE, 0);
gtk_widget_show (preview);
g_signal_connect (preview, "invalidated",
G_CALLBACK (preview_update_preview),
drawable);
frame = gimp_frame_new (_("Smoothing Parameters"));
gtk_box_pack_start (GTK_BOX (main_vbox), frame, FALSE, FALSE, 0);
gtk_widget_show (frame);
/* Get the image resolution and unit */
gimp_image_get_resolution (image_ID, &xres, &yres);
unit = gimp_image_get_unit (image_ID);
coord = gimp_coordinates_new (unit, "%a", TRUE, FALSE, -1,
GIMP_SIZE_ENTRY_UPDATE_SIZE,
FALSE,
TRUE,
_("_Radius 1:"), dogvals.inner, xres,
0, 8 * MAX (drawable->width, drawable->height),
0, 0,
_("R_adius 2:"), dogvals.outer, yres,
0, 8 * MAX (drawable->width, drawable->height),
0, 0);
gtk_container_add (GTK_CONTAINER (frame), coord);
gtk_widget_show (coord);
gimp_size_entry_set_pixel_digits (GIMP_SIZE_ENTRY (coord), 1);
g_signal_connect (coord, "value-changed",
G_CALLBACK (change_radius_callback),
preview);
button = gtk_check_button_new_with_mnemonic (_("_Normalize"));
gtk_box_pack_start (GTK_BOX (main_vbox), button, FALSE, FALSE, 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), dogvals.normalize);
g_signal_connect (button, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&dogvals.normalize);
g_signal_connect_swapped (button, "toggled",
G_CALLBACK (gimp_preview_invalidate),
preview);
gtk_widget_show (button);
button = gtk_check_button_new_with_mnemonic (_("_Invert"));
gtk_box_pack_start (GTK_BOX (main_vbox), button, FALSE, FALSE, 0);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (button), dogvals.invert);
g_signal_connect (button, "toggled",
G_CALLBACK (gimp_toggle_button_update),
&dogvals.invert);
g_signal_connect_swapped (button, "toggled",
G_CALLBACK (gimp_preview_invalidate),