gimp/pdb/groups/plug_in_compat.pdb

5546 lines
179 KiB
Plaintext
Raw Normal View History

# 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>
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 <= float <= 20',
desc => 'Red/hue component frequency factor' },
{ name => 'redangle', type => '0 <= float <= 360',
desc => 'Red/hue component angle factor (0-360)' },
{ name => 'greenfrequency', type => '0 <= float <= 20',
desc => 'Green/saturation component frequency factor' },
{ name => 'greenangle', type => '0 <= float <= 360',
desc => 'Green/saturation component angle factor (0-360)' },
{ name => 'bluefrequency', type => '0 <= float <= 20',
desc => 'Blue/luminance component frequency factor' },
{ name => 'blueangle', type => '0 <= float <= 360',
desc => 'Blue/luminance component angle factor (0-360)' },
{ name => 'colormodel', type => '0 <= uchar <= 1',
desc => 'Color model { RGB-MODEL (0), HSL-MODEL (1) }' },
{ name => 'redmode', type => '0 <= uchar <= 1',
desc => 'Red/hue application mode { TRUE, FALSE }' },
{ name => 'greenmode', type => '0 <= uchar <= 1',
desc => 'Green/saturation application mode { TRUE, FALSE }' },
{ name => 'bluemode', type => '0 <= uchar <= 1',
desc => 'Blue/luminance application mode { 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 =
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 <= float <= 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))
{
GimpRGB color;
GeglColor *gegl_color;
GeglNode *node;
if (set_background)
gimp_context_get_background (context, &color);
else
gimp_rgba_set (&color, 0.0, 0.0, 0.0, 0.0);
gegl_color = gimp_gegl_color_new (&color, NULL);
node = gegl_node_new_child (NULL,
"operation", "gegl:apply-lens",
"refraction-index", refraction,
"keep-surroundings", keep_surroundings,
"background-color", gegl_color,
NULL);
g_object_unref (gegl_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 active layer based on empty borders of the input drawable';
$help = <<'HELP';
Crop the active layer 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 the cropped layer (the current active layer).
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))
{
GimpLayer *layer = gimp_image_get_active_layer (image);
gint x, y, width, height;
if (layer)
{
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"));
gimp_item_resize (GIMP_ITEM (layer),
context, GIMP_FILL_TRANSPARENT,
width, height, -x, -y);
gimp_image_undo_group_end (image);
break;
default:
break;
}
}
}
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 <= float <= 360.0',
desc => 'Azimuth' },
{ name => 'elevation', type => '0.5 <= float <= 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 <= float <= 1.0',
desc => 'Level that full transparency should represent' },
{ name => 'ambient', type => '0.0 <= float <= 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 <= float <= 360.0',
desc => 'Azimuth' },
{ name => 'elevation', type => '0.5 <= float <= 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 <= float <= 1.0',
desc => 'Level that full transparency should represent' },
{ name => 'ambient', type => '0.0 <= float <= 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 <= float <= 50.0',
desc => 'Cartoon mask radius (radius of pixel neighborhood)' },
{ name => 'pct_black', type => '0.0 <= float <= 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 <= float <= 2',
desc => 'Set the red gain for the red channel' },
{ name => 'rg_gain', type => '-2 <= float <= 2',
desc => 'Set the green gain for the red channel' },
{ name => 'rb_gain', type => '-2 <= float <= 2',
desc => 'Set the blue gain for the red channel' },
{ name => 'gr_gain', type => '-2 <= float <= 2',
desc => 'Set the red gain for the green channel' },
{ name => 'gg_gain', type => '-2 <= float <= 2',
desc => 'Set the green gain for the green channel' },
{ name => 'gb_gain', type => '-2 <= float <= 2',
desc => 'Set the blue gain for the green channel' },
{ name => 'br_gain', type => '-2 <= float <= 2',
desc => 'Set the red gain for the blue channel' },
{ name => 'bg_gain', type => '-2 <= float <= 2',
desc => 'Set the green gain for the blue channel' },
{ name => 'bb_gain', type => '-2 <= float <= 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 => 'color',
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 = gimp_gegl_color_new (&color, NULL);
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 => 'floatarray',
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 => 'float',
desc => 'Divisor' },
{ name => 'offset', type => 'float',
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"),
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"),
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 <= float <= 100.0',
desc => 'Average diameter of each tile (in pixels)' },
{ name => 'tile_saturation', type => '0.0 <= float <= 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))
{
GimpRGB color;
GeglColor *gegl_color;
GeglNode *node;
if (bg_color)
{
gimp_context_get_background (context, &color);
gimp_rgb_set_alpha (&color, 0.0);
}
else
{
gimp_rgba_set (&color, 0.0, 0.0, 0.0, 0.0);
}
gegl_color = gimp_gegl_color_new (&color, NULL);
node = gegl_node_new_child (NULL,
"operation", "gegl:cubism",
"tile-size", tile_size,
"tile-saturation", tile_saturation,
"bg-color", gegl_color,
NULL);
g_object_unref (gegl_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 <= float <= 20.0',
desc => 'Light frequency (red)' },
{ name => 'lam_g', type => '0.0 <= float <= 20.0',
desc => 'Light frequency (green)' },
{ name => 'lam_b', type => '0.0 <= float <= 20.0',
desc => 'Light frequency (blue)' },
{ name => 'contour_r', type => '0.0 <= float <= 10.0',
desc => 'Number of contours (red)' },
{ name => 'contour_g', type => '0.0 <= float <= 10.0',
desc => 'Number of contours (green)' },
{ name => 'contour_b', type => '0.0 <= float <= 10.0',
desc => 'Number of contours (blue)' },
{ name => 'edges_r', type => '0.0 <= float <= 1.0',
desc => 'Number of sharp edges (red)' },
{ name => 'edges_g', type => '0.0 <= float <= 1.0',
desc => 'Number of sharp edges (green)' },
{ name => 'edges_b', type => '0.0 <= float <= 1.0',
desc => 'Number of sharp edges (blue)' },
{ name => 'brightness', type => '0.0 <= float <= 1.0',
desc => 'Brightness and shifting/fattening of contours' },
{ name => 'scattering', type => '0.0 <= float <= 100.0',
desc => 'Scattering (Speed vs. quality)' },
{ name => 'polarization', type => '-1.0 <= float <= 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 <= float <= 500.0',
desc => 'Displace multiplier for x direction' },
{ name => 'amount_y', type => '-500.0 <= float <= 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 <= float <= 500.0',
desc => 'Displace multiplier for radial direction' },
{ name => 'amount_y', type => '-500.0 <= float <= 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 <= float <= 10.0',
desc => 'Radius of inner gaussian blur in pixels' },
{ name => 'outer', type => '0.0 <= float <= 10.0',
desc => 'Radius of outer gaussian blur in pixels' },
{ name => 'normalize', type => 'boolean',
desc => 'Normalize' },
{ name => 'invert', type => 'boolean',
desc => 'Invert' }
);
%invoke = (
code => <<'CODE'
{
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
GIMP_PDB_ITEM_CONTENT, error) &&
gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
{
GeglNode *node;
if (normalize || invert)
gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_MISC,
C_("undo-type", "DoG Edge Detect"));
node = gegl_node_new_child (NULL,
"operation", "gegl:difference-of-gaussians",
"radius1", inner * 0.32,
"radius2", outer * 0.32,
NULL);
node = wrap_in_gamma_cast (node, drawable);
gimp_drawable_apply_operation (drawable, progress,
C_("undo-type", "DoG Edge Detect"),
node);
g_object_unref (node);
if (normalize)
{
node = gegl_node_new_child (NULL,
"operation", "gegl:stretch-contrast",
"keep-colors", TRUE,
"perceptual", TRUE,
NULL);
gimp_drawable_apply_operation (drawable, progress,
C_("undo-type", "Normalize"),
node);
g_object_unref (node);
}
if (invert)
gimp_drawable_apply_operation_by_name (drawable, progress,
C_("undo-type", "Invert"),
"gegl:invert-gamma",
NULL);
if (normalize || invert)
gimp_image_undo_group_end (image);
}
else
success = FALSE;
}
CODE
);
}
sub plug_in_edge {
$blurb = 'Several simple methods for detecting edges';
$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 <= float <= 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 <= float <= 360.0',
desc => 'The Light Angle (degrees)' },
{ name => 'elevation', type => '0.0 <= float <= 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 => 'uchar',
desc => 'Red value (from)' },
{ name => 'from_green', type => 'uchar',
desc => 'Green value (from)' },
{ name => 'from_blue', type => 'uchar',
desc => 'Blue value (from)' },
{ name => 'to_red', type => 'uchar',
desc => 'Red value (to)' },
{ name => 'to_green', type => 'uchar',
desc => 'Green value (to)' },
{ name => 'to_blue', type => 'uchar',
desc => 'Blue value (to)' },
{ name => 'red_threshold', type => 'uchar',
desc => 'Red threshold' },
{ name => 'green_threshold', type => 'uchar',
desc => 'Green threshold' },
{ name => 'blue_threshold', type => 'uchar',
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))
{
GimpRGB from;
GimpRGB to;
GeglColor *gegl_from;
GeglColor *gegl_to;
GeglNode *node;
gimp_rgb_set_uchar (&from, from_red, from_green, from_blue);
gimp_rgb_set_uchar (&to, to_red, to_green, to_blue);
gegl_from = gimp_gegl_color_new (&from, NULL);
gegl_to = gimp_gegl_color_new (&to, NULL);
node = gegl_node_new_child (NULL,
"operation", "gegl:color-exchange",
"from-color", gegl_from,
"to-color", gegl_to,
"red-threshold", red_threshold / 255.0,
"green-threshold", green_threshold / 255.0,
"blue-threshold", blue_threshold / 255.0,
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 <= float <= 50.0',
desc => 'xmin fractal image delimiter' },
{ name => 'xmax', type => '-50.0 <= float <= 50.0',
desc => 'xmax fractal image delimiter' },
{ name => 'ymin', type => '-50.0 <= float <= 50.0',
desc => 'ymin fractal image delimiter' },
{ name => 'ymax', type => '-50.0 <= float <= 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 <= float <= 500.0',
desc => 'Horizontal radius of gaussian blur (in pixels' },
{ name => 'vertical', type => '0.0 <= float <= 500.0',
desc => 'Vertical radius of gaussian blur (in pixels' },
{ name => 'method', type => '0 <= int32 <= 1', dead => 1,
desc => 'Blur method { IIR (0), RLE (1) }' }
);
%invoke = (
code => <<'CODE'
{
success = gaussian_blur (drawable, horizontal, vertical, progress, error);
}
CODE
);
}
sub plug_in_gauss_iir {
$blurb = 'Apply a gaussian blur';
$help = <<'HELP';
Applies a gaussian blur to the drawable, with specified radius of affect.
The standard deviation of the normal distribution used to modify pixel
values is calculated based on the supplied radius. Horizontal and vertical
blurring can be independently invoked by specifying only one to run.
HELP
&std_pdb_compat('gegl:gaussian-blur');
$date = '2014';
@inargs = (
{ name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
desc => 'The run mode' },
{ name => 'image', type => 'image', dead => 1,
desc => 'Input image (unused)' },
{ name => 'drawable', type => 'drawable',
desc => 'Input drawable' },
{ name => 'radius', type => '0.0 <= float <= 500.0',
desc => 'Radius of gaussian blur (in pixels' },
{ name => 'horizontal', type => 'boolean',
desc => 'Blur in horizontal direction' },
{ name => 'vertical', type => 'boolean',
desc => 'Blur in vertical direction' }
);
%invoke = (
code => <<'CODE'
{
success = gaussian_blur (drawable,
horizontal ? radius : 0.0,
vertical ? radius : 0.0,
progress, error);
}
CODE
);
}
sub plug_in_gauss_iir2 {
$blurb = 'Apply a gaussian blur';
$help = <<'HELP';
Applies a gaussian blur to the drawable, with specified radius of affect.
The standard deviation of the normal distribution used to modify pixel
values is calculated based on the supplied radius. Horizontal and vertical
blurring can be independently invoked by specifying only one to run.
HELP
&std_pdb_compat('gegl:gaussian-blur');
$date = '2014';
@inargs = (
{ name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
desc => 'The run mode' },
{ name => 'image', type => 'image', dead => 1,
desc => 'Input image (unused)' },
{ name => 'drawable', type => 'drawable',
desc => 'Input drawable' },
{ name => 'horizontal', type => '0.0 <= float <= 500.0',
desc => 'Horizontal radius of gaussian blur (in pixels' },
{ name => 'vertical', type => '0.0 <= float <= 500.0',
desc => 'Vertical radius of gaussian blur (in pixels' },
);
%invoke = (
code => <<'CODE'
{
success = gaussian_blur (drawable, horizontal, vertical, progress, error);
}
CODE
);
}
sub plug_in_gauss_rle {
$blurb = 'Apply a gaussian blur';
$help = <<'HELP';
Applies a gaussian blur to the drawable, with specified radius of affect.
The standard deviation of the normal distribution used to modify pixel
values is calculated based on the supplied radius. Horizontal and vertical
blurring can be independently invoked by specifying only one to run.
HELP
&std_pdb_compat('gegl:gaussian-blur');
$date = '2014';
@inargs = (
{ name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
desc => 'The run mode' },
{ name => 'image', type => 'image', dead => 1,
desc => 'Input image (unused)' },
{ name => 'drawable', type => 'drawable',
desc => 'Input drawable' },
{ name => 'radius', type => '0.0 <= float <= 500.0',
desc => 'Radius of gaussian blur (in pixels' },
{ name => 'horizontal', type => 'boolean',
desc => 'Blur in horizontal direction' },
{ name => 'vertical', type => 'boolean',
desc => 'Blur in vertical direction' }
);
%invoke = (
code => <<'CODE'
{
success = gaussian_blur (drawable,
horizontal ? radius : 0.0,
vertical ? radius : 0.0,
progress, error);
}
CODE
);
}
sub plug_in_gauss_rle2 {
$blurb = 'Apply a gaussian blur';
$help = <<'HELP';
Applies a gaussian blur to the drawable, with specified radius of affect.
The standard deviation of the normal distribution used to modify pixel
values is calculated based on the supplied radius. Horizontal and vertical
blurring can be independently invoked by specifying only one to run.
HELP
&std_pdb_compat('gegl:gaussian-blur');
$date = '2014';
@inargs = (
{ name => 'run_mode', type => 'enum GimpRunMode', dead => 1,
desc => 'The run mode' },
{ name => 'image', type => 'image', dead => 1,
desc => 'Input image (unused)' },
{ name => 'drawable', type => 'drawable',
desc => 'Input drawable' },
{ name => 'horizontal', type => '0.0 <= float <= 500.0',
desc => 'Horizontal radius of gaussian blur (in pixels' },
{ name => 'vertical', type => '0.0 <= float <= 500.0',
desc => 'Vertical radius of gaussian blur (in pixels' },
);
%invoke = (
code => <<'CODE'
{
success = gaussian_blur (drawable, horizontal, vertical, progress, error);
}
CODE
);
}
sub plug_in_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_iir 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 <= float <= 100',
desc => 'Effect centre offset in X' },
{ name => 'offset_y', type => '-100 <= float <= 100',
desc => 'Effect centre offset in Y' },
{ name => 'main_adjust', type => '-100 <= float <= 100',
desc => 'Amount of second-order distortion' },
{ name => 'edge_adjust', type => '-100 <= float <= 100',
desc => 'Amount of fourth-order distortion' },
{ name => 'rescale', type => '-100 <= float <= 100',
desc => 'Rescale overall image size' },
{ name => 'brighten', type => '-100 <= float <= 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;
GimpRGB color;
GeglColor *gegl_color;
gimp_context_get_background (context, &color);
if (gimp_drawable_has_alpha (drawable))
{
gimp_rgb_set_alpha (&color, 0.0);
}
else
{
gimp_rgb_set_alpha (&color, 1.0);
}
gegl_color = gimp_gegl_color_new (&color, NULL);
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", gegl_color,
NULL);
g_object_unref (gegl_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 => '0 <= uchar <= 1',
desc => 'Tileable maze? (TRUE or FALSE)' },
{ name => 'algorithm', type => '0 <= uchar <= 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;
GimpRGB color;
gimp_context_get_foreground (context, &color);
fg_color = gimp_gegl_color_new (&color, NULL);
gimp_context_get_background (context, &color);
bg_color = gimp_gegl_color_new (&color, NULL);
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);
g_object_unref (fg_color);
g_object_unref (bg_color);
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, -cirular');
$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 => 'float',
desc => 'Length' },
{ name => 'angle', type => '0 <= float <= 360',
desc => 'Angle' },
{ name => 'center_x', type => 'float',
desc => 'Center X' },
{ name => 'center_y', type => 'float',
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, -cirular');
$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 => 'float',
desc => 'Length' },
{ name => 'angle', type => '0 <= float <= 360',
desc => 'Angle' },
{ name => 'center_x', type => 'float',
desc => 'Center X' },
{ name => 'center_y', type => 'float',
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_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 <= float <= 1000',
desc => 'Average diameter of each tile (in pixels)' },
{ name => 'tile_height', type => '1 <= float <= 1000',
desc => 'Apparent height of each tile (in pixels)' },
{ name => 'tile_spacing', type => '0.1 <= float <= 1000',
desc => 'Inter_tile spacing (in pixels)' },
{ name => 'tile_neatness', type => '0 <= float <= 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 <= float <= 360',
desc => 'Direction of light_source (in degrees)' },
{ name => 'color_variation', type => '0.0 <= float <= 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)
{
GimpRGB fgcolor, bgcolor;
gimp_context_get_background (context, &bgcolor);
bg_color = gimp_gegl_color_new (&bgcolor, NULL);
gimp_context_get_foreground (context, &fgcolor);
fg_color = gimp_gegl_color_new (&fgcolor, NULL);
}
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 <= float <= 1500.0',
desc => 'Radius of neon effect (in pixels)' },
{ name => 'amount', type => '0.0 <= float <= 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 <= float <= 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 <= float <= 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 <= float <= 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 <= float <= 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 => '0 <= 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 => 'color',
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))
{
GeglNode *node;
GeglColor *gegl_color = gimp_gegl_color_new (&color, NULL);
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));
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_to (src_node, "output", node, "aux");
}
if (exponent_map)
{
GeglNode *src_node;
src_node = create_buffer_source_node (graph, exponent_map);
gegl_node_connect_to (src_node, "output", node, "aux2");
}
gimp_drawable_apply_operation (drawable, progress,
C_("undo-type", "Oilify"),
graph);
g_object_unref (graph);
}
else
success = FALSE;
}
CODE
);
}
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 => 'int32',
desc => 'Tile size (pixels)' },
{ name => 'move_max', type => 'float',
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 => 'color',
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;
GimpRGB color;
GeglColor *gegl_color;
gint bg_type;
switch (background_type)
{
default:
bg_type = background_type;
gimp_rgba_set (&color, 0.0, 0.0, 1.0, 1.0);
break;
case 3:
bg_type = 3;
gimp_context_get_foreground (context, &color);
break;
case 4:
bg_type = 3;
gimp_context_get_background (context, &color);
break;
case 5:
bg_type = 3;
color = background_color;
break;
}
gegl_color = gimp_gegl_color_new (&color, NULL);
node = gegl_node_new_child (NULL,
"operation", "gegl:tile-paper",
"tile-width", tile_size,
"tile-height", tile_size,
"move-rate", move_max,
"bg-color", gegl_color,
"centering", centering,
"wrap-around", wrap_around,
"background-type", bg_type,
"fractional-type", fractional_type,
NULL);
g_object_unref (gegl_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 <= float <= 50.0',
desc => 'Photocopy mask radius (radius of pixel neighborhood)' },
{ name => 'sharpness', type => '0.0 <= float <= 1.0',
desc => 'Sharpness (detail level)' },
{ name => 'pct_black', type => '0.0 <= float <= 1.0',
desc => 'Percentage of darkened pixels to set to black' },
{ name => 'pct_white', type => '0.0 <= float <= 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 squares';
$help = <<'HELP';
Pixelize the contents of the specified drawable with specified
pixelizing width.
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 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_width,
NULL);
gimp_drawable_apply_operation (drawable, progress,
C_("undo-type", "Pixelize"),
node);
g_object_unref (node);
}
else
success = FALSE;
}
CODE
);
}
sub plug_in_pixelize2 {
$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 <= float <= 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))
{
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: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 <= float <= 100.0',
desc => 'Circle depth in %' },
{ name => 'angle', type => '0.0 <= float < 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 => '1.0 <= float <= 100.0',
desc => 'Randomization percentage' },
{ name => 'rndm_rcount', type => '1.0 <= float <= 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 <= float <= 100.0',
desc => 'Randomization percentage' },
{ name => 'rndm_rcount', type => '1.0 <= float <= 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 <= float <= 100.0',
desc => 'Randomization percentage' },
{ name => 'rndm_rcount', type => '1.0 <= float <= 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 <= float <= 1.0',
desc => 'Noise in the first channel (red, gray)' },
{ name => 'noise_2', type => '0.0 <= float <= 1.0',
desc => 'Noise in the second channel (green, gray_alpha)' },
{ name => 'noise_3', type => '0.0 <= float <= 1.0',
desc => 'Noise in the third channel (blue)' },
{ name => 'noise_4', type => '0.0 <= float <= 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 => 'int32',
desc => 'Period: number of pixels for one wave to complete' },
{ name => 'amplitude', type => 'int32',
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", (gdouble) amplitude,
"period", (gdouble) 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 <= float <= 1.0',
desc => 'Noise in the first channel (red, gray)' },
{ name => 'noise_2', type => '0.0 <= float <= 1.0',
desc => 'Noise in the second channel (green, gray_alpha)' },
{ name => 'noise_3', type => '0.0 <= float <= 1.0',
desc => 'Noise in the third channel (blue)' },
{ name => 'noise_4', type => '0.0 <= float <= 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 => '0.0 < float',
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;
GimpRGB color;
gimp_context_get_background (context, &color);
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 <= float',
desc => 'Scale value for x axis' },
{ name => 'yscale', type => '0 <= float',
desc => 'Scale value for y axis' },
{ name => 'complex', type => '0 <= float',
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 => 'color',
desc => 'fist color (sometimes unused)' },
{ name => 'col2', type => 'color',
desc => 'second color (sometimes unused)' },
{ name => 'alpha1', type => '0 <= float <= 1',
2018-04-27 02:46:32 +08:00
desc => 'alpha for the first color (used if the drawable has an alpha channel)' },
{ name => 'alpha2', type => '0 <= float <= 1',
2018-04-27 02:46:32 +08:00
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 => 'float',
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;
GeglColor *gegl_color2;
gint x, y, width, height;
switch (colors)
{
case 0:
gimp_rgb_set (&col1, 0.0, 0.0, 0.0);
gimp_rgb_set (&col2, 1.0, 1.0, 1.0);
break;
case 1:
gimp_context_get_foreground (context, &col1);
gimp_context_get_background (context, &col2);
break;
}
gimp_rgb_set_alpha (&col1, alpha1);
gimp_rgb_set_alpha (&col2, alpha2);
gegl_color1 = gimp_gegl_color_new (&col1, NULL);
gegl_color2 = gimp_gegl_color_new (&col2, NULL);
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 => '0 <= float',
desc => 'Glow radius in pixels' },
{ name => 'brightness', type => '0.0 <= float <= 1.0',
desc => 'Glow brightness' },
{ name => 'sharpness', type => '0.0 <= float <= 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 => 'float',
desc => 'Horizontal texture size' },
{ name => 'ysize', type => 'float',
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 <= float <= 200',
desc => 'Horizontal spread amount' },
{ name => 'spread_amount_y', type => '0 <= float <= 200',
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 <= float <= 300.0',
desc => 'Radius of gaussian blur' },
{ name => 'amount', type => '0.0 <= float <= 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 <= float <= 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;
GimpRGB color;
GeglColor *gegl_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;
gimp_context_get_foreground (context, &color);
}
else
{
gegl_mode = 4;
gimp_context_get_background (context, &color);
}
gegl_color = gimp_gegl_color_new (&color, NULL);
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", gegl_color,
"top", to_top,
"left", to_left,
"right", to_right,
"bottom", to_bottom,
"value", value,
"alpha", alpha,
NULL);
if (gegl_color)
g_object_unref (gegl_color);
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 <= float <= 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 <= float <= 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 <= float <= 101',
desc => 'The Amplitude of the Waves' },
{ name => 'phase', type => '-360 <= float <= 360',
desc => 'The Phase of the Waves' },
{ name => 'wavelength', type => '0.1 <= float <= 50',
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 <= float <= 720',
desc => 'Whirl angle (degrees)' },
{ name => 'pinch', type => '-1 <= float <= 1',
desc => 'Pinch amount' },
{ name => 'radius', type => '0 <= float <= 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)
{
Initial space invasion commit in GIMP All babl formats now have a space equivalent to a color profile, determining the format's primaries and TRCs. This commit makes GIMP aware of this. libgimp: - enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA as deprecated aliases, add PERCEPTUAL values so we now have LINEAR, NON_LINEAR and PERCPTUAL for each encoding, matching the babl encoding variants RGB, R'G'B' and R~G~B~. - gimp_color_transform_can_gegl_copy() now returns TRUE if both profiles can return a babl space, increasing the amount of fast babl color conversions significantly. - TODO: no solution yet for getting libgimp drawable proxy buffers in the right format with space. plug-ins: - follow the GimpPrecision change. - TODO: everything else unchanged and partly broken or sub-optimal, like setting a new image's color profile too late. app: - add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as replacement for all "linear" booleans. - change gimp-babl functions to take babl spaces and GimpTRCType parameters and support all sorts of new perceptual ~ formats. - a lot of places changed in the early days of goat invasion didn't take advantage of gimp-babl utility functions and constructed formats manually. They all needed revisiting and many now use much simpler code calling gimp-babl API. - change gimp_babl_format_get_color_profile() to really extract a newly allocated color profile from the format, and add gimp_babl_get_builtin_color_profile() which does the same as gimp_babl_format_get_color_profile() did before. Visited all callers to decide whether they are looking for the format's actual profile, or for one of the builtin profiles, simplifying code that only needs builtin profiles. - drawables have a new get_space_api(), get_linear() is now get_trc(). - images now have a "layer space" and an API to get it, gimp_image_get_layer_format() returns formats in that space. - an image's layer space is created from the image's color profile, change gimpimage-color-profile to deal with that correctly - change many babl_format() calls to babl_format_with_space() and take the space from passed formats or drawables - add function gimp_layer_fix_format_space() which replaces the layer's buffer with one that has the image's layer format, but doesn't change pixel values - use gimp_layer_fix_format_space() to make sure layers loaded from XCF and created by plug-ins have the right space when added to the image, because it's impossible to always assign the right space upon layer creation - "assign color profile" and "discard color profile" now require use of gimp_layer_fix_format_space() too because the profile is now embedded in all formats via the space. Add gimp_image_assign_color_profile() which does all that and call it instead of a simple gimp_image_set_color_profile(), also from the PDB set-color-profile functions, which are essentially "assign" and "discard" calls. - generally, make sure a new image's color profile is set before adding layers to it, gimp_image_set_color_profile() is more than before considered know-what-you-are-doing API. - take special precaution in all places that call gimp_drawable_convert_type(), we now must pass a new_profile from all callers that convert layers within the same image (such as image_convert_type, image_convert_precision), because the layer's new space can't be determined from the image's layer format during the call. - change all "linear" properties to "trc", in all config objects like for levels and curves, in the histogram, in the widgets. This results in some GUI that now has three choices instead of two. TODO: we might want to reduce that back to two later. - keep "linear" boolean properties around as compat if needed for file pasring, but always convert the parsed parsed boolean to GimpTRCType. - TODO: the image's "enable color management" switch is currently broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
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),
Initial space invasion commit in GIMP All babl formats now have a space equivalent to a color profile, determining the format's primaries and TRCs. This commit makes GIMP aware of this. libgimp: - enum GimpPrecision: rename GAMMA values to NON_LINEAR and keep GAMMA as deprecated aliases, add PERCEPTUAL values so we now have LINEAR, NON_LINEAR and PERCPTUAL for each encoding, matching the babl encoding variants RGB, R'G'B' and R~G~B~. - gimp_color_transform_can_gegl_copy() now returns TRUE if both profiles can return a babl space, increasing the amount of fast babl color conversions significantly. - TODO: no solution yet for getting libgimp drawable proxy buffers in the right format with space. plug-ins: - follow the GimpPrecision change. - TODO: everything else unchanged and partly broken or sub-optimal, like setting a new image's color profile too late. app: - add enum GimpTRCType { LINEAR, NON_LINEAR, PERCEPTUAL } as replacement for all "linear" booleans. - change gimp-babl functions to take babl spaces and GimpTRCType parameters and support all sorts of new perceptual ~ formats. - a lot of places changed in the early days of goat invasion didn't take advantage of gimp-babl utility functions and constructed formats manually. They all needed revisiting and many now use much simpler code calling gimp-babl API. - change gimp_babl_format_get_color_profile() to really extract a newly allocated color profile from the format, and add gimp_babl_get_builtin_color_profile() which does the same as gimp_babl_format_get_color_profile() did before. Visited all callers to decide whether they are looking for the format's actual profile, or for one of the builtin profiles, simplifying code that only needs builtin profiles. - drawables have a new get_space_api(), get_linear() is now get_trc(). - images now have a "layer space" and an API to get it, gimp_image_get_layer_format() returns formats in that space. - an image's layer space is created from the image's color profile, change gimpimage-color-profile to deal with that correctly - change many babl_format() calls to babl_format_with_space() and take the space from passed formats or drawables - add function gimp_layer_fix_format_space() which replaces the layer's buffer with one that has the image's layer format, but doesn't change pixel values - use gimp_layer_fix_format_space() to make sure layers loaded from XCF and created by plug-ins have the right space when added to the image, because it's impossible to always assign the right space upon layer creation - "assign color profile" and "discard color profile" now require use of gimp_layer_fix_format_space() too because the profile is now embedded in all formats via the space. Add gimp_image_assign_color_profile() which does all that and call it instead of a simple gimp_image_set_color_profile(), also from the PDB set-color-profile functions, which are essentially "assign" and "discard" calls. - generally, make sure a new image's color profile is set before adding layers to it, gimp_image_set_color_profile() is more than before considered know-what-you-are-doing API. - take special precaution in all places that call gimp_drawable_convert_type(), we now must pass a new_profile from all callers that convert layers within the same image (such as image_convert_type, image_convert_precision), because the layer's new space can't be determined from the image's layer format during the call. - change all "linear" properties to "trc", in all config objects like for levels and curves, in the histogram, in the widgets. This results in some GUI that now has three choices instead of two. TODO: we might want to reduce that back to two later. - keep "linear" boolean properties around as compat if needed for file pasring, but always convert the parsed parsed boolean to GimpTRCType. - TODO: the image's "enable color management" switch is currently broken, will fix that in another commit.
2018-07-21 20:23:01 +08:00
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_to (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_to (src_node, "output", node, "aux");
}
if (do_y)
{
GeglNode *src_node;
src_node = create_buffer_source_node (graph, displace_map_y);
gegl_node_connect_to (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,
GimpProgress *progress,
GError **error)
{
if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL,
GIMP_PDB_ITEM_CONTENT, error) &&
gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error))
{
GeglNode *node;
node = gegl_node_new_child (NULL,
"operation", "gegl:gaussian-blur",
"std-dev-x", horizontal * 0.32,
"std-dev-y", vertical * 0.32,
"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_gauss_iir
plug_in_gauss_iir2
plug_in_gauss_rle
plug_in_gauss_rle2
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_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_pixelize2
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;