Several types functions were using the wording "float" historically to mean double-precision, e.g. the float array type (which was in fact a double array). Or the scanner function gimp_scanner_parse_float() was in fact returning a double value. What if we wanted someday to actually add float (usually this naming means in C the single-precision IEEE 754 floating point representation) support? How would we name this? Now technically it's not entirely wrong (a double is still a floating point). So I've been wondering if that is because maybe we never planned to have float and double precision may be good enough for all usage in a plug-in API (which doesn't have to be as generic so the higher precision is enough)? But how can we be sure? Also we already had some functions using the wording double (e.g. gimp_procedure_add_double_argument()), so let's just go the safe route and use the accurate wording. The additional change in PDB is internal, but there too, I was also finding very confusing that we were naming double-precision float as 'float' type. So I took the opportunity to update this. It doesn't change any signature. In fact the whole commit doesn't change any type or code logic, only naming, except for one bug fix in the middle which I encountered while renaming: in gimp_scanner_parse_deprecated_color(), I discovered a hidden bug in scanning (color-hsv*) values, which was mistakenly using a double type for an array of float.
5399 lines
176 KiB
Text
5399 lines
176 KiB
Text
# 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/>.
|
|
|
|
# "Perlized" from C source by Manish Singh <yosh@gimp.org>
|
|
|
|
|
|
# The declared ranges generate min/max in GParamSpecs
|
|
# and the min becomes the default in the GParamSpecs.
|
|
# A declared range must correspond with range declared in GEGL
|
|
# else args defaulted from min may generate out-of-range warnings.
|
|
|
|
sub plug_in_alienmap2 {
|
|
$blurb = 'Alter colors in various psychedelic ways';
|
|
|
|
$help = <<'HELP';
|
|
No help yet. Just try it and you'll see!
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:alien-map');
|
|
$date = '2013';
|
|
|
|
@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 => 'redfrequency', type => '0 <= double <= 20',
|
|
desc => 'Red/hue component frequency factor' },
|
|
{ name => 'redangle', type => '0 <= double <= 360',
|
|
desc => 'Red/hue component angle factor (0-360)' },
|
|
{ name => 'greenfrequency', type => '0 <= double <= 20',
|
|
desc => 'Green/saturation component frequency factor' },
|
|
{ name => 'greenangle', type => '0 <= double <= 360',
|
|
desc => 'Green/saturation component angle factor (0-360)' },
|
|
{ name => 'bluefrequency', type => '0 <= double <= 20',
|
|
desc => 'Blue/luminance component frequency factor' },
|
|
{ name => 'blueangle', type => '0 <= double <= 360',
|
|
desc => 'Blue/luminance component angle factor (0-360)' },
|
|
{ name => 'colormodel', type => '0 <= int32 <= 1',
|
|
desc => 'Color model { RGB-MODEL (0), HSL-MODEL (1) }' },
|
|
{ name => 'redmode', type => 'boolean',
|
|
desc => 'Red/hue application mode' },
|
|
{ name => 'greenmode', type => 'boolean',
|
|
desc => 'Green/saturation application mode' },
|
|
{ name => 'bluemode', type => 'boolean',
|
|
desc => 'Blue/luminance application mode' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:alien-map",
|
|
"color-model", (gint) colormodel,
|
|
"cpn-1-frequency", (gdouble) redfrequency,
|
|
"cpn-2-frequency", (gdouble) greenfrequency,
|
|
"cpn-3-frequency", (gdouble) bluefrequency,
|
|
"cpn-1-phaseshift", (gdouble) redangle,
|
|
"cpn-2-phaseshift", (gdouble) greenangle,
|
|
"cpn-3-phaseshift", (gdouble) blueangle,
|
|
"cpn-1-keep", (gboolean) !redmode,
|
|
"cpn-2-keep", (gboolean) !greenmode,
|
|
"cpn-3-keep", (gboolean) !bluemode,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Alien Map"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_antialias {
|
|
$blurb = 'Antialias using the Scale3X edge-extrapolation algorithm';
|
|
|
|
$help = <<'HELP';
|
|
No more help.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:antialias');
|
|
$date = '2013';
|
|
|
|
@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' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:antialias",
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Antialias"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_apply_canvas {
|
|
$blurb = 'Add a canvas texture to the image';
|
|
|
|
$help = <<'HELP';
|
|
This function applies a canvas texture map to the drawable.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:texturize-canvas');
|
|
$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 => 'direction', type => '0 <= int32 <= 3',
|
|
desc => 'Light direction (0 - 3)' },
|
|
{ name => 'depth', type => '1 <= int32 <= 50',
|
|
desc => 'Texture depth (1 - 50)' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:texturize-canvas",
|
|
"direction", direction,
|
|
"depth", depth,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Apply Canvas"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_applylens {
|
|
$blurb = 'Simulate an elliptical lens over the image';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in uses Snell's law to draw an ellipsoid lens over the image.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:apply-lens');
|
|
$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 => 'refraction', type => '1.0 <= double <= 100.0',
|
|
desc => 'Lens refraction index' },
|
|
{ name => 'keep_surroundings', type => 'boolean',
|
|
desc => 'Keep lens surroundings' },
|
|
{ name => 'set_background', type => 'boolean',
|
|
desc => 'Set lens surroundings to BG value' },
|
|
{ name => 'set_transparent', type => 'boolean', dead => 1,
|
|
desc => 'Set lens surroundings transparent' }
|
|
);
|
|
|
|
%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))
|
|
{
|
|
GeglColor *color;
|
|
GeglNode *node;
|
|
|
|
if (set_background)
|
|
{
|
|
color = gegl_color_duplicate (gimp_context_get_background (context));
|
|
}
|
|
else
|
|
{
|
|
color = gegl_color_new ("black");
|
|
gegl_color_set_rgba_with_space (color, 0.0, 0.0, 0.0, 0.0, NULL);
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:apply-lens",
|
|
"refraction-index", refraction,
|
|
"keep-surroundings", keep_surroundings,
|
|
"background-color", color,
|
|
NULL);
|
|
|
|
g_object_unref (color);
|
|
|
|
node = wrap_in_selection_bounds (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Apply Lens"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_autocrop {
|
|
$blurb = 'Remove empty borders from the image';
|
|
|
|
$help = <<'HELP';
|
|
Remove empty borders from the image.
|
|
HELP
|
|
|
|
&std_pdb_misc;
|
|
$date = '1997';
|
|
|
|
@inargs = (
|
|
{ name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
|
|
desc => 'The run mode' },
|
|
{ name => 'image', type => 'image',
|
|
desc => 'Input image)' },
|
|
{ name => 'drawable', type => 'drawable',
|
|
desc => 'Input drawable' }
|
|
);
|
|
|
|
%invoke = (
|
|
code => <<'CODE'
|
|
{
|
|
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
|
|
GIMP_PDB_ITEM_CONTENT, error))
|
|
{
|
|
gint x, y, width, height;
|
|
gint off_x, off_y;
|
|
|
|
gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable),
|
|
0, 0,
|
|
gimp_item_get_width (GIMP_ITEM (drawable)),
|
|
gimp_item_get_height (GIMP_ITEM (drawable)),
|
|
&x, &y, &width, &height);
|
|
|
|
gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
|
|
x += off_x;
|
|
y += off_y;
|
|
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE,
|
|
_("Autocrop image"));
|
|
|
|
if (x < 0 ||
|
|
y < 0 ||
|
|
x + width > gimp_image_get_width (image) ||
|
|
y + height > gimp_image_get_height (image))
|
|
{
|
|
/*
|
|
* partially outside the image area, we need to
|
|
* resize the image to be able to crop properly.
|
|
*/
|
|
gimp_image_resize (image, context, width, height, -x, -y, NULL);
|
|
|
|
x = y = 0;
|
|
}
|
|
|
|
gimp_image_crop (image, context, GIMP_FILL_TRANSPARENT,
|
|
x, y, width, height, TRUE);
|
|
|
|
gimp_image_undo_group_end (image);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_autocrop_layer {
|
|
$blurb = 'Crop the selected layers based on empty borders of the input drawable';
|
|
|
|
$help = <<'HELP';
|
|
Crop the selected layers of the input "image" based on empty borders of the input "drawable".
|
|
\n\nThe input drawable serves as a base for detecting cropping extents (transparency or background color), and is not necessarily among the cropped layers (the current selected layers).
|
|
HELP
|
|
|
|
&std_pdb_misc;
|
|
$date = '1997';
|
|
|
|
@inargs = (
|
|
{ name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
|
|
desc => 'The run mode' },
|
|
{ name => 'image', type => 'image',
|
|
desc => 'Input image)' },
|
|
{ name => 'drawable', type => 'drawable',
|
|
desc => 'Input drawable' }
|
|
);
|
|
|
|
%invoke = (
|
|
code => <<'CODE'
|
|
{
|
|
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
|
|
GIMP_PDB_ITEM_CONTENT, error))
|
|
{
|
|
GList *layers = gimp_image_get_selected_layers (image);
|
|
GList *iter;
|
|
gint x, y, width, height;
|
|
|
|
if (layers)
|
|
{
|
|
switch (gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable),
|
|
0, 0,
|
|
gimp_item_get_width (GIMP_ITEM (drawable)),
|
|
gimp_item_get_height (GIMP_ITEM (drawable)),
|
|
&x, &y, &width, &height))
|
|
{
|
|
case GIMP_AUTO_SHRINK_SHRINK:
|
|
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE,
|
|
_("Autocrop layer"));
|
|
|
|
for (iter = layers; iter; iter = iter->next)
|
|
gimp_item_resize (GIMP_ITEM (iter->data),
|
|
context, GIMP_FILL_TRANSPARENT,
|
|
width, height, -x, -y);
|
|
|
|
gimp_image_undo_group_end (image);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
success = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
success = FALSE;
|
|
}
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_autostretch_hsv {
|
|
$blurb = 'Stretch contrast to cover the maximum possible range';
|
|
|
|
$help = <<'HELP';
|
|
This simple plug-in does an automatic contrast stretch. For each
|
|
channel in the image, it finds the minimum and maximum values... it
|
|
uses those values to stretch the individual histograms to the full
|
|
contrast range. For some images it may do just what you want; for
|
|
others it may be total crap :). This version differs from Contrast
|
|
Autostretch in that it works in HSV space, and preserves hue.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:stretch-contrast-hsv');
|
|
$date = '2013';
|
|
|
|
@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' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:stretch-contrast-hsv",
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Stretch Contrast HSV"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_bump_map {
|
|
$blurb = 'Create an embossing effect using a bump map';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in uses the algorithm described by John Schlag,
|
|
"Fast Embossing Effects on Raster Image Data" in
|
|
Graphics GEMS IV (ISBN 0-12-336155-9).
|
|
It takes a drawable to be applied as a bump
|
|
map to another image and produces a nice embossing effect.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:bump-map');
|
|
$date = '2015';
|
|
|
|
@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 => 'bumpmap', type => 'drawable',
|
|
desc => 'Bump map drawable' },
|
|
{ name => 'azimuth', type => '0.0 <= double <= 360.0',
|
|
desc => 'Azimuth' },
|
|
{ name => 'elevation', type => '0.5 <= double <= 90.0',
|
|
desc => 'Elevation' },
|
|
{ name => 'depth', type => '1 <= int32 <= 65',
|
|
desc => 'Depth' },
|
|
{ name => 'xofs', type => 'int32',
|
|
desc => 'X offset' },
|
|
{ name => 'yofs', type => 'int32',
|
|
desc => 'Y offset' },
|
|
{ name => 'waterlevel', type => '0.0 <= double <= 1.0',
|
|
desc => 'Level that full transparency should represent' },
|
|
{ name => 'ambient', type => '0.0 <= double <= 1.0',
|
|
desc => 'Ambient lighting factor' },
|
|
{ name => 'compensate', type => 'boolean',
|
|
desc => 'Compensate for darkening' },
|
|
{ name => 'invert', type => 'boolean',
|
|
desc => 'Invert bumpmap' },
|
|
{ name => 'type', type => '0 <= int32 <= 3',
|
|
desc => 'Type of map { LINEAR (0), SPHERICAL (1), SINUSOIDAL (2) }' }
|
|
);
|
|
|
|
%invoke = (
|
|
code => <<'CODE'
|
|
{
|
|
success = bump_map (drawable,
|
|
bumpmap,
|
|
azimuth,
|
|
elevation,
|
|
depth,
|
|
xofs,
|
|
yofs,
|
|
waterlevel,
|
|
ambient,
|
|
compensate,
|
|
invert,
|
|
type,
|
|
FALSE,
|
|
progress,
|
|
error);
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_bump_map_tiled {
|
|
$blurb = 'Create an embossing effect using a tiled image as a bump map';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in uses the algorithm described by John Schlag,
|
|
"Fast Embossing Effects on Raster Image Data" in
|
|
Graphics GEMS IV (ISBN 0-12-336155-9).
|
|
It takes a drawable to be tiled and applied as a bump map
|
|
to another image and produces a nice embossing effect.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:bump-map');
|
|
$date = '2015';
|
|
|
|
@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 => 'bumpmap', type => 'drawable',
|
|
desc => 'Bump map drawable' },
|
|
{ name => 'azimuth', type => '0.0 <= double <= 360.0',
|
|
desc => 'Azimuth' },
|
|
{ name => 'elevation', type => '0.5 <= double <= 90.0',
|
|
desc => 'Elevation' },
|
|
{ name => 'depth', type => '1 <= int32 <= 65',
|
|
desc => 'Depth' },
|
|
{ name => 'xofs', type => 'int32',
|
|
desc => 'X offset' },
|
|
{ name => 'yofs', type => 'int32',
|
|
desc => 'Y offset' },
|
|
{ name => 'waterlevel', type => '0.0 <= double <= 1.0',
|
|
desc => 'Level that full transparency should represent' },
|
|
{ name => 'ambient', type => '0.0 <= double <= 1.0',
|
|
desc => 'Ambient lighting factor' },
|
|
{ name => 'compensate', type => 'boolean',
|
|
desc => 'Compensate for darkening' },
|
|
{ name => 'invert', type => 'boolean',
|
|
desc => 'Invert bumpmap' },
|
|
{ name => 'type', type => '0 <= int32 <= 3',
|
|
desc => 'Type of map { LINEAR (0), SPHERICAL (1), SINUSOIDAL (2) }' }
|
|
);
|
|
|
|
%invoke = (
|
|
code => <<'CODE'
|
|
{
|
|
success = bump_map (drawable,
|
|
bumpmap,
|
|
azimuth,
|
|
elevation,
|
|
depth,
|
|
xofs,
|
|
yofs,
|
|
waterlevel,
|
|
ambient,
|
|
compensate,
|
|
invert,
|
|
type,
|
|
TRUE,
|
|
progress,
|
|
error);
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_c_astretch {
|
|
$blurb = 'Stretch contrast to cover the maximum possible range';
|
|
|
|
$help = <<'HELP';
|
|
This simple plug-in does an automatic contrast stretch. For each
|
|
channel in the image, it finds the minimum and maximum values... it
|
|
uses those values to stretch the individual histograms to the full
|
|
contrast range. For some images it may do just what you want; for
|
|
others it may not work that well.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:stretch-contrast');
|
|
$date = '2013';
|
|
|
|
@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' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:stretch-contrast",
|
|
"keep-colors", (gboolean) FALSE,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Stretch Contrast"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_cartoon {
|
|
$blurb = 'Simulate a cartoon by enhancing edges';
|
|
|
|
$help = <<'HELP';
|
|
Propagates dark values in an image based on each pixel's relative
|
|
darkness to a neighboring average. The idea behind this filter is to
|
|
give the look of a black felt pen drawing subsequently shaded with
|
|
color. This is achieved by darkening areas of the image which are
|
|
measured to be darker than a neighborhood average. In this way,
|
|
sufficiently large shifts in intensity are darkened to black. The rate
|
|
at which they are darkened to black is determined by the second
|
|
pct_black parameter. The mask_radius parameter controls the size of
|
|
the pixel neighborhood over which the average intensity is computed
|
|
and then compared to each pixel in the neighborhood to decide whether
|
|
or not to darken it to black. Large values for mask_radius result in
|
|
very thick black areas bordering the shaded regions of color and much
|
|
less detail for black areas everywhere including inside regions of
|
|
color. Small values result in more subtle pen strokes and detail
|
|
everywhere. Small values for the pct_black make the blend from the
|
|
color regions to the black border lines smoother and the lines
|
|
themselves thinner and less noticeable; larger values achieve the
|
|
opposite effect.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:cartoon');
|
|
$date = '2019';
|
|
|
|
@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 => 'mask_radius', type => '1.0 <= double <= 50.0',
|
|
desc => 'Cartoon mask radius (radius of pixel neighborhood)' },
|
|
{ name => 'pct_black', type => '0.0 <= double <= 1.0',
|
|
desc => 'Percentage of darkened pixels to set to black' },
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:cartoon",
|
|
"mask-radius", mask_radius,
|
|
"pct-black", pct_black,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Cartoon"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_colors_channel_mixer {
|
|
$blurb = 'Alter colors by mixing RGB Channels';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in mixes the RGB channels.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:channel-mixer');
|
|
$date = '2013';
|
|
|
|
@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 => 'monochrome', type => '0 <= int32 <= 1',
|
|
desc => 'Monochrome { TRUE, FALSE }' },
|
|
{ name => 'rr_gain', type => '-2 <= double <= 2',
|
|
desc => 'Set the red gain for the red channel' },
|
|
{ name => 'rg_gain', type => '-2 <= double <= 2',
|
|
desc => 'Set the green gain for the red channel' },
|
|
{ name => 'rb_gain', type => '-2 <= double <= 2',
|
|
desc => 'Set the blue gain for the red channel' },
|
|
{ name => 'gr_gain', type => '-2 <= double <= 2',
|
|
desc => 'Set the red gain for the green channel' },
|
|
{ name => 'gg_gain', type => '-2 <= double <= 2',
|
|
desc => 'Set the green gain for the green channel' },
|
|
{ name => 'gb_gain', type => '-2 <= double <= 2',
|
|
desc => 'Set the blue gain for the green channel' },
|
|
{ name => 'br_gain', type => '-2 <= double <= 2',
|
|
desc => 'Set the red gain for the blue channel' },
|
|
{ name => 'bg_gain', type => '-2 <= double <= 2',
|
|
desc => 'Set the green gain for the blue channel' },
|
|
{ name => 'bb_gain', type => '-2 <= double <= 2',
|
|
desc => 'Set the blue gain for the blue channel' },
|
|
);
|
|
|
|
%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 = NULL;
|
|
|
|
if (monochrome)
|
|
{
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:mono-mixer",
|
|
"red", rr_gain,
|
|
"green", rg_gain,
|
|
"blue", rb_gain,
|
|
NULL);
|
|
}
|
|
else
|
|
{
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:channel-mixer",
|
|
"rr-gain", rr_gain,
|
|
"rg-gain", rg_gain,
|
|
"rb-gain", rb_gain,
|
|
"gr-gain", gr_gain,
|
|
"gg-gain", gg_gain,
|
|
"gb-gain", gb_gain,
|
|
"br-gain", br_gain,
|
|
"bg-gain", bg_gain,
|
|
"bb-gain", bb_gain,
|
|
NULL);
|
|
}
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Channel Mixer"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_colortoalpha {
|
|
$blurb = 'Convert a specified color to transparency';
|
|
|
|
$help = <<'HELP';
|
|
This replaces as much of a given color as possible in each pixel with
|
|
a corresponding amount of alpha, then readjusts the color accordingly.
|
|
HELP
|
|
|
|
&std_pdb_misc;
|
|
$date = '1999';
|
|
|
|
@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 => 'color', type => 'geglcolor',
|
|
desc => 'Color to remove' }
|
|
);
|
|
|
|
%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))
|
|
{
|
|
GeglColor *gegl_color = gegl_color_duplicate (color);
|
|
GeglNode *node =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:color-to-alpha",
|
|
"color", gegl_color,
|
|
NULL);
|
|
g_object_unref (gegl_color);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Color to Alpha"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_convmatrix {
|
|
$blurb = 'Apply a generic 5x5 convolution matrix';
|
|
|
|
$help = <<'HELP';
|
|
Apply a generic 5x5 convolution matrix.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:convolution-matrix');
|
|
$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 => 'matrix', type => 'doublearray',
|
|
desc => 'The 5x5 convolution matrix',
|
|
array => { name => 'argc_matrix',
|
|
desc => 'The number of elements in the following array, must always be 25' } },
|
|
{ name => 'alpha_alg', type => 'boolean',
|
|
desc => 'Enable weighting by alpha channel' },
|
|
{ name => 'divisor', type => 'double',
|
|
desc => 'Divisor' },
|
|
{ name => 'offset', type => 'double',
|
|
desc => 'Offset' },
|
|
{ name => 'channels', type => 'int32array',
|
|
desc => 'Mask of the channels to be filtered',
|
|
array => { name => 'argc_channels',
|
|
desc => 'The number of elements in following array, must always be 5' } },
|
|
{ name => 'bmode', type => '0 <= int32 <= 2',
|
|
desc => 'Mode for treating image borders { EXTEND (0), WRAP (1), CLEAR (2) }' }
|
|
);
|
|
|
|
%invoke = (
|
|
code => <<'CODE'
|
|
{
|
|
if (argc_matrix != 25)
|
|
{
|
|
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
_("Array 'matrix' has only %d members, must have 25"),
|
|
/* TODO: rather than converting the gsize, we should
|
|
* change the string, but we are in string freeze.
|
|
*/
|
|
(gint) argc_matrix);
|
|
success = FALSE;
|
|
}
|
|
|
|
if (success && argc_channels != 5)
|
|
{
|
|
g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_INVALID_ARGUMENT,
|
|
_("Array 'channels' has only %d members, must have 5"),
|
|
/* TODO: rather than converting the gsize, we should
|
|
* change the string, but we are in string freeze.
|
|
*/
|
|
(gint) argc_channels);
|
|
success = FALSE;
|
|
}
|
|
|
|
if (success &&
|
|
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;
|
|
GeglAbyssPolicy border = GEGL_ABYSS_CLAMP;
|
|
gboolean r = channels[1];
|
|
gboolean g = channels[2];
|
|
gboolean b = channels[3];
|
|
gboolean a = channels[4];
|
|
|
|
if (gimp_drawable_is_gray (drawable))
|
|
{
|
|
r = channels[0];
|
|
g = channels[0];
|
|
b = channels[0];
|
|
}
|
|
|
|
switch (bmode)
|
|
{
|
|
case 0: border = GEGL_ABYSS_CLAMP; break;
|
|
case 1: border = GEGL_ABYSS_LOOP; break;
|
|
case 2: border = GEGL_ABYSS_NONE; break;
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:convolution-matrix",
|
|
"a1", matrix[0],
|
|
"a2", matrix[1],
|
|
"a3", matrix[2],
|
|
"a4", matrix[3],
|
|
"a5", matrix[4],
|
|
"b1", matrix[5],
|
|
"b2", matrix[6],
|
|
"b3", matrix[7],
|
|
"b4", matrix[8],
|
|
"b5", matrix[9],
|
|
"c1", matrix[10],
|
|
"c2", matrix[11],
|
|
"c3", matrix[12],
|
|
"c4", matrix[13],
|
|
"c5", matrix[14],
|
|
"d1", matrix[15],
|
|
"d2", matrix[16],
|
|
"d3", matrix[17],
|
|
"d4", matrix[18],
|
|
"d5", matrix[19],
|
|
"e1", matrix[20],
|
|
"e2", matrix[21],
|
|
"e3", matrix[22],
|
|
"e4", matrix[23],
|
|
"e5", matrix[24],
|
|
"divisor", divisor,
|
|
"offset", offset,
|
|
"red", r,
|
|
"green", g,
|
|
"blue", b,
|
|
"alpha", a,
|
|
"normalize", FALSE,
|
|
"alpha-weight", alpha_alg,
|
|
"border", border,
|
|
NULL);
|
|
|
|
node = wrap_in_gamma_cast (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Convolution Matrix"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_cubism {
|
|
$blurb = 'Convert the image into randomly rotated square blobs';
|
|
|
|
$help = <<'HELP';
|
|
Convert the image into randomly rotated square blobs.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:cubism');
|
|
$date = '2013';
|
|
|
|
@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 => 'tile_size', type => '0.0 <= double <= 100.0',
|
|
desc => 'Average diameter of each tile (in pixels)' },
|
|
{ name => 'tile_saturation', type => '0.0 <= double <= 10.0',
|
|
desc => 'Expand tiles by this amount' },
|
|
{ name => 'bg_color', type => '0 <= int32 <= 1',
|
|
desc => 'Background color { BLACK (0), BG (1) }' }
|
|
);
|
|
|
|
%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))
|
|
{
|
|
GeglColor *color;
|
|
GeglNode *node;
|
|
|
|
if (bg_color)
|
|
{
|
|
color = gegl_color_duplicate (gimp_context_get_background (context));
|
|
gimp_color_set_alpha (color, 0.0);
|
|
}
|
|
else
|
|
{
|
|
color = gegl_color_new ("black");
|
|
gegl_color_set_rgba_with_space (color, 0.0, 0.0, 0.0, 0.0, NULL);
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:cubism",
|
|
"tile-size", tile_size,
|
|
"tile-saturation", tile_saturation,
|
|
"bg-color", color,
|
|
NULL);
|
|
g_object_unref (color);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Cubism"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_deinterlace {
|
|
$blurb = 'Fix images where every other row is missing';
|
|
|
|
$help = <<'HELP';
|
|
Deinterlace is useful for processing images from video capture
|
|
cards. When only the odd or even fields get captured, deinterlace can
|
|
be used to interpolate between the existing fields to correct this.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:deinterlace');
|
|
$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 => 'evenodd', type => '0 <= int32 <= 1',
|
|
desc => 'Which lines to keep { KEEP-ODD (0), KEEP-EVEN (1)' }
|
|
);
|
|
|
|
%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;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:deinterlace",
|
|
"keep", evenodd ? 0 : 1,
|
|
"orientation", 0, /* HORIZONTAL */
|
|
"size", 1,
|
|
NULL);
|
|
|
|
node = wrap_in_gamma_cast (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Deinterlace"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_diffraction {
|
|
$blurb = 'Generate diffraction patterns';
|
|
|
|
$help = <<'HELP';
|
|
Help? What help?
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:diffraction-patterns');
|
|
$date = '2015';
|
|
|
|
@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 => 'lam_r', type => '0.0 <= double <= 20.0',
|
|
desc => 'Light frequency (red)' },
|
|
{ name => 'lam_g', type => '0.0 <= double <= 20.0',
|
|
desc => 'Light frequency (green)' },
|
|
{ name => 'lam_b', type => '0.0 <= double <= 20.0',
|
|
desc => 'Light frequency (blue)' },
|
|
{ name => 'contour_r', type => '0.0 <= double <= 10.0',
|
|
desc => 'Number of contours (red)' },
|
|
{ name => 'contour_g', type => '0.0 <= double <= 10.0',
|
|
desc => 'Number of contours (green)' },
|
|
{ name => 'contour_b', type => '0.0 <= double <= 10.0',
|
|
desc => 'Number of contours (blue)' },
|
|
{ name => 'edges_r', type => '0.0 <= double <= 1.0',
|
|
desc => 'Number of sharp edges (red)' },
|
|
{ name => 'edges_g', type => '0.0 <= double <= 1.0',
|
|
desc => 'Number of sharp edges (green)' },
|
|
{ name => 'edges_b', type => '0.0 <= double <= 1.0',
|
|
desc => 'Number of sharp edges (blue)' },
|
|
{ name => 'brightness', type => '0.0 <= double <= 1.0',
|
|
desc => 'Brightness and shifting/fattening of contours' },
|
|
{ name => 'scattering', type => '0.0 <= double <= 100.0',
|
|
desc => 'Scattering (Speed vs. quality)' },
|
|
{ name => 'polarization', type => '-1.0 <= double <= 1.0',
|
|
desc => 'Polarization' }
|
|
);
|
|
|
|
%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;
|
|
gint x, y, width, height;
|
|
|
|
gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:diffraction-patterns",
|
|
"red-frequency", lam_r,
|
|
"green-frequency", lam_g,
|
|
"blue-frequency", lam_b,
|
|
"red-contours", contour_r,
|
|
"green-contours", contour_g,
|
|
"blue-contours", contour_b,
|
|
"red-sedges", edges_r,
|
|
"green-sedges", edges_g,
|
|
"blue-sedges", edges_b,
|
|
"brightness", brightness,
|
|
"scattering", scattering,
|
|
"polarization", polarization,
|
|
"width", width,
|
|
"height", height,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Diffraction Patterns"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_displace {
|
|
$blurb = 'Displace pixels as indicated by displacement maps';
|
|
|
|
$help = <<'HELP';
|
|
Displaces the contents of the specified drawable by the amounts specified
|
|
by 'amount-x' and 'amount-y' multiplied by the luminance of corresponding
|
|
pixels in the 'displace-map' drawables.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:displace');
|
|
$date = '2015';
|
|
|
|
@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 => 'amount_x', type => '-500.0 <= double <= 500.0',
|
|
desc => 'Displace multiplier for x direction' },
|
|
{ name => 'amount_y', type => '-500.0 <= double <= 500.0',
|
|
desc => 'Displace multiplier for y direction' },
|
|
{ name => 'do_x', type => 'boolean',
|
|
desc => 'Displace in x direction ?' },
|
|
{ name => 'do_y', type => 'boolean',
|
|
desc => 'Displace in y direction ?' },
|
|
{ name => 'displace_map_x', type => 'drawable',
|
|
desc => 'Displacement map for x direction' },
|
|
{ name => 'displace_map_y', type => 'drawable',
|
|
desc => 'Displacement map for y direction' },
|
|
{ name => 'displace_type', type => '1 <= int32 <= 3',
|
|
desc => 'Edge behavior { WRAP (1), SMEAR (2), BLACK (3) }' }
|
|
);
|
|
|
|
%invoke = (
|
|
code => <<'CODE'
|
|
{
|
|
success = displace (drawable,
|
|
amount_x,
|
|
amount_y,
|
|
do_x,
|
|
do_y,
|
|
displace_map_x,
|
|
displace_map_y,
|
|
displace_type,
|
|
0,
|
|
progress,
|
|
error);
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_displace_polar {
|
|
$blurb = 'Displace pixels as indicated by displacement maps';
|
|
|
|
$help = <<'HELP';
|
|
Just like plug-in-displace but working in polar coordinates.
|
|
The drawable is whirled and pinched according to the map.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:displace');
|
|
$date = '2015';
|
|
|
|
@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 => 'amount_x', type => '-500.0 <= double <= 500.0',
|
|
desc => 'Displace multiplier for radial direction' },
|
|
{ name => 'amount_y', type => '-500.0 <= double <= 500.0',
|
|
desc => 'Displace multiplier for tangent direction' },
|
|
{ name => 'do_x', type => 'boolean',
|
|
desc => 'Displace in radial direction ?' },
|
|
{ name => 'do_y', type => 'boolean',
|
|
desc => 'Displace in tangent direction ?' },
|
|
{ name => 'displace_map_x', type => 'drawable',
|
|
desc => 'Displacement map for radial direction' },
|
|
{ name => 'displace_map_y', type => 'drawable',
|
|
desc => 'Displacement map for tangent direction' },
|
|
{ name => 'displace_type', type => '1 <= int32 <= 3',
|
|
desc => 'Edge behavior { WRAP (1), SMEAR (2), BLACK (3) }' }
|
|
);
|
|
|
|
%invoke = (
|
|
code => <<'CODE'
|
|
{
|
|
success = displace (drawable,
|
|
amount_x,
|
|
amount_y,
|
|
do_x,
|
|
do_y,
|
|
displace_map_x,
|
|
displace_map_y,
|
|
displace_type,
|
|
1,
|
|
progress,
|
|
error);
|
|
}
|
|
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 <= double <= 10.0',
|
|
desc => 'Radius of inner gaussian blur in pixels' },
|
|
{ name => 'outer', type => '0.0 <= double <= 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';
|
|
|
|
$help = <<'HELP';
|
|
Perform edge detection on the contents of the specified drawable.
|
|
AMOUNT is an arbitrary constant, WRAPMODE is like displace plug-in
|
|
(useful for tileable image). EDGEMODE sets the kind of matrix transform
|
|
applied to the pixels, SOBEL was the method used in older versions.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:edge');
|
|
$date = '2015';
|
|
|
|
@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 => 'amount', type => '1.0 <= double <= 10.0',
|
|
desc => 'Edge detection amount' },
|
|
{ name => 'warpmode', type => '0 <= int32 <= 3',
|
|
desc => 'Edge detection behavior { NONE (0), WRAP (1), SMEAR (2), BLACK (3) }' },
|
|
{ name => 'edgemode', type => '0 <= int32 <= 5',
|
|
desc => 'Edge detection algorithm { SOBEL (0), PREWITT (1), GRADIENT (2), ROBERTS (3), DIFFERENTIAL (4), LAPLACE (5) }' }
|
|
);
|
|
|
|
%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;
|
|
GeglAbyssPolicy border_behavior = GEGL_ABYSS_NONE;
|
|
|
|
switch (warpmode)
|
|
{
|
|
case 0:
|
|
border_behavior = GEGL_ABYSS_NONE;
|
|
break;
|
|
|
|
case 1:
|
|
border_behavior = GEGL_ABYSS_LOOP;
|
|
break;
|
|
|
|
case 2:
|
|
border_behavior = GEGL_ABYSS_CLAMP;
|
|
break;
|
|
|
|
case 3:
|
|
border_behavior = GEGL_ABYSS_BLACK;
|
|
break;
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:edge",
|
|
"algorithm", edgemode,
|
|
"amount", amount,
|
|
"border-behavior", border_behavior,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Edge"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_emboss {
|
|
$blurb = 'Simulate an image created by embossing';
|
|
|
|
$help = <<'HELP';
|
|
Emboss or Bumpmap the given drawable, specifying the angle and
|
|
elevation for the light source.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:emboss');
|
|
$date = '2019';
|
|
|
|
@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 => 'azimuth', type => '0.0 <= double <= 360.0',
|
|
desc => 'The Light Angle (degrees)' },
|
|
{ name => 'elevation', type => '0.0 <= double <= 180',
|
|
desc => 'The Elevation Angle (degrees)' },
|
|
{ name => 'depth', type => '0 < int32 < 100',
|
|
default => 1, desc => 'The Filter Width' },
|
|
{ name => 'emboss', type => 'boolean',
|
|
desc => 'Emboss (TRUE), Bumpmap (FALSE)' }
|
|
);
|
|
|
|
%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;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:emboss",
|
|
"type", emboss ? 0 : 1,
|
|
"azimuth", azimuth,
|
|
"elevation", elevation,
|
|
"depth", depth,
|
|
NULL);
|
|
|
|
node = wrap_in_gamma_cast (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Emboss"),
|
|
node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_engrave {
|
|
$blurb = 'Simulate an antique engraving';
|
|
|
|
$help = <<'HELP';
|
|
Creates a black-and-white 'engraved' version of an image as seen in
|
|
old illustrations.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:engrave');
|
|
$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 => 'height', type => '2 <= int32 <= 16',
|
|
desc => 'Resolution in pixels' },
|
|
{ name => 'limit', type => 'boolean',
|
|
desc => 'Limit line width' }
|
|
);
|
|
|
|
%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;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:engrave",
|
|
"row-height", height,
|
|
"limit", limit,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Engrave"),
|
|
node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_exchange {
|
|
$blurb = 'Swap one color with another';
|
|
|
|
$help = <<'HELP';
|
|
Exchange one color with another, optionally setting a threshold to
|
|
convert from one shade to another.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:color-exchange');
|
|
$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 => 'from_red', type => '0.0 <= double <= 1.0',
|
|
desc => 'Red value (from)' },
|
|
{ name => 'from_green', type => '0.0 <= double <= 1.0',
|
|
desc => 'Green value (from)' },
|
|
{ name => 'from_blue', type => '0.0 <= double <= 1.0',
|
|
desc => 'Blue value (from)' },
|
|
{ name => 'to_red', type => '0.0 <= double <= 1.0',
|
|
desc => 'Red value (to)' },
|
|
{ name => 'to_green', type => '0.0 <= double <= 1.0',
|
|
desc => 'Green value (to)' },
|
|
{ name => 'to_blue', type => '0.0 <= double <= 1.0',
|
|
desc => 'Blue value (to)' },
|
|
{ name => 'red_threshold', type => '0.0 <= double <= 1.0',
|
|
desc => 'Red threshold' },
|
|
{ name => 'green_threshold', type => '0.0 <= double <= 1.0',
|
|
desc => 'Green threshold' },
|
|
{ name => 'blue_threshold', type => '0.0 <= double <= 1.0',
|
|
desc => 'Blue threshold' }
|
|
);
|
|
|
|
%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))
|
|
{
|
|
GeglColor *gegl_from = gegl_color_new (NULL);
|
|
GeglColor *gegl_to = gegl_color_new (NULL);
|
|
GeglNode *node;
|
|
|
|
gegl_color_set_rgba (gegl_from, from_red, from_green,
|
|
from_blue, 1.0);
|
|
gegl_color_set_rgba (gegl_to, to_red, to_green,
|
|
to_blue, 1.0);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:color-exchange",
|
|
"from-color", gegl_from,
|
|
"to-color", gegl_to,
|
|
"red-threshold", red_threshold,
|
|
"green-threshold", green_threshold,
|
|
"blue-threshold", blue_threshold,
|
|
NULL);
|
|
|
|
g_object_unref (gegl_from);
|
|
g_object_unref (gegl_to);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Color Exchange"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_flarefx {
|
|
$blurb = 'Add a lens flare effect';
|
|
|
|
$help = <<'HELP';
|
|
Adds a lens flare effects. Makes your image look like it was snapped
|
|
with a cheap camera with a lot of lens :)
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:lens-flare');
|
|
$date = '2015';
|
|
|
|
@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 => 'pos_x', type => 'int32',
|
|
desc => 'X-Position' },
|
|
{ name => 'pos_y', type => 'int32',
|
|
desc => 'Y-Position' }
|
|
);
|
|
|
|
%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;
|
|
gint width = gimp_item_get_width (GIMP_ITEM (drawable));
|
|
gint height = gimp_item_get_height (GIMP_ITEM (drawable));
|
|
gdouble x = (gdouble) pos_x / (gdouble) width;
|
|
gdouble y = (gdouble) pos_y / (gdouble) height;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:lens-flare",
|
|
"pos-x", x,
|
|
"pos-y", y,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Lens Flare"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_fractal_trace {
|
|
$blurb = 'Transform image with the Mandelbrot Fractal';
|
|
|
|
$help = <<'HELP';
|
|
Transform image with the Mandelbrot Fractal
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:fractal-trace');
|
|
$date = '2018';
|
|
|
|
@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 => 'xmin', type => '-50.0 <= double <= 50.0',
|
|
desc => 'xmin fractal image delimiter' },
|
|
{ name => 'xmax', type => '-50.0 <= double <= 50.0',
|
|
desc => 'xmax fractal image delimiter' },
|
|
{ name => 'ymin', type => '-50.0 <= double <= 50.0',
|
|
desc => 'ymin fractal image delimiter' },
|
|
{ name => 'ymax', type => '-50.0 <= double <= 50.0',
|
|
desc => 'ymax fractal image delimiter' },
|
|
{ name => 'depth', type => '1 <= int32 <= 65536',
|
|
desc => 'Trace depth' },
|
|
{ name => 'outside_type', type => '0 <= int32 <= 3',
|
|
desc => 'Outside type { WRAP (0), TRANS (1), BLACK (2), WHITE (3) }' }
|
|
);
|
|
|
|
%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;
|
|
GeglAbyssPolicy abyss = GEGL_ABYSS_LOOP;
|
|
|
|
switch (outside_type)
|
|
{
|
|
case 0: abyss = GEGL_ABYSS_LOOP; break;
|
|
case 1: abyss = GEGL_ABYSS_NONE; break;
|
|
case 2: abyss = GEGL_ABYSS_BLACK; break;
|
|
case 3: abyss = GEGL_ABYSS_WHITE; break;
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:fractal-trace",
|
|
"X1", xmin,
|
|
"X2", xmax,
|
|
"Y1", ymin,
|
|
"Y2", ymax,
|
|
"depth", depth,
|
|
"abyss-policy", abyss,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Fractal Trace"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
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 <= double <= 1500.0',
|
|
desc => 'Horizontal radius of gaussian blur (in pixels)' },
|
|
{ name => 'vertical', type => '0.0 <= double <= 1500.0',
|
|
desc => 'Vertical radius of gaussian blur (in pixels)' },
|
|
{ name => 'method', type => '0 <= int32 <= 1',
|
|
desc => 'Blur method { AUTO (0), FIR (1), IIR (2) }' }
|
|
);
|
|
|
|
%invoke = (
|
|
code => <<'CODE'
|
|
{
|
|
success = gaussian_blur (drawable, horizontal, vertical, method, progress,
|
|
error);
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_glasstile {
|
|
$blurb = 'Simulate distortion caused by square glass tiles';
|
|
|
|
$help = <<'HELP';
|
|
Divide the image into square glassblocks in which the image is
|
|
refracted.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:tile-glass');
|
|
$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 => 'tilex', type => '10 <= int32 <= 500',
|
|
desc => 'Tile width' },
|
|
{ name => 'tiley', type => '10 <= int32 <= 500',
|
|
desc => 'Tile height' },
|
|
);
|
|
|
|
%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;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:tile-glass",
|
|
"tile-width", tilex,
|
|
"tile-height", tiley,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Glass Tile"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_hsv_noise {
|
|
$blurb = 'Randomize hue, saturation and value independently';
|
|
|
|
$help = <<'HELP';
|
|
Scattering pixel values in HSV space
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:noise-hsv');
|
|
$date = '2013';
|
|
|
|
@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 => 'holdness', type => '1 <= int32 <= 8',
|
|
desc => 'Convolution strength' },
|
|
{ name => 'hue_distance', type => '0 <= int32 <= 180',
|
|
desc => 'Scattering of hue angle' },
|
|
{ name => 'saturation_distance', type => '0 <= int32 <= 255',
|
|
desc => 'Distribution distance on saturation axis' },
|
|
{ name => 'value_distance', type => '0 <= int32 <= 255',
|
|
desc => 'Distribution distance on value axis' }
|
|
);
|
|
|
|
%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;
|
|
|
|
gdouble saturation = saturation_distance / 255.0;
|
|
gdouble value = value_distance / 255.0;
|
|
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:noise-hsv",
|
|
"holdness", (gint) holdness,
|
|
"hue-distance", (gdouble) hue_distance,
|
|
"saturation-distance", (gdouble) saturation,
|
|
"value-distance", (gdouble) value,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Noise HSV"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_illusion {
|
|
$blurb = 'Superimpose many altered copies of the image';
|
|
|
|
$help = <<'HELP';
|
|
Produce illusion.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:illusion');
|
|
$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 => 'division', type => '0 <= int32 <= 64',
|
|
desc => 'The number of divisions' },
|
|
{ name => 'type', type => '0 <= int32 <= 1',
|
|
desc => 'Illusion type { TYPE1 (0), TYPE2 (1) }' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:illusion",
|
|
"division", (gint) division,
|
|
"illusion-type", (gint) type,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Illusion"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_laplace {
|
|
$blurb = 'High-resolution edge detection';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in creates one-pixel wide edges from the
|
|
image, with the value proportional to the gradient.
|
|
It uses the Laplace operator (a 3x3 kernel with -8
|
|
in the middle). The image has to be laplacered to
|
|
get useful results, a gauss with 1.5 - 5.0
|
|
depending on the noise in the image is best.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:edge-laplace');
|
|
$date = '2013';
|
|
|
|
@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' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:edge-laplace",
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Laplace"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_lens_distortion {
|
|
$blurb = 'Corrects lens distortion';
|
|
|
|
$help = <<'HELP';
|
|
Corrects barrel or pincushion lens distortion.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:lens-distortion');
|
|
$date = '2013';
|
|
|
|
@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 => 'offset_x', type => '-100 <= double <= 100',
|
|
desc => 'Effect centre offset in X' },
|
|
{ name => 'offset_y', type => '-100 <= double <= 100',
|
|
desc => 'Effect centre offset in Y' },
|
|
{ name => 'main_adjust', type => '-100 <= double <= 100',
|
|
desc => 'Amount of second-order distortion' },
|
|
{ name => 'edge_adjust', type => '-100 <= double <= 100',
|
|
desc => 'Amount of fourth-order distortion' },
|
|
{ name => 'rescale', type => '-100 <= double <= 100',
|
|
desc => 'Rescale overall image size' },
|
|
{ name => 'brighten', type => '-100 <= double <= 100',
|
|
desc => 'Adjust brightness in corners' }
|
|
);
|
|
|
|
%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 = NULL;
|
|
GeglColor *color;
|
|
|
|
color = gegl_color_duplicate (gimp_context_get_background (context));
|
|
|
|
if (gimp_drawable_has_alpha (drawable))
|
|
gimp_color_set_alpha (color, 0.0);
|
|
else
|
|
gimp_color_set_alpha (color, 1.0);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:lens-distortion",
|
|
"main", (gdouble) main_adjust,
|
|
"edge", (gdouble) edge_adjust,
|
|
"zoom", (gdouble) rescale,
|
|
"x-shift", (gdouble) offset_x,
|
|
"y-shift", (gdouble) offset_y,
|
|
"brighten", (gdouble) brighten,
|
|
"background", color,
|
|
NULL);
|
|
|
|
g_object_unref (color);
|
|
|
|
node = wrap_in_selection_bounds (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Lens Distortion"),
|
|
node);
|
|
g_object_unref (node);
|
|
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_make_seamless {
|
|
$blurb = 'Alters edges to make the image seamlessly tileable';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in creates a seamless tileable from the input drawable.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:tile-seamless');
|
|
$date = '2013';
|
|
|
|
@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' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:tile-seamless",
|
|
NULL);
|
|
|
|
node = wrap_in_selection_bounds (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Tile Seamless"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_maze {
|
|
$blurb = 'Draw a labyrinth';
|
|
|
|
$help = <<'HELP';
|
|
Generates a maze using either the depth-first search method or Prim's
|
|
algorithm. Can make tileable mazes too.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:maze');
|
|
$date = '2015';
|
|
|
|
@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 => 'width', type => '1 <= int32 <= 1024',
|
|
desc => 'Width of the passages' },
|
|
{ name => 'height', type => '1 <= int32 <= 1024',
|
|
desc => 'Height of the passages' },
|
|
{ name => 'tileable', type => 'boolean',
|
|
desc => 'Tileable maze?' },
|
|
{ name => 'algorithm', type => '0 <= int32 <= 1',
|
|
desc => 'Generation algorithm (0 = DEPTH FIRST, 1 = PRIM\'S ALGORITHM)' },
|
|
{ name => 'seed', type => 'int32',
|
|
desc => 'Random Seed' },
|
|
{ name => 'multiple', type => 'int32', dead => 1,
|
|
desc => 'Multiple (use 57)' },
|
|
{ name => 'offset', type => 'int32', dead => 1,
|
|
desc => 'Offset (use 1)' }
|
|
);
|
|
|
|
%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;
|
|
GeglColor *fg_color;
|
|
GeglColor *bg_color;
|
|
|
|
fg_color = gimp_context_get_foreground (context);
|
|
bg_color = gimp_context_get_background (context);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:maze",
|
|
"x", width,
|
|
"y", height,
|
|
"algorithm-type", algorithm,
|
|
"tileable", tileable,
|
|
"seed", seed,
|
|
"fg-color", fg_color,
|
|
"bg-color", bg_color,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Maze"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_mblur {
|
|
$blurb = 'Simulate movement using directional blur';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in simulates the effect seen when
|
|
photographing a moving object at a slow shutter
|
|
speed. Done by adding multiple displaced copies.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:motion-blur-linear, -zoom, -circular');
|
|
$date = '2013';
|
|
|
|
@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 => 'type', type => '0 <= int32 <= 2',
|
|
desc => 'Type of motion blur { LINEAR (0), RADIAL (1), ZOOM (2) }' },
|
|
{ name => 'length', type => 'double',
|
|
desc => 'Length' },
|
|
{ name => 'angle', type => '0 <= double <= 360',
|
|
desc => 'Angle' },
|
|
{ name => 'center_x', type => 'double',
|
|
desc => 'Center X' },
|
|
{ name => 'center_y', type => 'double',
|
|
desc => 'Center Y' }
|
|
);
|
|
|
|
%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 = NULL;
|
|
gint width = gimp_item_get_width (GIMP_ITEM (drawable));
|
|
gint height = gimp_item_get_height (GIMP_ITEM (drawable));
|
|
|
|
center_x /= (gdouble) width;
|
|
center_y /= (gdouble) height;
|
|
|
|
if (angle > 180.0)
|
|
angle -= 360.0;
|
|
|
|
if (type == 0)
|
|
{
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:motion-blur-linear",
|
|
"length", length,
|
|
"angle", angle,
|
|
NULL);
|
|
}
|
|
else if (type == 1)
|
|
{
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:motion-blur-circular",
|
|
"center-x", center_x,
|
|
"center-y", center_y,
|
|
"angle", angle,
|
|
NULL);
|
|
}
|
|
else if (type == 2)
|
|
{
|
|
gdouble factor = CLAMP (length / 256.0, 0.0, 1.0);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:motion-blur-zoom",
|
|
"center-x", center_x,
|
|
"center-y", center_y,
|
|
"factor", factor,
|
|
NULL);
|
|
}
|
|
|
|
if (node != NULL)
|
|
{
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Motion Blur"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_mblur_inward {
|
|
$blurb = 'Simulate movement using directional blur';
|
|
|
|
$help = <<'HELP';
|
|
This procedure is equivalent to plug-in-mblur but
|
|
performs the zoom blur inward instead of outward.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:motion-blur-linear, -zoom, -circular');
|
|
$date = '2013';
|
|
|
|
@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 => 'type', type => '0 <= int32 <= 2',
|
|
desc => 'Type of motion blur { LINEAR (0), RADIAL (1), ZOOM (2) }' },
|
|
{ name => 'length', type => 'double',
|
|
desc => 'Length' },
|
|
{ name => 'angle', type => '0 <= double <= 360',
|
|
desc => 'Angle' },
|
|
{ name => 'center_x', type => 'double',
|
|
desc => 'Center X' },
|
|
{ name => 'center_y', type => 'double',
|
|
desc => 'Center Y' }
|
|
);
|
|
|
|
%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 = NULL;
|
|
gint width = gimp_item_get_width (GIMP_ITEM (drawable));
|
|
gint height = gimp_item_get_height (GIMP_ITEM (drawable));
|
|
|
|
center_x /= (gdouble) width;
|
|
center_y /= (gdouble) height;
|
|
|
|
if (type == 0)
|
|
{
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:motion-blur-linear",
|
|
"length", length,
|
|
"angle", angle,
|
|
NULL);
|
|
}
|
|
else if (type == 1)
|
|
{
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:motion-blur-circular",
|
|
"center-x", center_x,
|
|
"center-y", center_y,
|
|
"angle", angle,
|
|
NULL);
|
|
}
|
|
else if (type == 2)
|
|
{
|
|
gdouble factor = CLAMP (-length / (256.0 - length), -10.0, 0.0);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:motion-blur-zoom",
|
|
"center-x", center_x,
|
|
"center-y", center_y,
|
|
"factor", factor,
|
|
NULL);
|
|
}
|
|
|
|
if (node != NULL)
|
|
{
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Motion Blur"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_median_blur {
|
|
$blurb = 'Blur using the median color near each pixel';
|
|
|
|
$help = <<'HELP';
|
|
Blur resulting from computing the median color in the
|
|
neighborhood of each pixel
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:median-blur');
|
|
$date = '2021';
|
|
|
|
@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 => '-400 <= int32 <= 400',
|
|
desc => 'Neighborhood radius, a negative value will calculate with inverted percentiles' },
|
|
{ name => 'percentile', type => '0 <= double <= 100',
|
|
desc => 'Neighborhood color percentile' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:median-blur",
|
|
"radius", radius,
|
|
"percentile", percentile,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Median Blur"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_mosaic {
|
|
$blurb = 'Convert the image into irregular tiles';
|
|
|
|
$help = <<'HELP';
|
|
Mosaic is a filter which transforms an image into
|
|
what appears to be a mosaic, composed of small primitives,
|
|
each of constant color and of an approximate size.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:mosaic');
|
|
$date = '2013';
|
|
|
|
@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 => 'tile_size', type => '1 <= double <= 1000',
|
|
desc => 'Average diameter of each tile (in pixels)' },
|
|
{ name => 'tile_height', type => '1 <= double <= 1000',
|
|
desc => 'Apparent height of each tile (in pixels)' },
|
|
{ name => 'tile_spacing', type => '0.1 <= double <= 1000',
|
|
desc => 'Inter_tile spacing (in pixels)' },
|
|
{ name => 'tile_neatness', type => '0 <= double <= 1.0',
|
|
desc => 'Deviation from perfectly formed tiles' },
|
|
{ name => 'tile_allow_split', type => '0 <= int32 <= 1',
|
|
desc => 'Allows splitting tiles at hard edges' },
|
|
{ name => 'light_dir', type => '0 <= double <= 360',
|
|
desc => 'Direction of light_source (in degrees)' },
|
|
{ name => 'color_variation', type => '0.0 <= double <= 1.0',
|
|
desc => 'Magnitude of random color variations' },
|
|
{ name => 'antialiasing', type => '0 <= int32 <= 1',
|
|
desc => 'Enables smoother tile output at the cost of speed' },
|
|
{ name => 'color_averaging', type => '0 <= int32 <= 1',
|
|
desc => 'Tile color based on average of subsumed pixels' },
|
|
{ name => 'tile_type', type => '0 <= int32 <= 3',
|
|
desc => 'Tile geometry { SQUARES (0), HEXAGONS (1), OCTAGONS (2), TRIANGLES (3) }' },
|
|
{ name => 'tile_surface', type => '0 <= int32 <= 1',
|
|
desc => 'Surface characteristics { SMOOTH (0), ROUGH (1) }' },
|
|
{ name => 'grout_color', type => '0 <= int32 <= 1',
|
|
desc => 'Grout color (black/white or fore/background) { BW (0), FG-BG (1) }' }
|
|
);
|
|
|
|
%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))
|
|
{
|
|
GeglColor *fg_color;
|
|
GeglColor *bg_color;
|
|
GeglNode *node;
|
|
|
|
if (grout_color)
|
|
{
|
|
bg_color = gegl_color_duplicate (gimp_context_get_background (context));
|
|
fg_color = gegl_color_duplicate (gimp_context_get_foreground (context));
|
|
}
|
|
else
|
|
{
|
|
/* sic */
|
|
fg_color = gegl_color_new ("white");
|
|
bg_color = gegl_color_new ("black");
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:mosaic",
|
|
"tile-size", (gdouble) tile_size,
|
|
"tile-height", (gdouble) tile_height,
|
|
"tile-spacing", (gdouble) tile_spacing,
|
|
"tile-neatness", (gdouble) tile_neatness,
|
|
"tile-allow-split", (gboolean) tile_allow_split,
|
|
"light-dir", (gdouble) light_dir,
|
|
"color-variation", (gfloat) color_variation,
|
|
"antialiasing", (gboolean) antialiasing,
|
|
"color-averaging", (gboolean) color_averaging,
|
|
"tile-type", (gint) tile_type,
|
|
"tile-surface", (gboolean) tile_surface,
|
|
"light-color", fg_color,
|
|
"joints-color", bg_color,
|
|
NULL);
|
|
|
|
g_object_unref (fg_color);
|
|
g_object_unref (bg_color);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Mosaic"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_neon {
|
|
$blurb = 'Simulate the glowing boundary of a neon light';
|
|
|
|
$help = <<'HELP';
|
|
This filter works in a manner similar to the edge plug-in, but uses
|
|
the first derivative of the gaussian operator to achieve resolution
|
|
independence. The IIR method of calculating the effect is utilized to
|
|
keep the processing time constant between large and small standard
|
|
deviations.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:edge-neon');
|
|
$date = '2019';
|
|
|
|
@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 <= double <= 1500.0',
|
|
desc => 'Radius of neon effect (in pixels)' },
|
|
{ name => 'amount', type => '0.0 <= double <= 100.0',
|
|
desc => 'Effect enhancement variable' }
|
|
);
|
|
|
|
%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;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:edge-neon",
|
|
"radius", radius,
|
|
"amount", amount,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Neon"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_newsprint {
|
|
$blurb = 'Halftone the image to give newspaper-like effect';
|
|
|
|
$help = $blurb;
|
|
|
|
&std_pdb_compat('gegl:newsprint');
|
|
$date = '2019';
|
|
|
|
@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 => 'cell_width', type => '0 <= int32 <= 1500',
|
|
desc => 'Screen cell width in pixels' },
|
|
{ name => 'colorspace', type => '0 <= int32 <= 3',
|
|
desc => 'Separate to { GRAYSCALE (0), RGB (1), CMYK (2), LUMINANCE (3) }' },
|
|
{ name => 'k_pullout', type => '0 <= int32 <= 100',
|
|
desc => 'Percentage of black to pullout (CMYK only)' },
|
|
{ name => 'gry_ang', type => '0.0 <= double <= 360.0',
|
|
desc => 'Grey/black screen angle (degrees)' },
|
|
{ name => 'gry_spotfn', type => '0 <= int32 <= 4',
|
|
desc => 'Grey/black spot function { DOTS (0), LINES (1), DIAMONDS (2), EUCLIDIAN-DOT (3), PS-DIAMONDS (4) }' },
|
|
{ name => 'red_ang', type => '0.0 <= double <= 360.0',
|
|
desc => 'Red/cyan screen angle (degrees)' },
|
|
{ name => 'red_spotfn', type => '0 <= int32 <= 4',
|
|
desc => 'Red/cyan spot function { DOTS (0), LINES (1), DIAMONDS (2), EUCLIDIAN-DOT (3), PS-DIAMONDS (4) }' },
|
|
{ name => 'grn_ang', type => '0.0 <= double <= 360.0',
|
|
desc => 'Green/magenta screen angle (degrees)' },
|
|
{ name => 'grn_spotfn', type => '0 <= int32 <= 4',
|
|
desc => 'Green/magenta spot function { DOTS (0), LINES (1), DIAMONDS (2), EUCLIDIAN-DOT (3), PS-DIAMONDS (4) }' },
|
|
{ name => 'blu_ang', type => '0.0 <= double <= 360.0',
|
|
desc => 'Blue/yellow screen angle (degrees)' },
|
|
{ name => 'blu_spotfn', type => '0 <= int32 <= 4',
|
|
desc => 'Blue/yellow spot function { DOTS (0), LINES (1), DIAMONDS (2), EUCLIDIAN-DOT (3), PS-DIAMONDS (4) }' },
|
|
{ name => 'oversample', type => '1 <= int32 <= 128',
|
|
desc => 'how many times to oversample spot fn' }
|
|
);
|
|
|
|
%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;
|
|
gint color_model = newsprint_color_model (colorspace);
|
|
gint pattern = newsprint_pattern (gry_spotfn);
|
|
gint pattern2 = newsprint_pattern (red_spotfn);
|
|
gint pattern3 = newsprint_pattern (grn_spotfn);
|
|
gint pattern4 = newsprint_pattern (blu_spotfn);
|
|
gdouble angle = newsprint_angle (gry_ang);
|
|
gdouble angle2 = newsprint_angle (red_ang);
|
|
gdouble angle3 = newsprint_angle (grn_ang);
|
|
gdouble angle4 = newsprint_angle (blu_ang);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:newsprint",
|
|
"color-model", color_model,
|
|
"black-pullout", (gdouble) k_pullout / 100.0,
|
|
"period", (gdouble) cell_width,
|
|
"angle", angle,
|
|
"pattern", pattern,
|
|
"period2", (gdouble) cell_width,
|
|
"angle2", angle2,
|
|
"pattern2", pattern2,
|
|
"period3", (gdouble) cell_width,
|
|
"angle3", angle3,
|
|
"pattern3", pattern3,
|
|
"period4", (gdouble) cell_width,
|
|
"angle4", angle4,
|
|
"pattern4", pattern4,
|
|
"aa-samples", oversample,
|
|
NULL);
|
|
|
|
node = wrap_in_gamma_cast (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Newsprint"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_normalize {
|
|
$blurb = 'Stretch brightness values to cover the full range';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in performs almost the same operation as the 'contrast
|
|
autostretch' plug-in, except that it won't allow the color channels to
|
|
normalize independently. This is actually what most people probably
|
|
want instead of contrast-autostretch; use c-a only if you wish to
|
|
remove an undesirable color-tint from a source image which is supposed
|
|
to contain pure-white and pure-black.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:stretch-contrast');
|
|
$date = '2019';
|
|
|
|
@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' }
|
|
);
|
|
|
|
%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;
|
|
|
|
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);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_nova {
|
|
$blurb = 'Add a starburst to the image';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in produces an effect like a supernova burst. The amount of
|
|
the light effect is approximately in proportion to 1/r, where r is the
|
|
distance from the center of the star.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:supernova');
|
|
$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 => 'xcenter', type => 'int32',
|
|
desc => 'X coordinates of the center of supernova' },
|
|
{ name => 'ycenter', type => 'int32',
|
|
desc => 'Y coordinates of the center of supernova' },
|
|
{ name => 'color', type => 'geglcolor',
|
|
desc => 'Color of supernova' },
|
|
{ name => 'radius', type => '1 <= int32 <= 3000',
|
|
desc => 'Radius of supernova' },
|
|
{ name => 'nspoke', type => '1 <= int32 <= 1024',
|
|
desc => 'Number of spokes' },
|
|
{ name => 'randomhue', type => '0 <= int32 <= 360',
|
|
desc => 'Random hue' }
|
|
);
|
|
|
|
%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))
|
|
{
|
|
GeglColor *gegl_color;
|
|
GeglNode *node;
|
|
gdouble center_x = (gdouble) xcenter / (gdouble) gimp_item_get_width (GIMP_ITEM (drawable));
|
|
gdouble center_y = (gdouble) ycenter / (gdouble) gimp_item_get_height (GIMP_ITEM (drawable));
|
|
|
|
gegl_color = gegl_color_duplicate (color);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:supernova",
|
|
"center-x", center_x,
|
|
"center-y", center_y,
|
|
"radius", radius,
|
|
"spokes-count", nspoke,
|
|
"random-hue", randomhue,
|
|
"color", gegl_color,
|
|
"seed", g_random_int (),
|
|
NULL);
|
|
|
|
g_object_unref (gegl_color);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Supernova"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_oilify {
|
|
$blurb = 'Smear colors to simulate an oil painting';
|
|
|
|
$help = <<'HELP';
|
|
This function performs the well-known oil-paint effect on the
|
|
specified drawable.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:oilify');
|
|
$date = '2019';
|
|
|
|
@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 => 'mask_size', type => '1 <= int32 <= 200',
|
|
desc => 'Oil paint mask size' },
|
|
{ name => 'mode', type => '0 <= int32 <= 1',
|
|
desc => 'Algorithm { RGB (0), INTENSITY (1) }' }
|
|
);
|
|
|
|
%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;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:oilify",
|
|
"mask-radius", MAX (1, mask_size / 2),
|
|
"use-inten", mode ? TRUE : FALSE,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Oilify"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_oilify_enhanced {
|
|
$blurb = 'Smear colors to simulate an oil painting';
|
|
|
|
$help = <<'HELP';
|
|
This function performs the well-known oil-paint effect on the
|
|
specified drawable.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:oilify');
|
|
$date = '2019';
|
|
|
|
@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 => 'mode', type => '0 <= int32 <= 1',
|
|
desc => 'Algorithm { RGB (0), INTENSITY (1) }' },
|
|
{ name => 'mask_size', type => '1 <= int32 <= 200',
|
|
desc => 'Oil paint mask size' },
|
|
{ name => 'mask_size_map', type => 'drawable', none_ok => 1,
|
|
desc => 'Mask size control map' },
|
|
{ name => 'exponent', type => '1 <= int32 <= 20',
|
|
desc => 'Oil paint exponent' },
|
|
{ name => 'exponent_map', type => 'drawable', none_ok => 1,
|
|
desc => 'Exponent control map' }
|
|
);
|
|
|
|
%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 *graph;
|
|
GeglNode *node;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:oilify",
|
|
"mask-radius", MAX (1, mask_size / 2),
|
|
"use-inten", mode ? TRUE : FALSE,
|
|
"exponent", exponent,
|
|
NULL);
|
|
|
|
graph = wrap_in_graph (node);
|
|
|
|
if (mask_size_map)
|
|
{
|
|
GeglNode *src_node;
|
|
src_node = create_buffer_source_node (graph, mask_size_map);
|
|
gegl_node_connect (src_node, "output", node, "aux");
|
|
}
|
|
|
|
if (exponent_map)
|
|
{
|
|
GeglNode *src_node;
|
|
src_node = create_buffer_source_node (graph, exponent_map);
|
|
gegl_node_connect (src_node, "output", node, "aux2");
|
|
}
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Oilify"),
|
|
graph);
|
|
g_object_unref (graph);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
# We simplify the GEGL signature, reducing tile width and height to just size
|
|
|
|
sub plug_in_papertile {
|
|
$blurb = 'Cut image into paper tiles, and slide them';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in cuts an image into paper tiles and slides each paper tile.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:tile-paper');
|
|
$date = '2015';
|
|
|
|
@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 => 'tile_size', type => '1 <= int32',
|
|
desc => 'Tile size (pixels)' },
|
|
{ name => 'move_max', type => '1.0 <= double <= 100.0',
|
|
desc => 'Max move rate (%)' },
|
|
{ name => 'fractional_type', type => '0 <= int32 <= 2',
|
|
desc => 'Fractional type { BACKGROUND (0), IGNORE (1), FORCE (2) }' },
|
|
{ name => 'wrap_around', type => 'boolean',
|
|
desc => 'Wrap around' },
|
|
{ name => 'centering', type => 'boolean',
|
|
desc => 'Centering' },
|
|
{ name => 'background_type', type => '0 <= int32 <= 5',
|
|
desc => 'Background type { TRANSPARENT (0), INVERTED (1), IMAGE (2), FG (3), BG (4), COLOR (5) }' },
|
|
{ name => 'background_color', type => 'geglcolor',
|
|
desc => 'Background color (for background-type == 5)' },
|
|
{ name => 'background_alpha', type => 'int32', dead => 1,
|
|
desc => 'Background alpha (unused)' }
|
|
);
|
|
|
|
%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;
|
|
GeglColor *color;
|
|
gint bg_type;
|
|
|
|
switch (background_type)
|
|
{
|
|
default:
|
|
bg_type = background_type;
|
|
color = gegl_color_new (NULL);
|
|
/* XXX: I guess what we want is to set this color (why blue?) in the
|
|
* drawable's space, though I haven't looked too much into it.
|
|
*/
|
|
gegl_color_set_rgba_with_space (color, 0.0, 0.0, 1.0, 1.0, gimp_drawable_get_space (drawable));
|
|
break;
|
|
|
|
case 3:
|
|
bg_type = 3;
|
|
color = gegl_color_duplicate (gimp_context_get_foreground (context));
|
|
break;
|
|
|
|
case 4:
|
|
bg_type = 3;
|
|
color = gegl_color_duplicate (gimp_context_get_background (context));
|
|
break;
|
|
|
|
case 5:
|
|
bg_type = 3;
|
|
color = gegl_color_duplicate (background_color);
|
|
break;
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:tile-paper",
|
|
"tile-width", tile_size,
|
|
"tile-height", tile_size,
|
|
"move-rate", move_max,
|
|
"bg-color", color,
|
|
"centering", centering,
|
|
"wrap-around", wrap_around,
|
|
"background-type", bg_type,
|
|
"fractional-type", fractional_type,
|
|
NULL);
|
|
|
|
g_object_unref (color);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Paper Tile"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_photocopy {
|
|
$blurb = 'Simulate color distortion produced by a copy machine';
|
|
|
|
$help = <<'HELP';
|
|
Propagates dark values in an image based on each pixel's relative
|
|
darkness to a neighboring average. The idea behind this filter is to
|
|
give the look of a photocopied version of the image, with toner
|
|
transferred based on the relative darkness of a particular
|
|
region. This is achieved by darkening areas of the image which are
|
|
measured to be darker than a neighborhood average and setting other
|
|
pixels to white. In this way, sufficiently large shifts in intensity
|
|
are darkened to black. The rate at which they are darkened to black is
|
|
determined by the second pct_black parameter. The mask_radius
|
|
parameter controls the size of the pixel neighborhood over which the
|
|
average intensity is computed and then compared to each pixel in the
|
|
neighborhood to decide whether or not to darken it to black. Large
|
|
values for mask_radius result in very thick black areas bordering the
|
|
regions of white and much less detail for black areas everywhere
|
|
including inside regions of color. Small values result in less toner
|
|
overall and more detail everywhere. Small values for the pct_black
|
|
make the blend from the white regions to the black border lines
|
|
smoother and the toner regions themselves thinner and less noticeable;
|
|
larger values achieve the opposite effect.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:photocopy');
|
|
$date = '2019';
|
|
|
|
@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 => 'mask_radius', type => '3.0 <= double <= 50.0',
|
|
desc => 'Photocopy mask radius (radius of pixel neighborhood)' },
|
|
{ name => 'sharpness', type => '0.0 <= double <= 1.0',
|
|
desc => 'Sharpness (detail level)' },
|
|
{ name => 'pct_black', type => '0.0 <= double <= 1.0',
|
|
desc => 'Percentage of darkened pixels to set to black' },
|
|
{ name => 'pct_white', type => '0.0 <= double <= 1.0',
|
|
desc => 'Percentage of non-darkened pixels left white' },
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:photocopy",
|
|
"mask-radius", mask_radius,
|
|
"sharpness", sharpness,
|
|
"black", pct_black,
|
|
"white", pct_white,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Photocopy"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_pixelize {
|
|
$blurb = 'Simplify image into an array of solid-colored rectangles';
|
|
|
|
$help = <<'HELP';
|
|
Pixelize the contents of the specified drawable with specified
|
|
pixelizing width and height.
|
|
HELP
|
|
|
|
&std_pdb_misc;
|
|
$date = '1997';
|
|
|
|
@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 => 'pixel_width', type => '1 <= int32 <= GIMP_MAX_IMAGE_SIZE',
|
|
desc => 'Pixel width (the decrease in horizontal resolution)' },
|
|
{ name => 'pixel_height', type => '1 <= int32 <= GIMP_MAX_IMAGE_SIZE',
|
|
desc => 'Pixel height (the decrease in vertical resolution)' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:pixelize",
|
|
"size-x", pixel_width,
|
|
"size-y", pixel_height,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Pixelize"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_plasma {
|
|
$blurb = 'Create a random plasma texture';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in produces plasma fractal images.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:plasma');
|
|
$date = '2013';
|
|
|
|
@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 => 'seed', type => '-1 <= int32 <= G_MAXINT',
|
|
desc => 'Random seed' },
|
|
{ name => 'turbulence', type => '0.0 <= double <= 7.0',
|
|
desc => 'The value of the turbulence' }
|
|
);
|
|
|
|
%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))
|
|
{
|
|
GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
|
|
GeglNode *node;
|
|
gint x, y, width, height;
|
|
|
|
gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height);
|
|
|
|
if (! gimp_channel_is_empty (gimp_image_get_mask (image)))
|
|
x = y = 0;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:plasma",
|
|
"seed", seed,
|
|
"turbulence", turbulence,
|
|
"x", x,
|
|
"y", y,
|
|
"width", width,
|
|
"height", height,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Plasma"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_polar_coords {
|
|
$blurb = 'Convert image to or from polar coordinates';
|
|
|
|
$help = <<'HELP';
|
|
Remaps and image from rectangular coordinates to polar coordinates or
|
|
vice versa.
|
|
HELP
|
|
|
|
&std_pdb_misc;
|
|
$date = '1997';
|
|
|
|
@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 => 'circle', type => '0.0 <= double <= 100.0',
|
|
desc => 'Circle depth in %' },
|
|
{ name => 'angle', type => '0.0 <= double < 360.0',
|
|
desc => 'Offset angle' },
|
|
{ name => 'backwards', type => 'boolean',
|
|
desc => 'Map backwards' },
|
|
{ name => 'inverse', type => 'boolean',
|
|
desc => 'Map from top' },
|
|
{ name => 'polrec', type => 'boolean',
|
|
desc => 'Polar to rectangular' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:polar-coordinates",
|
|
"depth", circle,
|
|
"angle", angle,
|
|
"bw", backwards, /* XXX name */
|
|
"top", inverse,
|
|
"polar", polrec,
|
|
NULL);
|
|
|
|
node = wrap_in_selection_bounds (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Polar Coordinates"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_randomize_hurl {
|
|
$blurb = 'Completely randomize a fraction of pixels';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in "hurls" randomly-valued pixels onto the selection or
|
|
image. You may select the percentage of pixels to modify and the
|
|
number of times to repeat the process.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:noise-hurl');
|
|
$date = '2013';
|
|
|
|
@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 => 'rndm_pct', type => '0.0 <= double <= 100.0',
|
|
desc => 'Randomization percentage' },
|
|
{ name => 'rndm_rcount', type => '1.0 <= double <= 100.0',
|
|
desc => 'Repeat count' },
|
|
{ name => 'randomize', type => 'boolean',
|
|
desc => 'Use random seed' },
|
|
{ name => 'seed', type => 'int32',
|
|
desc => 'Seed value (used only if randomize is FALSE)' }
|
|
);
|
|
|
|
%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 (randomize)
|
|
seed = (gint32) g_random_int ();
|
|
|
|
node =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:noise-hurl",
|
|
"seed", seed,
|
|
"pct-random", rndm_pct,
|
|
"repeat", (gint) rndm_rcount,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Random Hurl"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_randomize_pick {
|
|
$blurb = 'Randomly interchange some pixels with neighbors';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in replaces a pixel with a random adjacent pixel. You may
|
|
select the percentage of pixels to modify and the number of times to
|
|
repeat the process.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:noise-pick');
|
|
$date = '2013';
|
|
|
|
@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 => 'rndm_pct', type => '1.0 <= double <= 100.0',
|
|
desc => 'Randomization percentage' },
|
|
{ name => 'rndm_rcount', type => '1.0 <= double <= 100.0',
|
|
desc => 'Repeat count' },
|
|
{ name => 'randomize', type => 'boolean',
|
|
desc => 'Use random seed' },
|
|
{ name => 'seed', type => 'int32',
|
|
desc => 'Seed value (used only if randomize is FALSE)' }
|
|
);
|
|
|
|
%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 (randomize)
|
|
seed = (gint32) g_random_int ();
|
|
|
|
node =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:noise-pick",
|
|
"seed", seed,
|
|
"pct-random", rndm_pct,
|
|
"repeat", (gint) rndm_rcount,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Random Pick"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_randomize_slur {
|
|
$blurb = 'Randomly slide some pixels downward (similar to melting';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in "slurs" (melts like a bunch of icicles) an image. You may
|
|
select the percentage of pixels to modify and the number of times to
|
|
repeat the process.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:noise-slur');
|
|
$date = '2013';
|
|
|
|
@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 => 'rndm_pct', type => '1.0 <= double <= 100.0',
|
|
desc => 'Randomization percentage' },
|
|
{ name => 'rndm_rcount', type => '1.0 <= double <= 100.0',
|
|
desc => 'Repeat count' },
|
|
{ name => 'randomize', type => 'boolean',
|
|
desc => 'Use random seed' },
|
|
{ name => 'seed', type => 'int32',
|
|
desc => 'Seed value (used only if randomize is FALSE)' }
|
|
);
|
|
|
|
%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 (randomize)
|
|
seed = (gint32) g_random_int ();
|
|
|
|
node =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:noise-slur",
|
|
"seed", seed,
|
|
"pct-random", rndm_pct,
|
|
"repeat", (gint) rndm_rcount,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Random Slur"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_red_eye_removal {
|
|
$blurb = 'Remove the red eye effect caused by camera flashes';
|
|
|
|
$help = <<'HELP';
|
|
This procedure removes the red eye effect caused by camera flashes by
|
|
using a percentage based red color threshold. Make a selection
|
|
containing the eyes, and apply the filter while adjusting the
|
|
threshold to accurately remove the red eyes.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:red-eye-removal');
|
|
$date = '2013';
|
|
|
|
@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 => 'threshold', type => '0 <= int32 <= 100',
|
|
desc => 'Red eye threshold in percent' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:red-eye-removal",
|
|
"threshold", (gdouble) (threshold - 50) / 50.0 * 0.2 + 0.4,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Red Eye Removal"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_rgb_noise {
|
|
$blurb = 'Distort colors by random amounts';
|
|
|
|
$help = <<'HELP';
|
|
Add normally distributed (zero mean) random values to image channels.
|
|
Noise may be additive (uncorrelated) or multiplicative (correlated -
|
|
also known as speckle noise). For color images color channels may be
|
|
treated together or independently.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:noise-rgb');
|
|
$date = '2013';
|
|
|
|
@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 => 'independent', type => 'boolean',
|
|
desc => 'Noise in channels independent' },
|
|
{ name => 'correlated', type => 'boolean',
|
|
desc => 'Noise correlated (i.e. multiplicative not additive)' },
|
|
{ name => 'noise_1', type => '0.0 <= double <= 1.0',
|
|
desc => 'Noise in the first channel (red, gray)' },
|
|
{ name => 'noise_2', type => '0.0 <= double <= 1.0',
|
|
desc => 'Noise in the second channel (green, gray_alpha)' },
|
|
{ name => 'noise_3', type => '0.0 <= double <= 1.0',
|
|
desc => 'Noise in the third channel (blue)' },
|
|
{ name => 'noise_4', type => '0.0 <= double <= 1.0',
|
|
desc => 'Noise in the fourth channel (alpha)' }
|
|
);
|
|
|
|
%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;
|
|
gdouble r, g, b, a;
|
|
|
|
if (gimp_drawable_is_gray (drawable))
|
|
{
|
|
r = noise_1;
|
|
g = noise_1;
|
|
b = noise_1;
|
|
a = noise_2;
|
|
}
|
|
else
|
|
{
|
|
r = noise_1;
|
|
g = noise_2;
|
|
b = noise_3;
|
|
a = noise_4;
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:noise-rgb",
|
|
"correlated", correlated,
|
|
"independent", independent,
|
|
"red", r,
|
|
"green", g,
|
|
"blue", b,
|
|
"alpha", a,
|
|
"seed", g_random_int (),
|
|
NULL);
|
|
|
|
node = wrap_in_gamma_cast (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "RGB Noise"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_ripple {
|
|
$blurb = 'Displace pixels in a ripple pattern';
|
|
|
|
$help = <<'HELP';
|
|
Ripples the pixels of the specified drawable.
|
|
Each row or column will be displaced a certain number
|
|
of pixels coinciding with the given wave form.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:ripple');
|
|
$date = '2018';
|
|
|
|
@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 => 'period', type => ' 0.0 < double < 1000.0',
|
|
default => 200.0, desc => 'Period: number of pixels for one wave to complete' },
|
|
{ name => 'amplitude', type => ' 0.0 < double < 1000.0',
|
|
default => 25.0, desc => 'Amplitude: maximum displacement of wave' },
|
|
{ name => 'orientation', type => '0 <= int32 <= 1',
|
|
desc => 'Orientation { ORIENTATION-HORIZONTAL (0), ORIENTATION-VERTICAL (1) }' },
|
|
{ name => 'edges', type => '0 <= int32 <= 2',
|
|
desc => 'Edges { SMEAR (0), WRAP (1), BLANK (2) }' },
|
|
{ name => 'waveform', type => '0 <= int32 <= 1',
|
|
desc => 'Waveform { SAWTOOTH (0), SINE (1) }' },
|
|
{ name => 'antialias', type => 'boolean',
|
|
desc => 'Antialias { TRUE, FALSE }' },
|
|
{ name => 'tile', type => 'boolean',
|
|
desc => 'Tileable { TRUE, FALSE }' }
|
|
);
|
|
|
|
%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;
|
|
gdouble angle, phi;
|
|
|
|
angle = orientation ? 0.0 : 90.0;
|
|
phi = waveform ? 0.0 : 0.75;
|
|
if (orientation == 0 && waveform == 1)
|
|
phi = 0.5;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:ripple",
|
|
"amplitude", amplitude,
|
|
"period", period,
|
|
"phi", phi,
|
|
"angle", angle,
|
|
"sampler_type", antialias ? GEGL_SAMPLER_CUBIC : GEGL_SAMPLER_NEAREST,
|
|
"wave_type", waveform ? 0 : 1,
|
|
"abyss_policy", edges == 0 ? GEGL_ABYSS_CLAMP :
|
|
edges == 1 ? GEGL_ABYSS_LOOP :
|
|
GEGL_ABYSS_NONE,
|
|
"tileable", tile ? TRUE : FALSE,
|
|
NULL);
|
|
|
|
node = wrap_in_gamma_cast (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Ripple"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
{
|
|
success = FALSE;
|
|
}
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_rotate {
|
|
$blurb = 'Rotates a layer or the whole image by 90, 180 or 270 degrees';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in does rotate the active layer or the whole image clockwise
|
|
by multiples of 90 degrees. When the whole image is chosen, the image
|
|
is resized if necessary.
|
|
HELP
|
|
|
|
&neo_pdb_misc;
|
|
$date = '2014';
|
|
|
|
@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 => 'angle', type => '1 <= int32 <= 3',
|
|
desc => 'Angle { 90 (1), 180 (2), 270 (3) } degrees' },
|
|
{ name => 'everything', type => 'boolean',
|
|
desc => 'Rotate the whole image' }
|
|
);
|
|
|
|
%invoke = (
|
|
code => <<'CODE'
|
|
{
|
|
GimpRotationType rotate_type = angle - 1;
|
|
|
|
if (everything)
|
|
{
|
|
gimp_image_rotate (image, context, rotate_type, progress);
|
|
}
|
|
else if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
|
|
GIMP_PDB_ITEM_CONTENT, error))
|
|
{
|
|
GimpItem *item = GIMP_ITEM (drawable);
|
|
gint off_x, off_y;
|
|
gdouble center_x, center_y;
|
|
|
|
gimp_item_get_offset (item, &off_x, &off_y);
|
|
|
|
center_x = ((gdouble) off_x + (gdouble) gimp_item_get_width (item) / 2.0);
|
|
center_y = ((gdouble) off_y + (gdouble) gimp_item_get_height (item) / 2.0);
|
|
|
|
gimp_item_rotate (item, context, rotate_type, center_x, center_y,
|
|
GIMP_IS_CHANNEL (drawable));
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_noisify {
|
|
$blurb = 'Adds random noise to image channels';
|
|
|
|
$help = <<'HELP';
|
|
Add normally distributed random values to image channels. For color
|
|
images each color channel may be treated together or independently.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:noise-rgb');
|
|
$date = '2013';
|
|
|
|
@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 => 'independent', type => 'boolean',
|
|
desc => 'Noise in channels independent' },
|
|
{ name => 'noise_1', type => '0.0 <= double <= 1.0',
|
|
desc => 'Noise in the first channel (red, gray)' },
|
|
{ name => 'noise_2', type => '0.0 <= double <= 1.0',
|
|
desc => 'Noise in the second channel (green, gray_alpha)' },
|
|
{ name => 'noise_3', type => '0.0 <= double <= 1.0',
|
|
desc => 'Noise in the third channel (blue)' },
|
|
{ name => 'noise_4', type => '0.0 <= double <= 1.0',
|
|
desc => 'Noise in the fourth channel (alpha)' }
|
|
);
|
|
|
|
%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;
|
|
gdouble r, g, b, a;
|
|
|
|
if (gimp_drawable_is_gray (drawable))
|
|
{
|
|
r = noise_1;
|
|
g = noise_1;
|
|
b = noise_1;
|
|
a = noise_2;
|
|
}
|
|
else
|
|
{
|
|
r = noise_1;
|
|
g = noise_2;
|
|
b = noise_3;
|
|
a = noise_4;
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:noise-rgb",
|
|
"correlated", FALSE,
|
|
"independent", independent,
|
|
"red", r,
|
|
"green", g,
|
|
"blue", b,
|
|
"alpha", a,
|
|
"seed", g_random_int (),
|
|
NULL);
|
|
|
|
node = wrap_in_gamma_cast (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Noisify"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_sel_gauss {
|
|
$blurb = 'Blur neighboring pixels, but only in low-contrast areas';
|
|
|
|
$help = <<'HELP';
|
|
This filter functions similar to the regular gaussian blur filter
|
|
except that neighbouring pixels that differ more than the given
|
|
maxdelta parameter will not be blended with. This way with the correct
|
|
parameters, an image can be smoothed out without losing
|
|
details. However, this filter can be rather slow.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:gaussian-blur-selective');
|
|
$date = '2099';
|
|
|
|
@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 => '1.0 <= double <= 1000.0',
|
|
desc => 'Radius of gaussian blur (in pixels)' },
|
|
{ name => 'max_delta', type => '0 <= int32 <= 255',
|
|
desc => 'Maximum delta' }
|
|
);
|
|
|
|
%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;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:gaussian-blur-selective",
|
|
"blur-radius", radius,
|
|
"max-delta", (gdouble) max_delta / 255.0,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Selective Gaussian Blur"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_semiflatten {
|
|
$blurb = 'Replace partial transparency with the current background color';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in flattens pixels in an RGBA image that aren't completely
|
|
transparent against the current GIMP background color.
|
|
HELP
|
|
|
|
&std_pdb_misc;
|
|
$date = '1997';
|
|
|
|
@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' }
|
|
);
|
|
|
|
%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) &&
|
|
gimp_drawable_has_alpha (drawable))
|
|
{
|
|
GeglNode *node;
|
|
GeglColor *color;
|
|
|
|
color = gimp_context_get_background (context);
|
|
|
|
node =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gimp:semi-flatten",
|
|
"color", color,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Semi-Flatten"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_shift {
|
|
$blurb = 'Shift each row or column of pixels by a random amount';
|
|
|
|
$help = <<'HELP';
|
|
Shifts the pixels of the specified drawable. Each row or column will
|
|
be displaced a random value of pixels.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:shift');
|
|
$date = '2013';
|
|
|
|
@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 => 'shift_amount', type => '0 <= int32 <= 200',
|
|
desc => 'Shift amount' },
|
|
{ name => 'orientation', type => '0 <= int32 <= 1',
|
|
desc => 'Orientation { ORIENTATION-VERTICAL (0), ORIENTATION-HORIZONTAL (1) }' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:shift",
|
|
"shift", shift_amount / 2,
|
|
"direction", orientation ? 0 : 1,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Shift"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_sinus {
|
|
$blurb = 'Generate complex sinusoidal textures';
|
|
$help = 'FIXME: sinus help',
|
|
|
|
&std_pdb_compat('gegl:sinus');
|
|
$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 => 'xscale', type => '0.0001 <= double <= 100.0',
|
|
desc => 'Scale value for x axis' },
|
|
{ name => 'yscale', type => '0.0001 <= double <= 100.0',
|
|
desc => 'Scale value for y axis' },
|
|
{ name => 'complex', type => '0 <= double',
|
|
desc => 'Complexity factor' },
|
|
{ name => 'seed', type => '0 <= int32',
|
|
desc => 'Seed value for random number generator' },
|
|
{ name => 'tiling', type => 'boolean',
|
|
desc => 'If set, the pattern generated will tile' },
|
|
{ name => 'perturb', type => 'boolean',
|
|
desc => 'If set, the pattern is a little more distorted...' },
|
|
{ name => 'colors', type => '0 <= int32 <=2',
|
|
desc => 'where to take the colors (0=B&W, 1=fg/bg, 2=col1/col2)' },
|
|
{ name => 'col1', type => 'geglcolor',
|
|
desc => 'fist color (sometimes unused)' },
|
|
{ name => 'col2', type => 'geglcolor',
|
|
desc => 'second color (sometimes unused)' },
|
|
{ name => 'alpha1', type => '0 <= double <= 1',
|
|
desc => 'alpha for the first color (used if the drawable has an alpha channel)' },
|
|
{ name => 'alpha2', type => '0 <= double <= 1',
|
|
desc => 'alpha for the second color (used if the drawable has an alpha channel)' },
|
|
{ name => 'blend', type => '0 <= int32 <= 2',
|
|
desc => '0=linear, 1=bilinear, 2=sinusoidal' },
|
|
{ name => 'blend_power', type => 'double',
|
|
desc => 'Power used to stretch the blend' }
|
|
);
|
|
|
|
%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;
|
|
GeglColor *gegl_color1 = NULL;
|
|
GeglColor *gegl_color2 = NULL;
|
|
gint x, y, width, height;
|
|
|
|
switch (colors)
|
|
{
|
|
case 0:
|
|
gegl_color1 = gegl_color_new ("black");
|
|
gegl_color2 = gegl_color_new ("white");
|
|
break;
|
|
|
|
case 1:
|
|
gegl_color1 = gegl_color_duplicate (gimp_context_get_foreground (context));
|
|
gegl_color2 = gegl_color_duplicate (gimp_context_get_background (context));
|
|
break;
|
|
}
|
|
|
|
if (gegl_color1 == NULL)
|
|
{
|
|
gegl_color1 = gegl_color_duplicate (col1);
|
|
gegl_color2 = gegl_color_duplicate (col2);
|
|
}
|
|
gimp_color_set_alpha (gegl_color1, alpha1);
|
|
gimp_color_set_alpha (gegl_color2, alpha2);
|
|
|
|
gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:sinus",
|
|
"x_scale", xscale,
|
|
"y-scale", yscale,
|
|
"complexity", complex,
|
|
"seed", seed,
|
|
"tiling", tiling,
|
|
"perturbation", perturb,
|
|
"color1", gegl_color1,
|
|
"color2", gegl_color2,
|
|
"blend-mode", blend,
|
|
"blend-power", blend_power,
|
|
"width", width,
|
|
"height", height,
|
|
NULL);
|
|
|
|
g_object_unref (gegl_color1);
|
|
g_object_unref (gegl_color2);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Sinus"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_sobel {
|
|
$blurb = 'Specialized direction-dependent edge detection';
|
|
|
|
$help = <<'HELP';
|
|
This plug-in calculates the gradient with a sobel operator. The user
|
|
can specify which direction to use. When both directions are used, the
|
|
result is the RMS of the two gradients; if only one direction is used,
|
|
the result either the absolute value of the gradient, or 127 +
|
|
gradient (if the 'keep sign' switch is on). This way, information
|
|
about the direction of the gradient is preserved. Resulting images are
|
|
not autoscaled."
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:edge-sobel');
|
|
$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 => 'boolean',
|
|
desc => 'Sobel in horizontal direction' },
|
|
{ name => 'vertical', type => 'boolean',
|
|
desc => 'Sobel in vertical direction' },
|
|
{ name => 'keep_sign', type => 'boolean',
|
|
desc => 'Keep sign of result (one direction only)' },
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:edge-sobel",
|
|
"horizontal", horizontal,
|
|
"vertical", vertical,
|
|
"keep-sign", keep_sign,
|
|
NULL);
|
|
|
|
node = wrap_in_gamma_cast (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Sobel"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_softglow {
|
|
$blurb = 'Simulate glow by making highlights intense and fuzzy';
|
|
|
|
$help = <<'HELP';
|
|
Gives an image a softglow effect by intensifying the highlights in the
|
|
image. This is done by screening a modified version of the drawable
|
|
with itself. The modified version is desaturated and then a sigmoidal
|
|
transfer function is applied to force the distribution of intensities
|
|
into very small and very large only. This desaturated version is then
|
|
blurred to give it a fuzzy 'vaseline-on-the-lens' effect. The glow
|
|
radius parameter controls the sharpness of the glow effect. The
|
|
brightness parameter controls the degree of intensification applied to
|
|
image highlights. The sharpness parameter controls how defined or
|
|
alternatively, diffuse, the glow effect should be.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:softglow');
|
|
$date = '2019';
|
|
|
|
@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 => 'glow_radius', type => '1.0 <= double <= 50.0',
|
|
desc => 'Glow radius in pixels' },
|
|
{ name => 'brightness', type => '0.0 <= double <= 1.0',
|
|
desc => 'Glow brightness' },
|
|
{ name => 'sharpness', type => '0.0 <= double <= 1.0',
|
|
desc => 'Glow sharpness' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:softglow",
|
|
"glow-radius", glow_radius,
|
|
"brightness", brightness,
|
|
"sharpness", sharpness,
|
|
NULL);
|
|
|
|
node = wrap_in_gamma_cast (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Softglow"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_solid_noise {
|
|
$blurb = 'Create a random cloud-like texture';
|
|
|
|
$help = <<'HELP';
|
|
Generates 2D textures using Perlin's classic solid noise function.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:noise-solid');
|
|
$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 => 'tileable', type => 'boolean',
|
|
desc => 'Create a tileable output' },
|
|
{ name => 'turbulent', type => 'boolean',
|
|
desc => 'Make a turbulent noise' },
|
|
{ name => 'seed', type => 'int32',
|
|
desc => 'Random seed' },
|
|
{ name => 'detail', type => '0 <= int32 <= 15',
|
|
desc => 'Detail level' },
|
|
{ name => 'xsize', type => '0.1 <= double <= 16.0',
|
|
desc => 'Horizontal texture size' },
|
|
{ name => 'ysize', type => '0.1 <= double <= 16.0',
|
|
desc => 'Vertical texture size' }
|
|
);
|
|
|
|
%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;
|
|
gint x, y, width, height;
|
|
|
|
gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &width, &height);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:noise-solid",
|
|
"x-size", xsize,
|
|
"y-size", ysize,
|
|
"detail", detail,
|
|
"tileable", tileable,
|
|
"turbulent", turbulent,
|
|
"seed", seed,
|
|
"width", width,
|
|
"height", height,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Solid Noise"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_spread {
|
|
$blurb = 'Move pixels around randomly';
|
|
|
|
$help = <<'HELP';
|
|
Spreads the pixels of the specified drawable. Pixels are randomly
|
|
moved to another location whose distance varies from the original by
|
|
the horizontal and vertical spread amounts.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:noise-spread');
|
|
$date = '2013';
|
|
|
|
@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 => 'spread_amount_x', type => '0 <= double <= 512',
|
|
desc => 'Horizontal spread amount' },
|
|
{ name => 'spread_amount_y', type => '0 <= double <= 512',
|
|
desc => 'Vertical spread amount' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:noise-spread",
|
|
"amount-x", (gint) spread_amount_x,
|
|
"amount-y", (gint) spread_amount_y,
|
|
"seed", g_random_int (),
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Spread"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_threshold_alpha {
|
|
$blurb = 'Make transparency all-or-nothing';
|
|
|
|
$help = <<'HELP';
|
|
Make transparency all-or-nothing.
|
|
HELP
|
|
|
|
&std_pdb_misc;
|
|
$date = '1997';
|
|
|
|
@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 => 'threshold', type => '0 <= int32 <= 255',
|
|
desc => 'Threshold' }
|
|
);
|
|
|
|
%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) &&
|
|
gimp_drawable_has_alpha (drawable))
|
|
{
|
|
GeglNode *node =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gimp:threshold-alpha",
|
|
"value", threshold / 255.0,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Threshold Alpha"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_unsharp_mask {
|
|
$blurb = "The most widely useful method for sharpening an image";
|
|
|
|
$help = <<'HELP';
|
|
The unsharp mask is a sharpening filter that works by comparing using
|
|
the difference of the image and a blurred version of the image. It is
|
|
commonly used on photographic images, and is provides a much more
|
|
pleasing result than the standard sharpen filter.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:unsharp-mask');
|
|
$date = '2018';
|
|
|
|
@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 <= double <= 300.0',
|
|
desc => 'Radius of gaussian blur' },
|
|
{ name => 'amount', type => '0.0 <= double <= 300.0',
|
|
desc => 'Strength of effect' },
|
|
{ name => 'threshold', type => '0 <= int32 <= 255',
|
|
desc => 'Threshold' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:unsharp-mask",
|
|
"std-dev", radius,
|
|
"scale", amount,
|
|
"threshold", threshold / 255.0,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Sharpen (Unsharp Mask)"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_video {
|
|
$blurb = 'Simulate distortion produced by a fuzzy or low-res monitor';
|
|
|
|
$help = <<'HELP';
|
|
This function simulates the degradation of being on an old
|
|
low-dotpitch RGB video monitor to the specified drawable.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:video-degradation');
|
|
$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 => 'pattern_number', type => '0 <= int32 <= 8',
|
|
desc => 'Type of RGB pattern to use' },
|
|
{ name => 'additive', type => 'boolean',
|
|
desc => 'Whether the function adds the result to the original image' },
|
|
{ name => 'rotated', type => 'boolean',
|
|
desc => 'Whether to rotate the RGB pattern by ninety degrees' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:video-degradation",
|
|
"pattern", pattern_number,
|
|
"additive", additive,
|
|
"rotated", rotated,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Video"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_vinvert {
|
|
$blurb = 'Invert the brightness of each pixel';
|
|
|
|
$help = <<'HELP';
|
|
This function takes an indexed/RGB image and inverts its 'value' in
|
|
HSV space. The upshot of this is that the color and saturation at any
|
|
given point remains the same, but its brightness is effectively
|
|
inverted. Quite strange. Sometimes produces unpleasant color
|
|
artifacts on images from lossy sources (ie. JPEG).
|
|
HELP
|
|
|
|
&std_pdb_misc;
|
|
$date = '1997';
|
|
|
|
@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' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:value-invert",
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Value Invert"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_vpropagate {
|
|
$blurb = 'Propagate certain colors to neighboring pixels',
|
|
|
|
$help = <<'HELP';
|
|
Propagate values of the layer.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:value-propagate');
|
|
$date = '2015';
|
|
|
|
@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 => 'propagate_mode', type => '0 <= int32 <= 7',
|
|
desc => 'Propagate mode { 0:white, 1:black, 2:middle value 3:foreground to peak, 4:foreground, 5:background, 6:opaque, 7:transparent }' },
|
|
{ name => 'propagating_channel', type => 'int32',
|
|
desc => 'Channels which values are propagated' },
|
|
{ name => 'propagating_rate', type => '0.0 <= double <= 1.0',
|
|
desc => 'Propagating rate' },
|
|
{ name => 'direction_mask', type => '0 <= int32 <= 15',
|
|
desc => 'Direction mask' },
|
|
{ name => 'lower_limit', type => '0 <= int32 <= 255',
|
|
desc => 'Lower limit' },
|
|
{ name => 'upper_limit', type => '0 <= int32 <= 255',
|
|
desc => 'Upper limit' }
|
|
);
|
|
|
|
%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;
|
|
GeglColor *color = NULL;
|
|
gint gegl_mode = 0;
|
|
gboolean to_left = (direction_mask & (0x1 << 0)) != 0;
|
|
gboolean to_top = (direction_mask & (0x1 << 1)) != 0;
|
|
gboolean to_right = (direction_mask & (0x1 << 2)) != 0;
|
|
gboolean to_bottom = (direction_mask & (0x1 << 3)) != 0;
|
|
gboolean value = (propagating_channel & (0x1 << 0)) != 0;
|
|
gboolean alpha = (propagating_channel & (0x1 << 1)) != 0;
|
|
|
|
switch (propagate_mode)
|
|
{
|
|
case 0:
|
|
case 1:
|
|
case 2:
|
|
gegl_mode = propagate_mode;
|
|
break;
|
|
|
|
case 3:
|
|
case 4:
|
|
case 5:
|
|
if (propagate_mode == 3 || propagate_mode == 4)
|
|
{
|
|
gegl_mode = propagate_mode;
|
|
|
|
color = gimp_context_get_foreground (context);
|
|
}
|
|
else
|
|
{
|
|
gegl_mode = 4;
|
|
|
|
color = gimp_context_get_background (context);
|
|
}
|
|
break;
|
|
|
|
case 6:
|
|
case 7:
|
|
gegl_mode = propagate_mode - 1;
|
|
break;
|
|
}
|
|
|
|
node =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:value-propagate",
|
|
"mode", gegl_mode,
|
|
"lower-threshold", (gdouble) lower_limit / 255.0,
|
|
"upper-threshold", (gdouble) upper_limit / 255.0,
|
|
"rate", propagating_rate,
|
|
"color", color,
|
|
"top", to_top,
|
|
"left", to_left,
|
|
"right", to_right,
|
|
"bottom", to_bottom,
|
|
"value", value,
|
|
"alpha", alpha,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Value Propagate"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_dilate {
|
|
$blurb = 'Grow lighter areas of the image',
|
|
|
|
$help = <<'HELP';
|
|
Dilate image.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:value-propagate');
|
|
$date = '2015';
|
|
|
|
@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 => 'propagate_mode', type => '0 <= int32 <= 7', dead => 1,
|
|
desc => 'Propagate mode { 0:white, 1:black, 2:middle value 3:foreground to peak, 4:foreground, 5:background, 6:opaque, 7:transparent }' },
|
|
{ name => 'propagating_channel', type => 'int32', dead => 1,
|
|
desc => 'Channels which values are propagated' },
|
|
{ name => 'propagating_rate', type => '0.0 <= double <= 1.0', dead => 1,
|
|
desc => 'Propagating rate' },
|
|
{ name => 'direction_mask', type => '0 <= int32 <= 15', dead => 1,
|
|
desc => 'Direction mask' },
|
|
{ name => 'lower_limit', type => '0 <= int32 <= 255', dead => 1,
|
|
desc => 'Lower limit' },
|
|
{ name => 'upper_limit', type => '0 <= int32 <= 255', dead => 1,
|
|
desc => 'Upper limit' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:value-propagate",
|
|
"mode", 0, /* GEGL_VALUE_PROPAGATE_MODE_WHITE */
|
|
"lower-threshold", 0.0,
|
|
"upper-threshold", 1.0,
|
|
"rate", 1.0,
|
|
"top", TRUE,
|
|
"left", TRUE,
|
|
"right", TRUE,
|
|
"bottom", TRUE,
|
|
"value", TRUE,
|
|
"alpha", FALSE,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Dilate"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_erode {
|
|
$blurb = 'Shrink lighter areas of the image',
|
|
|
|
$help = <<'HELP';
|
|
Erode image.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:value-propagate');
|
|
$date = '2015';
|
|
|
|
@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 => 'propagate_mode', type => '0 <= int32 <= 7', dead => 1,
|
|
desc => 'Propagate mode { 0:white, 1:black, 2:middle value 3:foreground to peak, 4:foreground, 5:background, 6:opaque, 7:transparent }' },
|
|
{ name => 'propagating_channel', type => 'int32', dead => 1,
|
|
desc => 'Channels which values are propagated' },
|
|
{ name => 'propagating_rate', type => '0.0 <= double <= 1.0', dead => 1,
|
|
desc => 'Propagating rate' },
|
|
{ name => 'direction_mask', type => '0 <= int32 <= 15', dead => 1,
|
|
desc => 'Direction mask' },
|
|
{ name => 'lower_limit', type => '0 <= int32 <= 255', dead => 1,
|
|
desc => 'Lower limit' },
|
|
{ name => 'upper_limit', type => '0 <= int32 <= 255', dead => 1,
|
|
desc => 'Upper limit' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:value-propagate",
|
|
"mode", 1, /* GEGL_VALUE_PROPAGATE_MODE_BLACK */
|
|
"lower-threshold", 0.0,
|
|
"upper-threshold", 1.0,
|
|
"rate", 1.0,
|
|
"top", TRUE,
|
|
"left", TRUE,
|
|
"right", TRUE,
|
|
"bottom", TRUE,
|
|
"value", TRUE,
|
|
"alpha", FALSE,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Erode"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_waves {
|
|
$blurb = 'Distort the image with waves';
|
|
|
|
$help = <<'HELP';
|
|
Distort the image with waves.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:waves');
|
|
$date = '2013';
|
|
|
|
@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 => 'amplitude', type => '0 <= double <= 101',
|
|
desc => 'The Amplitude of the Waves' },
|
|
{ name => 'phase', type => '-360 <= double <= 360',
|
|
desc => 'The Phase of the Waves' },
|
|
{ name => 'wavelength', type => '0.1 <= double <= 100',
|
|
desc => 'The Wavelength of the Waves' },
|
|
{ name => 'type', type => 'boolean',
|
|
desc => 'Type of waves: { 0 = smeared, 1 = black }' },
|
|
{ name => 'reflective', type => 'boolean', dead => 1,
|
|
desc => 'Use Reflection (not implemented)' }
|
|
);
|
|
|
|
%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;
|
|
gdouble width = gimp_item_get_width (GIMP_ITEM (drawable));
|
|
gdouble height = gimp_item_get_height (GIMP_ITEM (drawable));
|
|
gdouble aspect;
|
|
|
|
while (phase < 0)
|
|
phase += 360.0;
|
|
|
|
phase = fmod (phase, 360.0);
|
|
|
|
aspect = CLAMP (width / height, 0.1, 10.0);
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:waves",
|
|
"x", 0.5,
|
|
"y", 0.5,
|
|
"amplitude", amplitude,
|
|
"phi", (phase - 180.0) / 180.0,
|
|
"period", wavelength * 2.0,
|
|
"aspect", aspect,
|
|
"clamp", ! type,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Waves"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_whirl_pinch {
|
|
$blurb = 'Distort an image by whirling and pinching';
|
|
|
|
$help = <<'HELP';
|
|
Distorts the image by whirling and pinching, which are two common
|
|
center-based, circular distortions. Whirling is like projecting the
|
|
image onto the surface of water in a toilet and flushing. Pinching is
|
|
similar to projecting the image onto an elastic surface and pressing
|
|
or pulling on the center of the surface.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:whirl-pinch');
|
|
$date = '2013';
|
|
|
|
@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 => 'whirl', type => '-720 <= double <= 720',
|
|
desc => 'Whirl angle (degrees)' },
|
|
{ name => 'pinch', type => '-1 <= double <= 1',
|
|
desc => 'Pinch amount' },
|
|
{ name => 'radius', type => '0 <= double <= 2',
|
|
desc => 'Radius (1.0 is the largest circle that fits in the image, and 2.0 goes all the way to the corners)' }
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:whirl-pinch",
|
|
"whirl", whirl,
|
|
"pinch", pinch,
|
|
"radius", radius,
|
|
NULL);
|
|
|
|
node = wrap_in_selection_bounds (node, drawable);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Whirl and Pinch"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
sub plug_in_wind {
|
|
$blurb = 'Smear image to give windblown effect';
|
|
|
|
$help = <<'HELP';
|
|
Renders a wind effect.
|
|
HELP
|
|
|
|
&std_pdb_compat('gegl:wind');
|
|
$date = '2015';
|
|
|
|
@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 => 'threshold', type => '0 <= int32 <= 50',
|
|
desc => 'Controls where blending will be done' },
|
|
{ name => 'direction', type => '0 <= int32 <= 3',
|
|
desc => 'Wind direction { 0:left, 1:right, 2:top, 3:bottom }' },
|
|
{ name => 'strength', type => '1 <= int32 <= 100',
|
|
desc => 'Controls the extent of the blending' },
|
|
{ name => 'algorithm', type => '0 <= int32 <= 1',
|
|
desc => 'Algorithm { WIND (0), BLAST (1) }' },
|
|
{ name => 'edge', type => '0 <= int32 <= 2',
|
|
desc => 'Affected edge { BOTH (0), LEADING (1), TRAILING (2) }' },
|
|
);
|
|
|
|
%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 =
|
|
gegl_node_new_child (NULL,
|
|
"operation", "gegl:wind",
|
|
"threshold", threshold,
|
|
"direction", direction,
|
|
"strength", strength,
|
|
"style", algorithm,
|
|
"edge", edge,
|
|
NULL);
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Wind"),
|
|
node);
|
|
g_object_unref (node);
|
|
}
|
|
else
|
|
success = FALSE;
|
|
}
|
|
CODE
|
|
);
|
|
}
|
|
|
|
$extra{app}->{code} = <<'CODE';
|
|
static GeglNode *
|
|
wrap_in_graph (GeglNode *node)
|
|
{
|
|
GeglNode *new_node;
|
|
GeglNode *input;
|
|
GeglNode *output;
|
|
|
|
new_node = gegl_node_new ();
|
|
|
|
gegl_node_add_child (new_node, node);
|
|
g_object_unref (node);
|
|
|
|
gimp_gegl_node_set_underlying_operation (new_node, node);
|
|
|
|
input = gegl_node_get_input_proxy (new_node, "input");
|
|
output = gegl_node_get_output_proxy (new_node, "output");
|
|
|
|
gegl_node_link_many (input,
|
|
node,
|
|
output,
|
|
NULL);
|
|
|
|
return new_node;
|
|
}
|
|
|
|
static GeglNode *
|
|
wrap_in_selection_bounds (GeglNode *node,
|
|
GimpDrawable *drawable)
|
|
{
|
|
gint x, y;
|
|
gint width, height;
|
|
|
|
if (gimp_item_mask_intersect (GIMP_ITEM (drawable),
|
|
&x, &y, &width, &height))
|
|
{
|
|
GeglNode *new_node;
|
|
GeglNode *input;
|
|
GeglNode *output;
|
|
GeglNode *translate_before;
|
|
GeglNode *crop;
|
|
GeglNode *translate_after;
|
|
|
|
new_node = gegl_node_new ();
|
|
|
|
gegl_node_add_child (new_node, node);
|
|
g_object_unref (node);
|
|
|
|
gimp_gegl_node_set_underlying_operation (new_node, node);
|
|
|
|
input = gegl_node_get_input_proxy (new_node, "input");
|
|
output = gegl_node_get_output_proxy (new_node, "output");
|
|
|
|
translate_before = gegl_node_new_child (new_node,
|
|
"operation", "gegl:translate",
|
|
"x", (gdouble) -x,
|
|
"y", (gdouble) -y,
|
|
NULL);
|
|
crop = gegl_node_new_child (new_node,
|
|
"operation", "gegl:crop",
|
|
"width", (gdouble) width,
|
|
"height", (gdouble) height,
|
|
NULL);
|
|
translate_after = gegl_node_new_child (new_node,
|
|
"operation", "gegl:translate",
|
|
"x", (gdouble) x,
|
|
"y", (gdouble) y,
|
|
NULL);
|
|
|
|
gegl_node_link_many (input,
|
|
translate_before,
|
|
crop,
|
|
node,
|
|
translate_after,
|
|
output,
|
|
NULL);
|
|
|
|
return new_node;
|
|
}
|
|
else
|
|
{
|
|
return node;
|
|
}
|
|
}
|
|
|
|
static GeglNode *
|
|
wrap_in_gamma_cast (GeglNode *node,
|
|
GimpDrawable *drawable)
|
|
{
|
|
if (gimp_drawable_get_trc (drawable) != GIMP_TRC_LINEAR)
|
|
{
|
|
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),
|
|
GIMP_TRC_LINEAR),
|
|
babl_format_has_alpha (drawable_format),
|
|
babl_format_get_space (drawable_format));
|
|
|
|
new_node = gegl_node_new ();
|
|
|
|
gegl_node_add_child (new_node, node);
|
|
g_object_unref (node);
|
|
|
|
gimp_gegl_node_set_underlying_operation (new_node, 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", "gegl:cast-format",
|
|
"input-format", drawable_format,
|
|
"output-format", cast_format,
|
|
NULL);
|
|
cast_after = gegl_node_new_child (new_node,
|
|
"operation", "gegl: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 GeglNode *
|
|
create_buffer_source_node (GeglNode *parent,
|
|
GimpDrawable *drawable)
|
|
{
|
|
GeglNode *new_node;
|
|
GeglBuffer *buffer;
|
|
|
|
buffer = gimp_drawable_get_buffer (drawable);
|
|
g_object_ref (buffer);
|
|
new_node = gegl_node_new_child (parent,
|
|
"operation", "gegl:buffer-source",
|
|
"buffer", buffer,
|
|
NULL);
|
|
g_object_unref (buffer);
|
|
return new_node;
|
|
}
|
|
|
|
static gboolean
|
|
bump_map (GimpDrawable *drawable,
|
|
GimpDrawable *bump_map,
|
|
gdouble azimuth,
|
|
gdouble elevation,
|
|
gint depth,
|
|
gint offset_x,
|
|
gint offset_y,
|
|
gdouble waterlevel,
|
|
gdouble ambient,
|
|
gboolean compensate,
|
|
gboolean invert,
|
|
gint type,
|
|
gboolean tiled,
|
|
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 *graph;
|
|
GeglNode *node;
|
|
GeglNode *src_node;
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:bump-map",
|
|
"tiled", tiled,
|
|
"type", type,
|
|
"compensate", compensate,
|
|
"invert", invert,
|
|
"azimuth", azimuth,
|
|
"elevation", elevation,
|
|
"depth", depth,
|
|
"offset_x", offset_x,
|
|
"offset_y", offset_y,
|
|
"waterlevel", waterlevel,
|
|
"ambient", ambient,
|
|
NULL);
|
|
|
|
graph = wrap_in_graph (node);
|
|
|
|
src_node = create_buffer_source_node (graph, bump_map);
|
|
|
|
gegl_node_connect (src_node, "output", node, "aux");
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Bump Map"),
|
|
graph);
|
|
g_object_unref (graph);
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
displace (GimpDrawable *drawable,
|
|
gdouble amount_x,
|
|
gdouble amount_y,
|
|
gboolean do_x,
|
|
gboolean do_y,
|
|
GimpDrawable *displace_map_x,
|
|
GimpDrawable *displace_map_y,
|
|
gint displace_type,
|
|
gint displace_mode,
|
|
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))
|
|
{
|
|
if (do_x || do_y)
|
|
{
|
|
GeglNode *graph;
|
|
GeglNode *node;
|
|
GeglAbyssPolicy abyss_policy = GEGL_ABYSS_NONE;
|
|
|
|
switch (displace_type)
|
|
{
|
|
case 1:
|
|
abyss_policy = GEGL_ABYSS_LOOP;
|
|
break;
|
|
case 2:
|
|
abyss_policy = GEGL_ABYSS_CLAMP;
|
|
break;
|
|
case 3:
|
|
abyss_policy = GEGL_ABYSS_BLACK;
|
|
break;
|
|
}
|
|
|
|
node = gegl_node_new_child (NULL,
|
|
"operation", "gegl:displace",
|
|
"displace_mode", displace_mode,
|
|
"sampler_type", GEGL_SAMPLER_CUBIC,
|
|
"abyss_policy", abyss_policy,
|
|
"amount_x", amount_x,
|
|
"amount_y", amount_y,
|
|
NULL);
|
|
|
|
graph = wrap_in_graph (node);
|
|
|
|
if (do_x)
|
|
{
|
|
GeglNode *src_node;
|
|
src_node = create_buffer_source_node (graph, displace_map_x);
|
|
gegl_node_connect (src_node, "output", node, "aux");
|
|
}
|
|
|
|
if (do_y)
|
|
{
|
|
GeglNode *src_node;
|
|
src_node = create_buffer_source_node (graph, displace_map_y);
|
|
gegl_node_connect (src_node, "output", node, "aux2");
|
|
}
|
|
|
|
gimp_drawable_apply_operation (drawable, progress,
|
|
C_("undo-type", "Displace"),
|
|
graph);
|
|
g_object_unref (graph);
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
static gboolean
|
|
gaussian_blur (GimpDrawable *drawable,
|
|
gdouble horizontal,
|
|
gdouble vertical,
|
|
gint method,
|
|
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,
|
|
"std-dev-y", vertical,
|
|
"filter", method,
|
|
"abyss-policy", 1,
|
|
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 gint
|
|
newsprint_color_model (gint colorspace)
|
|
{
|
|
switch (colorspace)
|
|
{
|
|
case 0: return 1; /* black on white */
|
|
case 1: return 2; /* rgb */
|
|
case 2: return 3; /* cmyk */
|
|
case 3: return 1; /* black on white */
|
|
}
|
|
|
|
return 2;
|
|
}
|
|
|
|
static gint
|
|
newsprint_pattern (gint spotfn)
|
|
{
|
|
switch (spotfn)
|
|
{
|
|
case 0: return 1; /* circle */
|
|
case 1: return 0; /* line */
|
|
case 2: return 2; /* diamond */
|
|
case 3: return 4; /* ps circle */
|
|
case 4: return 2; /* FIXME postscript diamond */
|
|
}
|
|
|
|
return 1;
|
|
}
|
|
|
|
static gdouble
|
|
newsprint_angle (gdouble angle)
|
|
{
|
|
while (angle > 180.0)
|
|
angle -= 360.0;
|
|
|
|
while (angle < -180.0)
|
|
angle += 360.0;
|
|
|
|
return angle;
|
|
}
|
|
CODE
|
|
|
|
@headers = qw("libgimpbase/gimpbase.h"
|
|
"libgimpconfig/gimpconfig.h"
|
|
"libgimpmath/gimpmath.h"
|
|
"gegl/gimp-babl.h"
|
|
"gegl/gimp-gegl-utils.h"
|
|
"config/gimpcoreconfig.h"
|
|
"core/gimp.h"
|
|
"core/gimpchannel.h"
|
|
"core/gimpcontext.h"
|
|
"core/gimpdrawable-operation.h"
|
|
"core/gimpimage-crop.h"
|
|
"core/gimpimage-resize.h"
|
|
"core/gimpimage-rotate.h"
|
|
"core/gimpimage-undo.h"
|
|
"core/gimppickable.h"
|
|
"core/gimppickable-auto-shrink.h"
|
|
"gimppdberror.h"
|
|
"gimppdb-utils.h"
|
|
"gimp-intl.h");
|
|
|
|
@procs = qw(plug_in_alienmap2
|
|
plug_in_antialias
|
|
plug_in_apply_canvas
|
|
plug_in_applylens
|
|
plug_in_autocrop
|
|
plug_in_autocrop_layer
|
|
plug_in_autostretch_hsv
|
|
plug_in_bump_map
|
|
plug_in_bump_map_tiled
|
|
plug_in_c_astretch
|
|
plug_in_cartoon
|
|
plug_in_colors_channel_mixer
|
|
plug_in_colortoalpha
|
|
plug_in_convmatrix
|
|
plug_in_cubism
|
|
plug_in_deinterlace
|
|
plug_in_diffraction
|
|
plug_in_displace
|
|
plug_in_displace_polar
|
|
plug_in_dog
|
|
plug_in_edge
|
|
plug_in_emboss
|
|
plug_in_engrave
|
|
plug_in_exchange
|
|
plug_in_flarefx
|
|
plug_in_fractal_trace
|
|
plug_in_gauss
|
|
plug_in_glasstile
|
|
plug_in_hsv_noise
|
|
plug_in_illusion
|
|
plug_in_laplace
|
|
plug_in_lens_distortion
|
|
plug_in_make_seamless
|
|
plug_in_maze
|
|
plug_in_mblur
|
|
plug_in_mblur_inward
|
|
plug_in_median_blur
|
|
plug_in_mosaic
|
|
plug_in_neon
|
|
plug_in_newsprint
|
|
plug_in_normalize
|
|
plug_in_nova
|
|
plug_in_oilify
|
|
plug_in_oilify_enhanced
|
|
plug_in_papertile
|
|
plug_in_photocopy
|
|
plug_in_pixelize
|
|
plug_in_plasma
|
|
plug_in_polar_coords
|
|
plug_in_red_eye_removal
|
|
plug_in_randomize_hurl
|
|
plug_in_randomize_pick
|
|
plug_in_randomize_slur
|
|
plug_in_rgb_noise
|
|
plug_in_ripple
|
|
plug_in_rotate
|
|
plug_in_noisify
|
|
plug_in_sel_gauss
|
|
plug_in_semiflatten
|
|
plug_in_shift
|
|
plug_in_sinus
|
|
plug_in_sobel
|
|
plug_in_softglow
|
|
plug_in_solid_noise
|
|
plug_in_spread
|
|
plug_in_threshold_alpha
|
|
plug_in_unsharp_mask
|
|
plug_in_video
|
|
plug_in_vinvert
|
|
plug_in_vpropagate
|
|
plug_in_dilate
|
|
plug_in_erode
|
|
plug_in_waves
|
|
plug_in_whirl_pinch
|
|
plug_in_wind);
|
|
|
|
%exports = (app => [@procs], lib => []);
|
|
|
|
$desc = 'Plug-in Compat';
|
|
$doc_title = 'gimpplugincompat';
|
|
$doc_short_desc = 'Compatibility for removed plug-ins.';
|
|
$doc_long_desc = 'Functions that perform the operation of removed plug-ins using GEGL operations or other GIMP internal functions.';
|
|
|
|
1;
|