diff --git a/app/pdb/internal-procs.c b/app/pdb/internal-procs.c
index 35d298581a..017e0fdc0d 100644
--- a/app/pdb/internal-procs.c
+++ b/app/pdb/internal-procs.c
@@ -28,7 +28,7 @@
#include "internal-procs.h"
-/* 721 procedures registered total */
+/* 726 procedures registered total */
void
internal_procs_init (GimpPDB *pdb)
diff --git a/app/pdb/plug-in-compat-cmds.c b/app/pdb/plug-in-compat-cmds.c
index 789c86daf2..ae086814a1 100644
--- a/app/pdb/plug-in-compat-cmds.c
+++ b/app/pdb/plug-in-compat-cmds.c
@@ -42,6 +42,7 @@
#include "core/gimpparamspecs.h"
#include "core/gimppickable-auto-shrink.h"
#include "core/gimppickable.h"
+#include "gegl/gimp-babl.h"
#include "gegl/gimp-gegl-utils.h"
#include "gimppdb.h"
@@ -52,6 +53,95 @@
#include "gimp-intl.h"
+static GeglNode *
+wrap_in_gamma_cast (GeglNode *node,
+ GimpDrawable *drawable)
+{
+ if (! gimp_drawable_get_linear (drawable))
+ {
+ const Babl *drawable_format;
+ const Babl *cast_format;
+ GeglNode *new_node;
+ GeglNode *input;
+ GeglNode *output;
+ GeglNode *cast_before;
+ GeglNode *cast_after;
+
+ drawable_format = gimp_drawable_get_format (drawable);
+
+ cast_format =
+ gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
+ gimp_babl_precision (gimp_babl_format_get_component_type (drawable_format),
+ TRUE),
+ babl_format_has_alpha (drawable_format));
+
+ new_node = gegl_node_new ();
+
+ gegl_node_add_child (new_node, node);
+ g_object_unref (node);
+
+ input = gegl_node_get_input_proxy (new_node, "input");
+ output = gegl_node_get_output_proxy (new_node, "output");
+
+ cast_before = gegl_node_new_child (new_node,
+ "operation", "gimp:cast-format",
+ "input-format", drawable_format,
+ "output-format", cast_format,
+ NULL);
+ cast_after = gegl_node_new_child (new_node,
+ "operation", "gimp:cast-format",
+ "input-format", cast_format,
+ "output-format", drawable_format,
+ NULL);
+
+ gegl_node_link_many (input,
+ cast_before,
+ node,
+ cast_after,
+ output,
+ NULL);
+
+ return new_node;
+ }
+ else
+ {
+ return node;
+ }
+}
+
+static gboolean
+gaussian_blur (GimpDrawable *drawable,
+ gdouble horizontal,
+ gdouble vertical,
+ GimpProgress *progress,
+ GError **error)
+{
+ 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;
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:gaussian-blur",
+ "std-dev-x", horizontal * 0.32,
+ "std-dev-y", vertical * 0.32,
+ NULL);
+
+ node = wrap_in_gamma_cast (node, drawable);
+
+ gimp_drawable_apply_operation (drawable, progress,
+ C_("undo-type", "Gaussian Blur"),
+ node);
+
+ g_object_unref (node);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
static GimpValueArray *
plug_in_alienmap2_invoker (GimpProcedure *procedure,
Gimp *gimp,
@@ -612,6 +702,146 @@ plug_in_cubism_invoker (GimpProcedure *procedure,
error ? *error : NULL);
}
+static GimpValueArray *
+plug_in_gauss_invoker (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ const GimpValueArray *args,
+ GError **error)
+{
+ gboolean success = TRUE;
+ GimpDrawable *drawable;
+ gdouble horizontal;
+ gdouble vertical;
+
+ drawable = gimp_value_get_drawable (gimp_value_array_index (args, 2), gimp);
+ horizontal = g_value_get_double (gimp_value_array_index (args, 3));
+ vertical = g_value_get_double (gimp_value_array_index (args, 4));
+
+ if (success)
+ {
+ success = gaussian_blur (drawable, horizontal, vertical, progress, error);
+ }
+
+ return gimp_procedure_get_return_values (procedure, success,
+ error ? *error : NULL);
+}
+
+static GimpValueArray *
+plug_in_gauss_iir_invoker (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ const GimpValueArray *args,
+ GError **error)
+{
+ gboolean success = TRUE;
+ GimpDrawable *drawable;
+ gdouble radius;
+ gboolean horizontal;
+ gboolean vertical;
+
+ drawable = gimp_value_get_drawable (gimp_value_array_index (args, 2), gimp);
+ radius = g_value_get_double (gimp_value_array_index (args, 3));
+ horizontal = g_value_get_boolean (gimp_value_array_index (args, 4));
+ vertical = g_value_get_boolean (gimp_value_array_index (args, 5));
+
+ if (success)
+ {
+ success = gaussian_blur (drawable,
+ horizontal ? radius : 0.0,
+ vertical ? radius : 0.0,
+ progress, error);
+ }
+
+ return gimp_procedure_get_return_values (procedure, success,
+ error ? *error : NULL);
+}
+
+static GimpValueArray *
+plug_in_gauss_iir2_invoker (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ const GimpValueArray *args,
+ GError **error)
+{
+ gboolean success = TRUE;
+ GimpDrawable *drawable;
+ gdouble horizontal;
+ gdouble vertical;
+
+ drawable = gimp_value_get_drawable (gimp_value_array_index (args, 2), gimp);
+ horizontal = g_value_get_double (gimp_value_array_index (args, 3));
+ vertical = g_value_get_double (gimp_value_array_index (args, 4));
+
+ if (success)
+ {
+ success = gaussian_blur (drawable, horizontal, vertical, progress, error);
+ }
+
+ return gimp_procedure_get_return_values (procedure, success,
+ error ? *error : NULL);
+}
+
+static GimpValueArray *
+plug_in_gauss_rle_invoker (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ const GimpValueArray *args,
+ GError **error)
+{
+ gboolean success = TRUE;
+ GimpDrawable *drawable;
+ gdouble radius;
+ gboolean horizontal;
+ gboolean vertical;
+
+ drawable = gimp_value_get_drawable (gimp_value_array_index (args, 2), gimp);
+ radius = g_value_get_double (gimp_value_array_index (args, 3));
+ horizontal = g_value_get_boolean (gimp_value_array_index (args, 4));
+ vertical = g_value_get_boolean (gimp_value_array_index (args, 5));
+
+ if (success)
+ {
+ success = gaussian_blur (drawable,
+ horizontal ? radius : 0.0,
+ vertical ? radius : 0.0,
+ progress, error);
+ }
+
+ return gimp_procedure_get_return_values (procedure, success,
+ error ? *error : NULL);
+}
+
+static GimpValueArray *
+plug_in_gauss_rle2_invoker (GimpProcedure *procedure,
+ Gimp *gimp,
+ GimpContext *context,
+ GimpProgress *progress,
+ const GimpValueArray *args,
+ GError **error)
+{
+ gboolean success = TRUE;
+ GimpDrawable *drawable;
+ gdouble horizontal;
+ gdouble vertical;
+
+ drawable = gimp_value_get_drawable (gimp_value_array_index (args, 2), gimp);
+ horizontal = g_value_get_double (gimp_value_array_index (args, 3));
+ vertical = g_value_get_double (gimp_value_array_index (args, 4));
+
+ if (success)
+ {
+ success = gaussian_blur (drawable, horizontal, vertical, progress, error);
+ }
+
+ return gimp_procedure_get_return_values (procedure, success,
+ error ? *error : NULL);
+}
+
static GimpValueArray *
plug_in_hsv_noise_invoker (GimpProcedure *procedure,
Gimp *gimp,
@@ -2371,6 +2601,264 @@ register_plug_in_compat_procs (GimpPDB *pdb)
gimp_pdb_register_procedure (pdb, procedure);
g_object_unref (procedure);
+ /*
+ * gimp-plug-in-gauss
+ */
+ procedure = gimp_procedure_new (plug_in_gauss_invoker);
+ gimp_object_set_static_name (GIMP_OBJECT (procedure),
+ "plug-in-gauss");
+ gimp_procedure_set_static_strings (procedure,
+ "plug-in-gauss",
+ "Simplest, most commonly used way of blurring",
+ "Applies a gaussian blur to the drawable, with specified radius of affect. The standard deviation of the normal distribution used to modify pixel values is calculated based on the supplied radius. Horizontal and vertical blurring can be independently invoked by specifying only one to run. The 'method' parameter is ignored.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "2014",
+ 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 ("horizontal",
+ "horizontal",
+ "Horizontal radius of gaussian blur (in pixels",
+ 0.0, 500.0, 0.0,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ g_param_spec_double ("vertical",
+ "vertical",
+ "Vertical radius of gaussian blur (in pixels",
+ 0.0, 500.0, 0.0,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ gimp_param_spec_int32 ("method",
+ "method",
+ "Blur method { IIR (0), RLE (1) }",
+ 0, 1, 0,
+ GIMP_PARAM_READWRITE));
+ gimp_pdb_register_procedure (pdb, procedure);
+ g_object_unref (procedure);
+
+ /*
+ * gimp-plug-in-gauss-iir
+ */
+ procedure = gimp_procedure_new (plug_in_gauss_iir_invoker);
+ gimp_object_set_static_name (GIMP_OBJECT (procedure),
+ "plug-in-gauss-iir");
+ gimp_procedure_set_static_strings (procedure,
+ "plug-in-gauss-iir",
+ "Apply a gaussian blur",
+ "Applies a gaussian blur to the drawable, with specified radius of affect. The standard deviation of the normal distribution used to modify pixel values is calculated based on the supplied radius. Horizontal and vertical blurring can be independently invoked by specifying only one to run.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "2014",
+ 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 ("radius",
+ "radius",
+ "Radius of gaussian blur (in pixels",
+ 0.0, 500.0, 0.0,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ g_param_spec_boolean ("horizontal",
+ "horizontal",
+ "Blur in horizontal direction",
+ FALSE,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ g_param_spec_boolean ("vertical",
+ "vertical",
+ "Blur in vertical direction",
+ FALSE,
+ GIMP_PARAM_READWRITE));
+ gimp_pdb_register_procedure (pdb, procedure);
+ g_object_unref (procedure);
+
+ /*
+ * gimp-plug-in-gauss-iir2
+ */
+ procedure = gimp_procedure_new (plug_in_gauss_iir2_invoker);
+ gimp_object_set_static_name (GIMP_OBJECT (procedure),
+ "plug-in-gauss-iir2");
+ gimp_procedure_set_static_strings (procedure,
+ "plug-in-gauss-iir2",
+ "Apply a gaussian blur",
+ "Applies a gaussian blur to the drawable, with specified radius of affect. The standard deviation of the normal distribution used to modify pixel values is calculated based on the supplied radius. Horizontal and vertical blurring can be independently invoked by specifying only one to run.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "2014",
+ 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 ("horizontal",
+ "horizontal",
+ "Horizontal radius of gaussian blur (in pixels",
+ 0.0, 500.0, 0.0,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ g_param_spec_double ("vertical",
+ "vertical",
+ "Vertical radius of gaussian blur (in pixels",
+ 0.0, 500.0, 0.0,
+ GIMP_PARAM_READWRITE));
+ gimp_pdb_register_procedure (pdb, procedure);
+ g_object_unref (procedure);
+
+ /*
+ * gimp-plug-in-gauss-rle
+ */
+ procedure = gimp_procedure_new (plug_in_gauss_rle_invoker);
+ gimp_object_set_static_name (GIMP_OBJECT (procedure),
+ "plug-in-gauss-rle");
+ gimp_procedure_set_static_strings (procedure,
+ "plug-in-gauss-rle",
+ "Apply a gaussian blur",
+ "Applies a gaussian blur to the drawable, with specified radius of affect. The standard deviation of the normal distribution used to modify pixel values is calculated based on the supplied radius. Horizontal and vertical blurring can be independently invoked by specifying only one to run.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "2014",
+ 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 ("radius",
+ "radius",
+ "Radius of gaussian blur (in pixels",
+ 0.0, 500.0, 0.0,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ g_param_spec_boolean ("horizontal",
+ "horizontal",
+ "Blur in horizontal direction",
+ FALSE,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ g_param_spec_boolean ("vertical",
+ "vertical",
+ "Blur in vertical direction",
+ FALSE,
+ GIMP_PARAM_READWRITE));
+ gimp_pdb_register_procedure (pdb, procedure);
+ g_object_unref (procedure);
+
+ /*
+ * gimp-plug-in-gauss-rle2
+ */
+ procedure = gimp_procedure_new (plug_in_gauss_rle2_invoker);
+ gimp_object_set_static_name (GIMP_OBJECT (procedure),
+ "plug-in-gauss-rle2");
+ gimp_procedure_set_static_strings (procedure,
+ "plug-in-gauss-rle2",
+ "Apply a gaussian blur",
+ "Applies a gaussian blur to the drawable, with specified radius of affect. The standard deviation of the normal distribution used to modify pixel values is calculated based on the supplied radius. Horizontal and vertical blurring can be independently invoked by specifying only one to run.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "Compatibility procedure. Please see 'gegl:gaussian-blur' for credits.",
+ "2014",
+ 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 ("horizontal",
+ "horizontal",
+ "Horizontal radius of gaussian blur (in pixels",
+ 0.0, 500.0, 0.0,
+ GIMP_PARAM_READWRITE));
+ gimp_procedure_add_argument (procedure,
+ g_param_spec_double ("vertical",
+ "vertical",
+ "Vertical radius of gaussian blur (in pixels",
+ 0.0, 500.0, 0.0,
+ GIMP_PARAM_READWRITE));
+ gimp_pdb_register_procedure (pdb, procedure);
+ g_object_unref (procedure);
+
/*
* gimp-plug-in-hsv-noise
*/
diff --git a/plug-ins/common/.gitignore b/plug-ins/common/.gitignore
index 39d99820ae..31add96d3a 100644
--- a/plug-ins/common/.gitignore
+++ b/plug-ins/common/.gitignore
@@ -12,8 +12,6 @@
/blinds.exe
/blur
/blur.exe
-/blur-gauss
-/blur-gauss.exe
/blur-gauss-selective
/blur-gauss-selective.exe
/border-average
diff --git a/plug-ins/common/Makefile.am b/plug-ins/common/Makefile.am
index 55f70481c7..b96660f8c9 100644
--- a/plug-ins/common/Makefile.am
+++ b/plug-ins/common/Makefile.am
@@ -49,7 +49,6 @@ libexec_PROGRAMS = \
animation-play \
blinds \
blur \
- blur-gauss \
blur-gauss-selective \
border-average \
bump-map \
@@ -276,23 +275,6 @@ blur_LDADD = \
$(INTLLIBS) \
$(blur_RC)
-blur_gauss_SOURCES = \
- blur-gauss.c
-
-blur_gauss_LDADD = \
- $(libgimpui) \
- $(libgimpwidgets) \
- $(libgimpmodule) \
- $(libgimp) \
- $(libgimpmath) \
- $(libgimpconfig) \
- $(libgimpcolor) \
- $(libgimpbase) \
- $(GTK_LIBS) \
- $(RT_LIBS) \
- $(INTLLIBS) \
- $(blur_gauss_RC)
-
blur_gauss_selective_CFLAGS = $(MMX_EXTRA_CFLAGS)
blur_gauss_selective_SOURCES = \
diff --git a/plug-ins/common/blur-gauss.c b/plug-ins/common/blur-gauss.c
deleted file mode 100644
index edffda0521..0000000000
--- a/plug-ins/common/blur-gauss.c
+++ /dev/null
@@ -1,1667 +0,0 @@
-/* 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 .
- */
-
-#include "config.h"
-
-#include
-
-#include
-#include
-
-#include "libgimp/stdplugins-intl.h"
-
-#define GAUSS_PROC "plug-in-gauss"
-#define GAUSS_IIR_PROC "plug-in-gauss-iir"
-#define GAUSS_IIR2_PROC "plug-in-gauss-iir2"
-#define GAUSS_RLE_PROC "plug-in-gauss-rle"
-#define GAUSS_RLE2_PROC "plug-in-gauss-rle2"
-#define PLUG_IN_BINARY "blur-gauss"
-#define PLUG_IN_ROLE "gimp-blur-gauss"
-
-typedef enum
-{
- BLUR_IIR,
- BLUR_RLE
-} BlurMethod;
-
-typedef struct
-{
- gdouble horizontal;
- gdouble vertical;
- BlurMethod method;
-} BlurValues;
-
-
-/* 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 void gauss (GimpDrawable *drawable,
- gdouble horizontal,
- gdouble vertical,
- BlurMethod method,
- GtkWidget *preview);
-
-static void update_preview (GtkWidget *preview,
- GtkWidget *size);
-/*
- * Gaussian blur interface
- */
-static gboolean gauss_dialog (gint32 image_ID,
- GimpDrawable *drawable);
-
-/*
- * Gaussian blur helper functions
- */
-static void find_iir_constants (gdouble n_p[],
- gdouble n_m[],
- gdouble d_p[],
- gdouble d_m[],
- gdouble bd_p[],
- gdouble bd_m[],
- gdouble std_dev);
-
-static void transfer_pixels (const gdouble *src1,
- const gdouble *src2,
- guchar *dest,
- gint bytes,
- gint width);
-
-static void make_rle_curve (gdouble sigma,
- gint **p_curve,
- gint *p_length,
- gint **p_sum,
- gint *p_total);
-
-static void free_rle_curve (gint *curve,
- gint length,
- gint *sum);
-
-static inline gint run_length_encode (const guchar *src,
- gint *repeat,
- gint *dest,
- gint bytes,
- gint width,
- gint border,
- gboolean pack);
-
-
-const GimpPlugInInfo PLUG_IN_INFO =
-{
- NULL, /* init_proc */
- NULL, /* quit_proc */
- query, /* query_proc */
- run, /* run_proc */
-};
-
-static BlurValues bvals =
-{
- 5.0, /* x radius */
- 5.0, /* y radius */
- BLUR_RLE
-};
-
-
-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, "horizontal", "Horizontal radius of gaussian blur (in pixels, > 0.0)" },
- { GIMP_PDB_FLOAT, "vertical", "Vertical radius of gaussian blur (in pixels, > 0.0)" },
- { GIMP_PDB_INT32, "method", "Blur method { IIR (0), RLE (1) }" }
- };
-
- static const GimpParamDef args1[] =
- {
- { GIMP_PDB_INT32, "run-mode", "The run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
- { GIMP_PDB_IMAGE, "image", "Input image (unused)" },
- { GIMP_PDB_DRAWABLE, "drawable", "Input drawable" },
- { GIMP_PDB_FLOAT, "radius", "Radius of gaussian blur (in pixels, > 0.0)" },
- { GIMP_PDB_INT32, "horizontal", "Blur in horizontal direction" },
- { GIMP_PDB_INT32, "vertical", "Blur in vertical direction" }
- };
-
- static const GimpParamDef args2[] =
- {
- { 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, "horizontal", "Horizontal radius of gaussian blur (in pixels, > 0.0)" },
- { GIMP_PDB_FLOAT, "vertical", "Vertical radius of gaussian blur (in pixels, > 0.0)" }
- };
-
- gimp_install_procedure (GAUSS_PROC,
- N_("Simplest, most commonly used way of blurring"),
- "Applies a gaussian blur to the drawable, with "
- "specified radius of affect. The standard deviation "
- "of the normal distribution used to modify pixel "
- "values is calculated based on the supplied radius. "
- "Horizontal and vertical blurring can be "
- "independently invoked by specifying only one to "
- "run. The IIR gaussian blurring works best for "
- "large radius values and for images which are not "
- "computer-generated.",
- "Spencer Kimball & Peter Mattis",
- "Spencer Kimball & Peter Mattis",
- "1995-1996",
- N_("_Gaussian Blur..."),
- "RGB*, GRAY*",
- GIMP_PLUGIN,
- G_N_ELEMENTS (args), 0,
- args, NULL);
-
- gimp_install_procedure (GAUSS_IIR_PROC,
- N_("Apply a gaussian blur"),
- "Applies a gaussian blur to the drawable, with "
- "specified radius of affect. The standard deviation "
- "of the normal distribution used to modify pixel "
- "values is calculated based on the supplied radius. "
- "Horizontal and vertical blurring can be "
- "independently invoked by specifying only one to "
- "run. The IIR gaussian blurring works best for "
- "large radius values and for images which are not "
- "computer-generated.",
- "Spencer Kimball & Peter Mattis",
- "Spencer Kimball & Peter Mattis",
- "1995-1996",
- NULL,
- "RGB*, GRAY*",
- GIMP_PLUGIN,
- G_N_ELEMENTS (args1), 0,
- args1, NULL);
-
- gimp_install_procedure (GAUSS_IIR2_PROC,
- N_("Apply a gaussian blur"),
- "Applies a gaussian blur to the drawable, with "
- "specified radius of affect. The standard deviation "
- "of the normal distribution used to modify pixel "
- "values is calculated based on the supplied radius. "
- "This radius can be specified indepently on for the "
- "horizontal and the vertical direction. The IIR "
- "gaussian blurring works best for large radius "
- "values and for images which are not "
- "computer-generated.",
- "Spencer Kimball, Peter Mattis & Sven Neumann",
- "Spencer Kimball, Peter Mattis & Sven Neumann",
- "1995-2000",
- NULL,
- "RGB*, GRAY*",
- GIMP_PLUGIN,
- G_N_ELEMENTS (args2), 0,
- args2, NULL);
-
- gimp_install_procedure (GAUSS_RLE_PROC,
- N_("Apply a gaussian blur"),
- "Applies a gaussian blur to the drawable, with "
- "specified radius of affect. The standard deviation "
- "of the normal distribution used to modify pixel "
- "values is calculated based on the supplied radius. "
- "Horizontal and vertical blurring can be "
- "independently invoked by specifying only one to "
- "run. The RLE gaussian blurring performs most "
- "efficiently on computer-generated images or images "
- "with large areas of constant intensity.",
- "Spencer Kimball & Peter Mattis",
- "Spencer Kimball & Peter Mattis",
- "1995-1996",
- NULL,
- "RGB*, GRAY*",
- GIMP_PLUGIN,
- G_N_ELEMENTS (args1), 0,
- args1, NULL);
-
- gimp_install_procedure (GAUSS_RLE2_PROC,
- N_("Apply a gaussian blur"),
- "Applies a gaussian blur to the drawable, with "
- "specified radius of affect. The standard deviation "
- "of the normal distribution used to modify pixel "
- "values is calculated based on the supplied radius. "
- "This radius can be specified indepently on for the "
- "horizontal and the vertical direction. The RLE "
- "gaussian blurring performs most efficiently on "
- "computer-generated images or images with large "
- "areas of constant intensity.",
- "Spencer Kimball, Peter Mattis & Sven Neumann",
- "Spencer Kimball, Peter Mattis & Sven Neumann",
- "1995-2000",
- NULL,
- "RGB*, GRAY*",
- GIMP_PLUGIN,
- G_N_ELEMENTS (args2), 0,
- args2, NULL);
-
- gimp_plugin_menu_register (GAUSS_PROC, "/Filters/Blur");
-}
-
-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;
- gdouble radius = 0.;
-
- 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;
-
- /* 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, GAUSS_PROC) == 0)
- {
- switch (run_mode)
- {
- case GIMP_RUN_INTERACTIVE:
- /* Possibly retrieve data */
- gimp_get_data (GAUSS_PROC, &bvals);
-
- /* First acquire information with a dialog */
- if (! gauss_dialog (image_ID, drawable))
- return;
- break;
-
- case GIMP_RUN_NONINTERACTIVE:
- /* Make sure all the arguments are there! */
- if (nparams != 6)
- status = GIMP_PDB_CALLING_ERROR;
-
- if (status == GIMP_PDB_SUCCESS)
- {
- bvals.horizontal = param[3].data.d_float;
- bvals.vertical = param[4].data.d_float;
- bvals.method = param[5].data.d_int32;
- }
- if (status == GIMP_PDB_SUCCESS &&
- (bvals.horizontal <= 0.0 && bvals.vertical <= 0.0))
- status = GIMP_PDB_CALLING_ERROR;
- break;
-
- case GIMP_RUN_WITH_LAST_VALS:
- /* Possibly retrieve data */
- gimp_get_data (GAUSS_PROC, &bvals);
- break;
-
- default:
- break;
- }
- }
- else if (strcmp (name, GAUSS_IIR_PROC) == 0)
- {
- if (nparams != 6)
- status = GIMP_PDB_CALLING_ERROR;
-
- if (status == GIMP_PDB_SUCCESS)
- {
- radius = param[3].data.d_float;
- bvals.horizontal = (param[4].data.d_int32) ? radius : 0.;
- bvals.vertical = (param[5].data.d_int32) ? radius : 0.;
- bvals.method = BLUR_IIR;
- }
-
- if (radius <= 0.0)
- status = GIMP_PDB_CALLING_ERROR;
-
- if (run_mode == GIMP_RUN_INTERACTIVE)
- {
- if (! gauss_dialog (image_ID, drawable))
- return;
- }
- }
- else if (strcmp (name, GAUSS_IIR2_PROC) == 0)
- {
- if (nparams != 5)
- status = GIMP_PDB_CALLING_ERROR;
-
- if (status == GIMP_PDB_SUCCESS)
- {
- bvals.horizontal = param[3].data.d_float;
- bvals.vertical = param[4].data.d_float;
- bvals.method = BLUR_IIR;
- }
-
- if (bvals.horizontal <= 0.0 && bvals.vertical <= 0.0)
- status = GIMP_PDB_CALLING_ERROR;
-
- if (run_mode == GIMP_RUN_INTERACTIVE)
- {
- if (! gauss_dialog (image_ID, drawable))
- return;
- }
- }
- else if (strcmp (name, GAUSS_RLE_PROC) == 0)
- {
- if (nparams != 6)
- status = GIMP_PDB_CALLING_ERROR;
-
- if (status == GIMP_PDB_SUCCESS)
- {
- radius = param[3].data.d_float;
- bvals.horizontal = (param[4].data.d_int32) ? radius : 0.;
- bvals.vertical = (param[5].data.d_int32) ? radius : 0.;
- bvals.method = BLUR_RLE;
- }
-
- if (radius <= 0.0)
- status = GIMP_PDB_CALLING_ERROR;
-
- if (run_mode == GIMP_RUN_INTERACTIVE)
- {
- if (! gauss_dialog (image_ID, drawable))
- return;
- }
- }
- else if (strcmp (name, GAUSS_RLE2_PROC) == 0)
- {
- if (nparams != 5)
- status = GIMP_PDB_CALLING_ERROR;
-
- if (status == GIMP_PDB_SUCCESS)
- {
- bvals.horizontal = param[3].data.d_float;
- bvals.vertical = param[4].data.d_float;
- bvals.method = BLUR_RLE;
- }
-
- if (bvals.horizontal <= 0.0 && bvals.vertical <= 0.0)
- status = GIMP_PDB_CALLING_ERROR;
-
- if (run_mode == GIMP_RUN_INTERACTIVE)
- {
- if (! gauss_dialog (image_ID, drawable))
- return;
- }
- }
- 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 (_("Gaussian Blur"));
-
- /* run the gaussian blur */
- gauss (drawable,
- bvals.horizontal, bvals.vertical,
- bvals.method,
- NULL);
-
- /* Store data */
- if (run_mode == GIMP_RUN_INTERACTIVE)
- gimp_set_data (GAUSS_PROC, &bvals, sizeof (BlurValues));
-
- 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);
- }
-
- values[0].data.d_status = status;
-}
-
-
-
-static gboolean
-gauss_dialog (gint32 image_ID,
- GimpDrawable *drawable)
-{
- GtkWidget *dialog;
- GtkWidget *main_vbox;
- GtkWidget *frame;
- GtkWidget *size;
- GtkWidget *hbox;
- GtkWidget *button;
- GtkWidget *preview;
-
- GimpUnit unit;
- gdouble xres;
- gdouble yres;
- gboolean run;
-
- gimp_ui_init (PLUG_IN_BINARY, FALSE);
-
- dialog = gimp_dialog_new (_("Gaussian Blur"), PLUG_IN_ROLE,
- NULL, 0,
- gimp_standard_help_func, GAUSS_PROC,
-
- GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
- GTK_STOCK_OK, GTK_RESPONSE_OK,
-
- NULL);
-
- gtk_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 (drawable, NULL);
- gtk_box_pack_start (GTK_BOX (main_vbox), preview, TRUE, TRUE, 0);
- gtk_widget_show (preview);
-
- hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 12);
- gtk_box_pack_start (GTK_BOX (main_vbox), hbox, FALSE, FALSE, 0);
- gtk_widget_show (hbox);
-
- /* parameter settings */
- frame = gimp_frame_new (_("Blur Radius"));
- gtk_box_pack_start (GTK_BOX (hbox), 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);
-
- size = gimp_coordinates_new (unit, "%a", TRUE, FALSE, -1,
- GIMP_SIZE_ENTRY_UPDATE_SIZE,
-
- (bvals.horizontal == bvals.vertical),
- FALSE,
-
- _("_Horizontal:"), bvals.horizontal, xres,
- 0, 8 * MAX (drawable->width, drawable->height),
- 0, 0,
-
- _("_Vertical:"), bvals.vertical, yres,
- 0, 8 * MAX (drawable->width, drawable->height),
- 0, 0);
-
- gtk_container_set_border_width (GTK_CONTAINER (size), 6);
- gtk_container_add (GTK_CONTAINER (frame), size);
- gtk_widget_show (size);
-
- gimp_size_entry_set_pixel_digits (GIMP_SIZE_ENTRY (size), 1);
-
- /* FIXME: Shouldn't need two signal connections here,
- gimp_coordinates_new() seems to be severily broken. */
- g_signal_connect_swapped (size, "value-changed",
- G_CALLBACK (gimp_preview_invalidate),
- preview);
- g_signal_connect_swapped (size, "refval-changed",
- G_CALLBACK (gimp_preview_invalidate),
- preview);
-
- g_signal_connect (preview, "invalidated",
- G_CALLBACK (update_preview),
- size);
-
- frame = gimp_int_radio_group_new (TRUE, _("Blur Method"),
- G_CALLBACK (gimp_radio_button_update),
- &bvals.method, bvals.method,
-
- _("_IIR"), BLUR_IIR, &button,
- _("_RLE"), BLUR_RLE, NULL,
-
- NULL);
-
- g_signal_connect_swapped (button, "toggled",
- G_CALLBACK (gimp_preview_invalidate),
- preview);
-
- gtk_box_pack_start (GTK_BOX (hbox), frame, FALSE, FALSE, 0);
- gtk_widget_show (frame);
-
- gtk_widget_show (dialog);
-
- run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
-
- if (run)
- {
- bvals.horizontal = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (size), 0);
- bvals.vertical = gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (size), 1);
- }
-
- gtk_widget_destroy (dialog);
-
- return run;
-}
-
-static void
-update_preview (GtkWidget *preview,
- GtkWidget *size)
-{
- gauss (gimp_drawable_preview_get_drawable (GIMP_DRAWABLE_PREVIEW (preview)),
- gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (size), 0),
- gimp_size_entry_get_refval (GIMP_SIZE_ENTRY (size), 1),
- bvals.method,
- preview);
-}
-
-/* Convert from separated to premultiplied alpha, on a single scan line. */
-static void
-multiply_alpha (guchar *buf,
- gint width,
- gint bytes)
-{
- gint i, j;
-
- for (i = 0; i < width; i++, buf += bytes)
- {
- gdouble alpha = buf[bytes - 1] * (1.0 / 255.0);
-
- for (j = 0; j < bytes - 1; j++)
- buf[j] = ROUND (buf[j] * alpha);
- }
-}
-
-/* Convert from premultiplied to separated alpha, on a single scan line. */
-static void
-separate_alpha (guchar *buf,
- gint width,
- gint bytes)
-{
- gint i, j;
-
- for (i = 0; i < width; i++, buf += bytes)
- {
- guchar alpha = buf[bytes - 1];
-
- switch (alpha)
- {
- case 0:
- case 255:
- break;
-
- default:
- {
- gdouble recip_alpha = 255.0 / alpha;
-
- for (j = 0; j < bytes - 1; j++)
- {
- gint new_val = ROUND (buf[j] * recip_alpha);
-
- buf[j] = MIN (255, new_val);
- }
- }
- break;
- }
- }
-}
-
-/*
- * run_length_encode (src, rle, pix, dist, width, border, pack);
- *
- * Copy 'width' 8bit pixels from 'src' to 'pix' and extend both sides
- * by 'border' pixels so 'pix[]' is filled from '-border' to 'width+border-1'.
- *
- * 'dist' is the distance between the pixels in 'src'.
- *
- * If 'pack' is TRUE, then 'rle' is filled with a run-length encoding
- * of the pixels. In plain english, that means that rle[i] gives the
- * number of times the same pixel is found pix[i], pix[i+1], ... A
- * standalone pixel has a rle value of 1.
- *
- * The function returns the number of times 2 identical consecutive pixels
- * were found.
- *
- * Note: The function must be inlined to insure that all tests on
- * 'pack' are efficiently resolved by the compiler (they are in
- * the critical loop). As a consequence, the function should
- * only be called with known constant value for 'pack'. In the
- * current implementation, 'pack' is always TRUE but it might be
- * more efficient to have an 'adaptive' algorithm that switches
- * to FALSE when the run-length is innefficient.
- */
-static inline gint
-run_length_encode (const guchar *src,
- gint *rle,
- gint *pix,
- gint dist, /* distance between 2 src pixels */
- gint width,
- gint border,
- gboolean pack)
-{
- gint last;
- gint count = 0;
- gint i = width;
- gint same = 0;
-
- src += dist * (width - 1);
-
- if (pack)
- rle += width + border - 1;
-
- pix += width + border - 1;
-
- last = *src;
- count = 0;
-
- /* the 'end' border */
- for (i = 0; i < border; i++)
- {
- count++;
- *pix-- = last;
-
- if (pack)
- *rle-- = count;
- }
-
- /* the real pixels */
- for (i = 0; i < width; i++)
- {
- gint c = *src;
- src -= dist;
-
- if (pack && c==last)
- {
- count++;
- *pix-- = last;
- *rle-- = count;
- same++;
- }
- else
- {
- count = 1;
- last = c;
- *pix-- = last;
-
- if (pack)
- *rle-- = count;
- }
- }
-
- /* the start pixels */
- for (i = 0; i < border; i++)
- {
- count++;
- *pix-- = last;
-
- if (pack)
- *rle-- = count;
- }
-
- return same;
-}
-
-
-static void
-do_encoded_lre (const gint *enc,
- const gint *src,
- guchar *dest,
- gint width,
- gint length,
- gint dist,
- const gint *curve,
- gint ctotal,
- const gint *csum)
-{
- gint col;
-
- for (col = 0; col < width; col++, dest += dist)
- {
- const gint *rpt;
- const gint *pix;
- gint nb;
- gint s1;
- gint i;
- gint val = ctotal / 2;
- gint start = - length;
-
- rpt = &enc[col + start];
- pix = &src[col + start];
-
- s1 = csum[start];
- nb = rpt[0];
- i = start + nb;
-
- while (i <= length)
- {
- gint s2 = csum[i];
-
- val += pix[0] * (s2-s1);
- s1 = s2;
- rpt = &rpt[nb];
- pix = &pix[nb];
- nb = rpt[0];
- i += nb;
- }
-
- val += pix[0] * (csum[length] - s1);
-
- val = val / ctotal;
- *dest = MIN (val, 255);
- }
-}
-
-static void
-do_full_lre (const gint *src,
- guchar *dest,
- gint width,
- gint length,
- gint dist,
- const gint *curve,
- gint ctotal)
-{
- gint col;
-
- for (col = 0; col < width; col++, dest += dist)
- {
- const gint *x1;
- const gint *x2;
- const gint *c = &curve[0];
- gint i;
- gint val = ctotal / 2;
-
- x1 = x2 = &src[col];
-
- /* The central point is a special case since it should only be
- * processed ONCE
- */
-
- val += x1[0] * c[0];
-
- c += 1;
- x1 += 1;
- x2 -= 1;
- i = length;
-
- /* Processing multiple points in a single iteration should be
- * faster but is not strictly required.
- * Some precise benchmarking will be needed to figure out
- * if this is really interesting.
- */
- while (i >= 8)
- {
- val += (x1[0] + x2[-0]) * c[0];
- val += (x1[1] + x2[-1]) * c[1];
- val += (x1[2] + x2[-2]) * c[2];
- val += (x1[3] + x2[-3]) * c[3];
- val += (x1[4] + x2[-4]) * c[4];
- val += (x1[5] + x2[-5]) * c[5];
- val += (x1[6] + x2[-6]) * c[6];
- val += (x1[7] + x2[-7]) * c[7];
-
- c += 8;
- x1 += 8;
- x2 -= 8;
- i -= 8;
- }
-
- while (i >= 4)
- {
- val += (x1[0] + x2[-0]) * c[0];
- val += (x1[1] + x2[-1]) * c[1];
- val += (x1[2] + x2[-2]) * c[2];
- val += (x1[3] + x2[-3]) * c[3];
- c += 4;
- x1 += 4;
- x2 -= 4;
- i -= 4;
- }
-
- /* Only that final loop is strictly required */
-
- while (i >= 1)
- {
- /* process the pixels at the distance i before and after the
- * central point. They must have the same coefficient
- */
- val += (x1[0] + x2[-0]) * c[0];
- c += 1;
- x1 += 1;
- x2 -= 1;
- i -= 1;
- }
-
- val = val / ctotal;
- *dest = MIN (val, 255);
- }
-}
-
-static void
-gauss_iir (GimpDrawable *drawable,
- gdouble horz,
- gdouble vert,
- BlurMethod method,
- guchar *preview_buffer,
- gint x1,
- gint y1,
- gint width,
- gint height)
-{
- GimpPixelRgn src_rgn, dest_rgn;
- gint bytes;
- gint has_alpha;
- guchar *dest;
- guchar *src, *sp_p, *sp_m;
- gdouble n_p[5], n_m[5];
- gdouble d_p[5], d_m[5];
- gdouble bd_p[5], bd_m[5];
- gdouble *val_p = NULL;
- gdouble *val_m = NULL;
- gdouble *vp, *vm;
- gint i, j;
- gint row, col, b;
- gint terms;
- gdouble progress, max_progress;
- gint initial_p[4];
- gint initial_m[4];
- gdouble std_dev;
- gboolean direct;
- gint progress_step;
-
- direct = (preview_buffer == NULL);
-
- bytes = drawable->bpp;
- has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
-
- val_p = g_new (gdouble, MAX (width, height) * bytes);
- val_m = g_new (gdouble, MAX (width, height) * bytes);
-
- src = g_new (guchar, MAX (width, height) * bytes);
- dest = g_new (guchar, MAX (width, height) * bytes);
-
- gimp_pixel_rgn_init (&src_rgn,
- drawable, 0, 0, drawable->width, drawable->height,
- FALSE, FALSE);
- if (direct)
- {
- gimp_pixel_rgn_init (&dest_rgn,
- drawable, 0, 0, drawable->width, drawable->height,
- TRUE, TRUE);
- }
-
-
- progress = 0.0;
- max_progress = (horz <= 0.0) ? 0 : width * height * horz;
- max_progress += (vert <= 0.0) ? 0 : width * height * vert;
-
-
- /* First the vertical pass */
- if (vert > 0.0)
- {
- vert = fabs (vert) + 1.0;
- std_dev = sqrt (-(vert * vert) / (2 * log (1.0 / 255.0)));
-
- /* We do not want too many progress updates because they
- * can slow down the processing significantly for very
- * large images
- */
- progress_step = width / 16;
-
- if (progress_step < 5)
- progress_step = 5;
-
- /* derive the constants for calculating the gaussian
- * from the std dev
- */
-
- find_iir_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);
-
- for (col = 0; col < width; col++)
- {
- memset (val_p, 0, height * bytes * sizeof (gdouble));
- memset (val_m, 0, height * bytes * sizeof (gdouble));
-
- gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, height);
-
- if (has_alpha)
- multiply_alpha (src, height, bytes);
-
- sp_p = src;
- sp_m = src + (height - 1) * bytes;
- vp = val_p;
- vm = val_m + (height - 1) * bytes;
-
- /* Set up the first vals */
- for (i = 0; i < bytes; i++)
- {
- initial_p[i] = sp_p[i];
- initial_m[i] = sp_m[i];
- }
-
- for (row = 0; row < height; row++)
- {
- gdouble *vpptr, *vmptr;
- terms = (row < 4) ? row : 4;
-
- for (b = 0; b < bytes; b++)
- {
- vpptr = vp + b; vmptr = vm + b;
- for (i = 0; i <= terms; i++)
- {
- *vpptr += n_p[i] * sp_p[(-i * bytes) + b] - d_p[i] * vp[(-i * bytes) + b];
- *vmptr += n_m[i] * sp_m[(i * bytes) + b] - d_m[i] * vm[(i * bytes) + b];
- }
- for (j = i; j <= 4; j++)
- {
- *vpptr += (n_p[j] - bd_p[j]) * initial_p[b];
- *vmptr += (n_m[j] - bd_m[j]) * initial_m[b];
- }
- }
-
- sp_p += bytes;
- sp_m -= bytes;
- vp += bytes;
- vm -= bytes;
- }
-
- transfer_pixels (val_p, val_m, dest, bytes, height);
-
-
- if (has_alpha)
- separate_alpha (dest, height, bytes);
-
- if (direct)
- {
- gimp_pixel_rgn_set_col(&dest_rgn, dest, col + x1, y1, height);
-
- progress += height * vert;
-
- if ((col % progress_step) == 0)
- gimp_progress_update (progress / max_progress);
- }
- else
- {
- for (row = 0; row < height; row++)
- memcpy (preview_buffer + (row * width + col) * bytes,
- dest + row * bytes,
- bytes);
- }
- }
-
- /* prepare for the horizontal pass */
- gimp_pixel_rgn_init (&src_rgn,
- drawable,
- 0, 0,
- drawable->width, drawable->height,
- FALSE, TRUE);
- }
- else if (!direct)
- {
- gimp_pixel_rgn_get_rect (&src_rgn,
- preview_buffer,
- x1, y1,
- width, height);
- }
-
- /* Now the horizontal pass */
- if (horz > 0.0)
- {
-
- /* We do not want too many progress updates because they
- * can slow down the processing significantly for very
- * large images
- */
- progress_step = height / 16;
-
- if (progress_step < 5)
- progress_step = 5;
-
- horz = fabs (horz) + 1.0;
-
- if (horz != vert)
- {
- std_dev = sqrt (-(horz * horz) / (2 * log (1.0 / 255.0)));
-
- /* derive the constants for calculating the gaussian
- * from the std dev
- */
- find_iir_constants (n_p, n_m, d_p, d_m, bd_p, bd_m, std_dev);
-
- }
-
-
- for (row = 0; row < height; row++)
- {
-
- memset (val_p, 0, width * bytes * sizeof (gdouble));
- memset (val_m, 0, width * bytes * sizeof (gdouble));
-
- if (direct)
- {
- gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, width);
- }
- else
- {
- memcpy (src,
- preview_buffer + row * width * bytes,
- width * bytes);
- }
-
-
- if (has_alpha)
- multiply_alpha (src, width, bytes);
-
-
- sp_p = src;
- sp_m = src + (width - 1) * bytes;
- vp = val_p;
- vm = val_m + (width - 1) * bytes;
-
- /* Set up the first vals */
- for (i = 0; i < bytes; i++)
- {
- initial_p[i] = sp_p[i];
- initial_m[i] = sp_m[i];
- }
-
- for (col = 0; col < width; col++)
- {
- gdouble *vpptr, *vmptr;
-
- terms = (col < 4) ? col : 4;
-
- for (b = 0; b < bytes; b++)
- {
- vpptr = vp + b; vmptr = vm + b;
-
- for (i = 0; i <= terms; i++)
- {
- *vpptr += n_p[i] * sp_p[(-i * bytes) + b] -
- d_p[i] * vp[(-i * bytes) + b];
- *vmptr += n_m[i] * sp_m[(i * bytes) + b] -
- d_m[i] * vm[(i * bytes) + b];
- }
- for (j = i; j <= 4; j++)
- {
- *vpptr += (n_p[j] - bd_p[j]) * initial_p[b];
- *vmptr += (n_m[j] - bd_m[j]) * initial_m[b];
- }
- }
-
- sp_p += bytes;
- sp_m -= bytes;
- vp += bytes;
- vm -= bytes;
- }
-
- transfer_pixels (val_p, val_m, dest, bytes, width);
-
- if (has_alpha)
- separate_alpha (dest, width, bytes);
-
- if (direct)
- {
- gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, width);
-
- progress += width * horz;
-
- if ((row % progress_step) == 0)
- gimp_progress_update (progress / max_progress);
- }
- else
- {
- memcpy (preview_buffer + row * width * bytes,
- dest,
- width * bytes);
- }
- }
- }
-
- /* free up buffers */
-
- g_free (val_p);
- g_free (val_m);
-
- g_free (src);
- g_free (dest);
-}
-
-
-static void
-gauss_rle (GimpDrawable *drawable,
- gdouble horz,
- gdouble vert,
- BlurMethod method,
- guchar *preview_buffer,
- gint x1,
- gint y1,
- gint width,
- gint height)
-{
- GimpPixelRgn src_rgn, dest_rgn;
- gint bytes;
- gboolean has_alpha;
- guchar *dest;
- guchar *src;
- gint row, col, b;
- gdouble progress, max_progress;
- gdouble std_dev;
- gint total = 1;
- gint *curve = NULL;
- gint *sum = NULL;
- gint length;
- gboolean direct;
- gint progress_step;
-
- direct = (preview_buffer == NULL);
-
- bytes = drawable->bpp;
- has_alpha = gimp_drawable_has_alpha (drawable->drawable_id);
-
- src = g_new (guchar, MAX (width, height) * bytes);
- dest = g_new (guchar, MAX (width, height) * bytes);
-
- gimp_pixel_rgn_init (&src_rgn,
- drawable, 0, 0, drawable->width, drawable->height,
- FALSE, FALSE);
-
- if (direct)
- gimp_pixel_rgn_init (&dest_rgn,
- drawable, 0, 0, drawable->width, drawable->height,
- TRUE, TRUE);
-
- progress = 0.0;
- max_progress = (horz <= 0.0) ? 0 : width * height * horz;
- max_progress += (vert <= 0.0) ? 0 : width * height * vert;
-
-
- /* First the vertical pass */
- if (vert > 0.0)
- {
- gint * rle = NULL;
- gint * pix = NULL;
-
- vert = fabs (vert) + 1.0;
- std_dev = sqrt (-(vert * vert) / (2 * log (1.0 / 255.0)));
-
- /* Insure that we do not have too many progress updates for
- * images with a lot of rows or columns
- */
- progress_step = width / 16;
-
- if (progress_step < 5)
- progress_step = 5;
-
- make_rle_curve (std_dev, &curve, &length, &sum, &total);
-
- rle = g_new (gint, height + 2 * length);
- rle += length; /* rle[] extends from -length to height+length-1 */
-
- pix = g_new (gint, height + 2 * length);
- pix += length; /* pix[] extends from -length to height+length-1 */
-
- for (col = 0; col < width; col++)
- {
-
- gimp_pixel_rgn_get_col (&src_rgn, src, col + x1, y1, height);
-
- if (has_alpha)
- multiply_alpha (src, height, bytes);
-
- for (b = 0; b < bytes; b++)
- {
- gint same = run_length_encode (src + b, rle, pix, bytes,
- height, length, TRUE);
-
- if (same > (3 * height) / 4)
- {
- /* encoded_rle is only fastest if there are a lot of
- * repeating pixels
- */
- do_encoded_lre (rle, pix, dest + b, height, length, bytes,
- curve, total, sum);
- }
- else
- {
- /* else a full but more simple algorithm is better */
- do_full_lre (pix, dest + b, height, length, bytes,
- curve, total);
- }
- }
-
- if (has_alpha)
- separate_alpha (dest, height, bytes);
-
- if (direct)
- {
- gimp_pixel_rgn_set_col (&dest_rgn, dest, col + x1, y1, height);
-
- progress += height * vert;
-
- if ((col % progress_step) == 0)
- gimp_progress_update (progress / max_progress);
- }
- else
- {
- for (row = 0; row < height; row++)
- memcpy (preview_buffer + (row * width + col) * bytes,
- dest + row * bytes,
- bytes);
- }
-
- }
-
-
- g_free (rle - length);
- g_free (pix - length);
-
- /* prepare for the horizontal pass */
- gimp_pixel_rgn_init (&src_rgn,
- drawable, 0, 0, drawable->width, drawable->height,
- FALSE, TRUE);
- }
- else if (!direct)
- {
- gimp_pixel_rgn_get_rect (&src_rgn,
- preview_buffer, x1, y1, width, height);
- }
-
- /* Now the horizontal pass */
- if (horz > 0.0)
- {
- gint * rle = NULL;
- gint * pix = NULL;
-
- /* Insure that we do not have too many progress updates for
- * images with a lot of rows or columns
- */
- progress_step = height / 16;
-
- if (progress_step < 5) {
- progress_step = 5;
- }
-
- horz = fabs (horz) + 1.0;
-
- /* euse the same curve if possible else recompute a new one */
- if (horz != vert)
- {
-
- std_dev = sqrt (-(horz * horz) / (2 * log (1.0 / 255.0)));
-
- if (curve != NULL) {
- free_rle_curve(curve, length, sum);
- }
-
- make_rle_curve(std_dev, &curve, &length, &sum, &total);
-
- }
-
-
- rle = g_new (gint, width+2*length);
- rle += length; /* so rle[] extends from -width to width+length-1 */
-
- pix = g_new (gint, width+2*length);
- pix += length; /* so pix[] extends from -width to width+length-1 */
-
- for (row = 0; row < height; row++)
- {
- if (direct)
- {
- gimp_pixel_rgn_get_row (&src_rgn, src, x1, row + y1, width);
- }
- else
- {
- memcpy (src,
- preview_buffer + row * width * bytes,
- width * bytes);
- }
-
- if (has_alpha)
- multiply_alpha (src, width, bytes);
-
- for (b = 0; b < bytes; b++)
- {
- gint same = run_length_encode (src + b, rle, pix, bytes,
- width, length, TRUE);
-
- if (same > (3 * width) / 4)
- {
- /* encoded_rle is only fastest if there are a lot of
- * repeating pixels
- */
- do_encoded_lre (rle, pix, dest + b, width, length, bytes,
- curve, total, sum);
- }
- else
- {
- /* else a full but more simple algorithm is better */
- do_full_lre (pix, dest + b, width, length, bytes,
- curve, total);
- }
- }
-
-
- if (has_alpha)
- separate_alpha (dest, width, bytes);
-
- if (direct)
- {
- gimp_pixel_rgn_set_row (&dest_rgn, dest, x1, row + y1, width);
-
- progress += width * horz;
-
- if ((row % progress_step) == 0)
- gimp_progress_update (progress / max_progress);
- }
- else
- {
- memcpy (preview_buffer + row * width * bytes,
- dest,
- width * bytes);
- }
- }
-
- g_free (rle - length);
- g_free (pix - length);
- }
-
- if (curve)
- free_rle_curve (curve, length, sum);
-
- g_free (src);
- g_free (dest);
-}
-
-
-static void
-gauss (GimpDrawable *drawable,
- gdouble horz,
- gdouble vert,
- BlurMethod method,
- GtkWidget *preview)
-{
-
- gint x, y;
- gint width, height;
- guchar *preview_buffer = NULL;
-
- /*
- * IIR goes wrong if the blur radius is less than 1, so we silently
- * switch to RLE in this case. See bug #315953
- */
- if (horz <= 1.0 || vert <= 1.0)
- method = BLUR_RLE;
-
- if (horz <= 0.0 && vert <= 0.0)
- {
- if (preview)
- gimp_preview_draw (GIMP_PREVIEW (preview));
- return;
- }
-
- if (preview)
- {
- gimp_preview_get_position (GIMP_PREVIEW (preview), &x, &y);
- gimp_preview_get_size (GIMP_PREVIEW (preview), &width, &height);
-
- preview_buffer = g_new (guchar, width * height * drawable->bpp);
-
- }
- else if (gimp_drawable_mask_intersect (drawable->drawable_id,
- &x, &y, &width, &height))
- { /* With a selection, extend the input area of the amount required */
- gint hor_extra = method == BLUR_IIR ? 4 : 1 + ceil (horz);
- gint ver_extra = method == BLUR_IIR ? 4 : 1 + ceil (vert);
- gint x2 = x + width;
- gint y2 = y + height;
-
- x = MAX (x - hor_extra, 0);
- y = MAX (y - ver_extra, 0);
- width = MIN (x2 + hor_extra, drawable->width) - x;
- height = MIN (y2 + ver_extra, drawable->height) - y;
- }
- else
- {
- return;
- }
-
-
- if (method == BLUR_IIR)
- gauss_iir (drawable,
- horz, vert, method, preview_buffer, x, y, width, height);
- else
- gauss_rle (drawable,
- horz, vert, method, preview_buffer, x, y, width, height);
-
- if (preview)
- {
- gimp_preview_draw_buffer (GIMP_PREVIEW (preview),
- preview_buffer, width * drawable->bpp);
- g_free (preview_buffer);
- }
- else
- {
- gimp_progress_update (1.0);
- /* merge the shadow, update the drawable */
- gimp_drawable_flush (drawable);
- gimp_drawable_merge_shadow (drawable->drawable_id, TRUE);
- gimp_drawable_update (drawable->drawable_id, x, y, width, height);
- }
-}
-
-static void
-transfer_pixels (const gdouble *src1,
- const gdouble *src2,
- guchar *dest,
- gint bytes,
- gint width)
-{
- gint b;
- gint bend = bytes * width;
- gdouble sum;
-
- for (b = 0; b < bend; b++)
- {
- sum = *src1++ + *src2++;
-
- if (sum > 255)
- sum = 255;
- else if (sum < 0)
- sum = 0;
-
- *dest++ = (guchar) sum;
- }
-}
-
-static void
-find_iir_constants (gdouble *n_p,
- gdouble *n_m,
- gdouble *d_p,
- gdouble *d_m,
- gdouble *bd_p,
- gdouble *bd_m,
- gdouble std_dev)
-{
- /* The constants used in the implemenation of a casual sequence
- * using a 4th order approximation of the gaussian operator
- */
-
- const gdouble div = sqrt (2 * G_PI) * std_dev;
- const gdouble x0 = -1.783 / std_dev;
- const gdouble x1 = -1.723 / std_dev;
- const gdouble x2 = 0.6318 / std_dev;
- const gdouble x3 = 1.997 / std_dev;
- const gdouble x4 = 1.6803 / div;
- const gdouble x5 = 3.735 / div;
- const gdouble x6 = -0.6803 / div;
- const gdouble x7 = -0.2598 / div;
- gint i;
-
- n_p [0] = x4 + x6;
- n_p [1] = (exp(x1)*(x7*sin(x3)-(x6+2*x4)*cos(x3)) +
- exp(x0)*(x5*sin(x2) - (2*x6+x4)*cos (x2)));
- n_p [2] = (2 * exp(x0+x1) *
- ((x4+x6)*cos(x3)*cos(x2) - x5*cos(x3)*sin(x2) -
- x7*cos(x2)*sin(x3)) +
- x6*exp(2*x0) + x4*exp(2*x1));
- n_p [3] = (exp(x1+2*x0) * (x7*sin(x3) - x6*cos(x3)) +
- exp(x0+2*x1) * (x5*sin(x2) - x4*cos(x2)));
- n_p [4] = 0.0;
-
- d_p [0] = 0.0;
- d_p [1] = -2 * exp(x1) * cos(x3) - 2 * exp(x0) * cos (x2);
- d_p [2] = 4 * cos(x3) * cos(x2) * exp(x0 + x1) + exp(2 * x1) + exp(2 * x0);
- d_p [3] = -2 * cos(x2) * exp(x0 + 2*x1) - 2*cos(x3) * exp(x1 + 2*x0);
- d_p [4] = exp(2*x0 + 2*x1);
-
- for (i = 0; i <= 4; i++)
- d_m[i] = d_p[i];
-
- n_m[0] = 0.0;
-
- for (i = 1; i <= 4; i++)
- n_m[i] = n_p[i] - d_p[i] * n_p[0];
-
- {
- gdouble sum_n_p, sum_n_m, sum_d;
- gdouble a, b;
-
- sum_n_p = 0.0;
- sum_n_m = 0.0;
- sum_d = 0.0;
-
- for (i = 0; i <= 4; i++)
- {
- sum_n_p += n_p[i];
- sum_n_m += n_m[i];
- sum_d += d_p[i];
- }
-
- a = sum_n_p / (1.0 + sum_d);
- b = sum_n_m / (1.0 + sum_d);
-
- for (i = 0; i <= 4; i++)
- {
- bd_p[i] = d_p[i] * a;
- bd_m[i] = d_m[i] * b;
- }
- }
-}
-
-
-/*
- * make_rle_curve(sigma, &curve, &length, &sum, &total)
- *
- *
- * Fill the Gauss curve.
- *
- * g(r) = exp (- r^2 / (2 * sigma^2))
- * r = sqrt (x^2 + y ^2)
- *
- * o length is filled with the length the curve (in both directions)
- * o curve[-length .. length] is allocated and filled with the
- * (scaled) gauss curve.
- * o sum[-length .. length] is allocated and filled with the 'summed' curve.
- * o total is filled with the sum of all elements in the curve (for
- * normalization).
- *
- *
- *
- */
-
-
-static void
-make_rle_curve (gdouble sigma,
- gint **p_curve,
- gint *p_length,
- gint **p_sum,
- gint *p_total)
-{
- const gdouble sigma2 = 2 * sigma * sigma;
- const gdouble l = sqrt (-sigma2 * log (1.0 / 255.0));
- gint temp;
- gint i, n;
- gint length;
- gint *sum;
- gint *curve;
-
- n = ceil (l) * 2;
- if ((n % 2) == 0)
- n += 1;
-
- curve = g_new (gint, n);
-
- length = n / 2;
- curve += length; /* 'center' the curve[] */
- curve[0] = 255;
-
- for (i = 1; i <= length; i++)
- {
- temp = (gint) (exp (- (i * i) / sigma2) * 255);
- curve[-i] = temp;
- curve[i] = temp;
- }
-
- sum = g_new (gint, 2 * length + 1);
-
- sum[0] = 0;
- for (i = 1; i <= length*2; i++)
- {
- sum[i] = curve[i-length-1] + sum[i-1];
- }
-
- sum += length; /* 'center' the sum[] */
-
- *p_total = sum[length] - sum[-length];
- *p_curve = curve;
- *p_sum = sum;
- *p_length = length;
-
-}
-
-/*
- * Free a curve previously allocated with make_rle_curve
- */
-static void
-free_rle_curve (gint *curve,
- gint length,
- gint *sum)
-{
- g_free (sum - length);
- g_free (curve - length);
-}
diff --git a/plug-ins/common/gimprc.common b/plug-ins/common/gimprc.common
index 573cc895fe..d95a83f30a 100644
--- a/plug-ins/common/gimprc.common
+++ b/plug-ins/common/gimprc.common
@@ -3,7 +3,6 @@ animation_optimize_RC = animation-optimize.rc.o
animation_play_RC = animation-play.rc.o
blinds_RC = blinds.rc.o
blur_RC = blur.rc.o
-blur_gauss_RC = blur-gauss.rc.o
blur_gauss_selective_RC = blur-gauss-selective.rc.o
border_average_RC = border-average.rc.o
bump_map_RC = bump-map.rc.o
diff --git a/plug-ins/common/plugin-defs.pl b/plug-ins/common/plugin-defs.pl
index 3fd4c27dd8..3e1717429b 100644
--- a/plug-ins/common/plugin-defs.pl
+++ b/plug-ins/common/plugin-defs.pl
@@ -4,7 +4,6 @@
'animation-play' => { ui => 1, gegl => 1 },
'blinds' => { ui => 1 },
'blur' => {},
- 'blur-gauss' => { ui => 1 },
'blur-gauss-selective' => { ui => 1, cflags => 'MMX_EXTRA_CFLAGS' },
'border-average' => { ui => 1, gegl => 1 },
'bump-map' => { ui => 1 },
diff --git a/tools/pdbgen/pdb/plug_in_compat.pdb b/tools/pdbgen/pdb/plug_in_compat.pdb
index db17a4477a..8e1f54f5e2 100644
--- a/tools/pdbgen/pdb/plug_in_compat.pdb
+++ b/tools/pdbgen/pdb/plug_in_compat.pdb
@@ -651,6 +651,194 @@ CODE
);
}
+sub plug_in_gauss {
+ $blurb = 'Simplest, most commonly used way of blurring';
+
+ $help = <<'HELP';
+Applies a gaussian blur to the drawable, with specified radius of affect.
+The standard deviation of the normal distribution used to modify pixel
+values is calculated based on the supplied radius.
+Horizontal and vertical blurring can be independently invoked by specifying
+only one to run. The 'method' parameter is ignored.
+HELP
+
+ &std_pdb_compat('gegl:gaussian-blur');
+ $date = '2014';
+
+ @inargs = (
+ { name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
+ desc => 'The run mode' },
+ { name => 'image', type => 'image', dead => 1,
+ desc => 'Input image (unused)' },
+ { name => 'drawable', type => 'drawable',
+ desc => 'Input drawable' },
+ { name => 'horizontal', type => '0.0 <= float <= 500.0',
+ desc => 'Horizontal radius of gaussian blur (in pixels' },
+ { name => 'vertical', type => '0.0 <= float <= 500.0',
+ desc => 'Vertical radius of gaussian blur (in pixels' },
+ { name => 'method', type => '0 <= int32 <= 1', dead => 1,
+ desc => 'Blur method { IIR (0), RLE (1) }' }
+ );
+
+ %invoke = (
+ code => <<'CODE'
+{
+ success = gaussian_blur (drawable, horizontal, vertical, progress, error);
+}
+CODE
+ );
+}
+
+sub plug_in_gauss_iir {
+ $blurb = 'Apply a gaussian blur';
+
+ $help = <<'HELP';
+Applies a gaussian blur to the drawable, with specified radius of affect.
+The standard deviation of the normal distribution used to modify pixel
+values is calculated based on the supplied radius. Horizontal and vertical
+blurring can be independently invoked by specifying only one to run.
+HELP
+
+ &std_pdb_compat('gegl:gaussian-blur');
+ $date = '2014';
+
+ @inargs = (
+ { name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
+ desc => 'The run mode' },
+ { name => 'image', type => 'image', dead => 1,
+ desc => 'Input image (unused)' },
+ { name => 'drawable', type => 'drawable',
+ desc => 'Input drawable' },
+ { name => 'radius', type => '0.0 <= float <= 500.0',
+ desc => 'Radius of gaussian blur (in pixels' },
+ { name => 'horizontal', type => 'boolean',
+ desc => 'Blur in horizontal direction' },
+ { name => 'vertical', type => 'boolean',
+ desc => 'Blur in vertical direction' }
+ );
+
+ %invoke = (
+ code => <<'CODE'
+{
+ success = gaussian_blur (drawable,
+ horizontal ? radius : 0.0,
+ vertical ? radius : 0.0,
+ progress, error);
+}
+CODE
+ );
+}
+
+sub plug_in_gauss_iir2 {
+ $blurb = 'Apply a gaussian blur';
+
+ $help = <<'HELP';
+Applies a gaussian blur to the drawable, with specified radius of affect.
+The standard deviation of the normal distribution used to modify pixel
+values is calculated based on the supplied radius. Horizontal and vertical
+blurring can be independently invoked by specifying only one to run.
+HELP
+
+ &std_pdb_compat('gegl:gaussian-blur');
+ $date = '2014';
+
+ @inargs = (
+ { name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
+ desc => 'The run mode' },
+ { name => 'image', type => 'image', dead => 1,
+ desc => 'Input image (unused)' },
+ { name => 'drawable', type => 'drawable',
+ desc => 'Input drawable' },
+ { name => 'horizontal', type => '0.0 <= float <= 500.0',
+ desc => 'Horizontal radius of gaussian blur (in pixels' },
+ { name => 'vertical', type => '0.0 <= float <= 500.0',
+ desc => 'Vertical radius of gaussian blur (in pixels' },
+ );
+
+ %invoke = (
+ code => <<'CODE'
+{
+ success = gaussian_blur (drawable, horizontal, vertical, progress, error);
+}
+CODE
+ );
+}
+
+sub plug_in_gauss_rle {
+ $blurb = 'Apply a gaussian blur';
+
+ $help = <<'HELP';
+Applies a gaussian blur to the drawable, with specified radius of affect.
+The standard deviation of the normal distribution used to modify pixel
+values is calculated based on the supplied radius. Horizontal and vertical
+blurring can be independently invoked by specifying only one to run.
+HELP
+
+ &std_pdb_compat('gegl:gaussian-blur');
+ $date = '2014';
+
+ @inargs = (
+ { name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
+ desc => 'The run mode' },
+ { name => 'image', type => 'image', dead => 1,
+ desc => 'Input image (unused)' },
+ { name => 'drawable', type => 'drawable',
+ desc => 'Input drawable' },
+ { name => 'radius', type => '0.0 <= float <= 500.0',
+ desc => 'Radius of gaussian blur (in pixels' },
+ { name => 'horizontal', type => 'boolean',
+ desc => 'Blur in horizontal direction' },
+ { name => 'vertical', type => 'boolean',
+ desc => 'Blur in vertical direction' }
+ );
+
+ %invoke = (
+ code => <<'CODE'
+{
+ success = gaussian_blur (drawable,
+ horizontal ? radius : 0.0,
+ vertical ? radius : 0.0,
+ progress, error);
+}
+CODE
+ );
+}
+
+sub plug_in_gauss_rle2 {
+ $blurb = 'Apply a gaussian blur';
+
+ $help = <<'HELP';
+Applies a gaussian blur to the drawable, with specified radius of affect.
+The standard deviation of the normal distribution used to modify pixel
+values is calculated based on the supplied radius. Horizontal and vertical
+blurring can be independently invoked by specifying only one to run.
+HELP
+
+ &std_pdb_compat('gegl:gaussian-blur');
+ $date = '2014';
+
+ @inargs = (
+ { name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
+ desc => 'The run mode' },
+ { name => 'image', type => 'image', dead => 1,
+ desc => 'Input image (unused)' },
+ { name => 'drawable', type => 'drawable',
+ desc => 'Input drawable' },
+ { name => 'horizontal', type => '0.0 <= float <= 500.0',
+ desc => 'Horizontal radius of gaussian blur (in pixels' },
+ { name => 'vertical', type => '0.0 <= float <= 500.0',
+ desc => 'Vertical radius of gaussian blur (in pixels' },
+ );
+
+ %invoke = (
+ code => <<'CODE'
+{
+ success = gaussian_blur (drawable, horizontal, vertical, progress, error);
+}
+CODE
+ );
+}
+
sub plug_in_hsv_noise {
$blurb = 'Randomize hue, saturation and value independently';
@@ -1997,9 +2185,100 @@ CODE
);
}
+$extra{app}->{code} = <<'CODE';
+static GeglNode *
+wrap_in_gamma_cast (GeglNode *node,
+ GimpDrawable *drawable)
+{
+ if (! gimp_drawable_get_linear (drawable))
+ {
+ const Babl *drawable_format;
+ const Babl *cast_format;
+ GeglNode *new_node;
+ GeglNode *input;
+ GeglNode *output;
+ GeglNode *cast_before;
+ GeglNode *cast_after;
+
+ drawable_format = gimp_drawable_get_format (drawable);
+
+ cast_format =
+ gimp_babl_format (gimp_babl_format_get_base_type (drawable_format),
+ gimp_babl_precision (gimp_babl_format_get_component_type (drawable_format),
+ TRUE),
+ babl_format_has_alpha (drawable_format));
+
+ new_node = gegl_node_new ();
+
+ gegl_node_add_child (new_node, node);
+ g_object_unref (node);
+
+ input = gegl_node_get_input_proxy (new_node, "input");
+ output = gegl_node_get_output_proxy (new_node, "output");
+
+ cast_before = gegl_node_new_child (new_node,
+ "operation", "gimp:cast-format",
+ "input-format", drawable_format,
+ "output-format", cast_format,
+ NULL);
+ cast_after = gegl_node_new_child (new_node,
+ "operation", "gimp:cast-format",
+ "input-format", cast_format,
+ "output-format", drawable_format,
+ NULL);
+
+ gegl_node_link_many (input,
+ cast_before,
+ node,
+ cast_after,
+ output,
+ NULL);
+
+ return new_node;
+ }
+ else
+ {
+ return node;
+ }
+}
+
+static gboolean
+gaussian_blur (GimpDrawable *drawable,
+ gdouble horizontal,
+ gdouble vertical,
+ GimpProgress *progress,
+ GError **error)
+{
+ 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;
+
+ node = gegl_node_new_child (NULL,
+ "operation", "gegl:gaussian-blur",
+ "std-dev-x", horizontal * 0.32,
+ "std-dev-y", vertical * 0.32,
+ NULL);
+
+ node = wrap_in_gamma_cast (node, drawable);
+
+ gimp_drawable_apply_operation (drawable, progress,
+ C_("undo-type", "Gaussian Blur"),
+ node);
+
+ g_object_unref (node);
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+CODE
@headers = qw("libgimpbase/gimpbase.h"
"libgimpmath/gimpmath.h"
+ "gegl/gimp-babl.h"
"gegl/gimp-gegl-utils.h"
"core/gimpcontext.h"
"core/gimpdrawable.h"
@@ -2022,6 +2301,11 @@ CODE
plug_in_colors_channel_mixer
plug_in_colortoalpha
plug_in_cubism
+ plug_in_gauss
+ plug_in_gauss_iir
+ plug_in_gauss_iir2
+ plug_in_gauss_rle
+ plug_in_gauss_rle2
plug_in_hsv_noise
plug_in_laplace
plug_in_lens_distortion