# 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 . # "Perlized" from C source by Manish Singh 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 selected layers based on empty borders of the input drawable'; $help = <<'HELP'; Crop the selected layers of the input "image" based on empty borders of the input "drawable". \n\nThe input drawable serves as a base for detecting cropping extents (transparency or background color), and is not necessarily among the cropped layers (the current selected layers). HELP &std_pdb_misc; $date = '1997'; @inargs = ( { name => 'run_mode', type => 'enum GimpRunMode', dead => 1, desc => 'The run mode' }, { name => 'image', type => 'image', desc => 'Input image)' }, { name => 'drawable', type => 'drawable', desc => 'Input drawable' } ); %invoke = ( code => <<'CODE' { if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, GIMP_PDB_ITEM_CONTENT, error)) { GList *layers = gimp_image_get_selected_layers (image); GList *iter; gint x, y, width, height; if (layers) { switch (gimp_pickable_auto_shrink (GIMP_PICKABLE (drawable), 0, 0, gimp_item_get_width (GIMP_ITEM (drawable)), gimp_item_get_height (GIMP_ITEM (drawable)), &x, &y, &width, &height)) { case GIMP_AUTO_SHRINK_SHRINK: gimp_image_undo_group_start (image, GIMP_UNDO_GROUP_ITEM_RESIZE, _("Autocrop layer")); for (iter = layers; iter; iter = iter->next) gimp_item_resize (GIMP_ITEM (iter->data), context, GIMP_FILL_TRANSPARENT, width, height, -x, -y); gimp_image_undo_group_end (image); break; default: break; } } else { success = FALSE; } } else { success = FALSE; } } CODE ); } sub plug_in_autostretch_hsv { $blurb = 'Stretch contrast to cover the maximum possible range'; $help = <<'HELP'; This simple plug-in does an automatic contrast stretch. For each channel in the image, it finds the minimum and maximum values... it uses those values to stretch the individual histograms to the full contrast range. For some images it may do just what you want; for others it may be total crap :). This version differs from Contrast Autostretch in that it works in HSV space, and preserves hue. HELP &std_pdb_compat('gegl:stretch-contrast-hsv'); $date = '2013'; @inargs = ( { name => 'run_mode', type => 'enum GimpRunMode', dead => 1, desc => 'The run mode' }, { name => 'image', type => 'image', dead => 1, desc => 'Input image (unused)' }, { name => 'drawable', type => 'drawable', desc => 'Input drawable' } ); %invoke = ( code => <<'CODE' { if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, GIMP_PDB_ITEM_CONTENT, error) && gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error)) { GeglNode *node = gegl_node_new_child (NULL, "operation", "gegl:stretch-contrast-hsv", NULL); gimp_drawable_apply_operation (drawable, progress, C_("undo-type", "Stretch Contrast HSV"), node); g_object_unref (node); } else success = FALSE; } CODE ); } sub plug_in_bump_map { $blurb = 'Create an embossing effect using a bump map'; $help = <<'HELP'; This plug-in uses the algorithm described by John Schlag, "Fast Embossing Effects on Raster Image Data" in Graphics GEMS IV (ISBN 0-12-336155-9). It takes a drawable to be applied as a bump map to another image and produces a nice embossing effect. HELP &std_pdb_compat('gegl:bump-map'); $date = '2015'; @inargs = ( { name => 'run_mode', type => 'enum GimpRunMode', dead => 1, desc => 'The run mode' }, { name => 'image', type => 'image', dead => 1, desc => 'Input image (unused)' }, { name => 'drawable', type => 'drawable', desc => 'Input drawable' }, { name => 'bumpmap', type => 'drawable', desc => 'Bump map drawable' }, { name => 'azimuth', type => '0.0 <= 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, -circular'); $date = '2013'; @inargs = ( { name => 'run_mode', type => 'enum GimpRunMode', dead => 1, desc => 'The run mode' }, { name => 'image', type => 'image', dead => 1, desc => 'Input image (unused)' }, { name => 'drawable', type => 'drawable', desc => 'Input drawable' }, { name => 'type', type => '0 <= int32 <= 2', desc => 'Type of motion blur { LINEAR (0), RADIAL (1), ZOOM (2) }' }, { name => 'length', type => '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, -circular'); $date = '2013'; @inargs = ( { name => 'run_mode', type => 'enum GimpRunMode', dead => 1, desc => 'The run mode' }, { name => 'image', type => 'image', dead => 1, desc => 'Input image (unused)' }, { name => 'drawable', type => 'drawable', desc => 'Input drawable' }, { name => 'type', type => '0 <= int32 <= 2', desc => 'Type of motion blur { LINEAR (0), RADIAL (1), ZOOM (2) }' }, { name => 'length', type => '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_median_blur { $blurb = 'Blur using the median color near each pixel'; $help = <<'HELP'; Blur resulting from computing the median color in the neighborhood of each pixel HELP &std_pdb_compat('gegl:median-blur'); $date = '2021'; @inargs = ( { name => 'run_mode', type => 'enum GimpRunMode', dead => 1, desc => 'The run mode' }, { name => 'image', type => 'image', dead => 1, desc => 'Input image (unused)' }, { name => 'drawable', type => 'drawable', desc => 'Input drawable' }, { name => 'radius', type => '-400 <= int32 <= 400', desc => 'Neighborhood radius, a negative value will calculate with inverted percentiles' }, { name => 'percentile', type => '0 <= float <= 100', desc => 'Neighborhood color percentile' } ); %invoke = ( code => <<'CODE' { if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, GIMP_PDB_ITEM_CONTENT, error) && gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error)) { GeglNode *node = gegl_node_new_child (NULL, "operation", "gegl:median-blur", "radius", radius, "percentile", percentile, NULL); gimp_drawable_apply_operation (drawable, progress, C_("undo-type", "Median Blur"), node); g_object_unref (node); } else success = FALSE; } CODE ); } sub plug_in_mosaic { $blurb = 'Convert the image into irregular tiles'; $help = <<'HELP'; Mosaic is a filter which transforms an image into what appears to be a mosaic, composed of small primitives, each of constant color and of an approximate size. HELP &std_pdb_compat('gegl:mosaic'); $date = '2013'; @inargs = ( { name => 'run_mode', type => 'enum GimpRunMode', dead => 1, desc => 'The run mode' }, { name => 'image', type => 'image', dead => 1, desc => 'Input image (unused)' }, { name => 'drawable', type => 'drawable', desc => 'Input drawable' }, { name => 'tile_size', type => '1 <= 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 => '0.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', desc => 'alpha for the first color (used if the drawable has an alpha channel)' }, { name => 'alpha2', type => '0 <= float <= 1', desc => 'alpha for the second color (used if the drawable has an alpha channel)' }, { name => 'blend', type => '0 <= int32 <= 2', desc => '0=linear, 1=bilinear, 2=sinusoidal' }, { name => 'blend_power', type => '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) { if (gimp_drawable_get_trc (drawable) != GIMP_TRC_LINEAR) { const Babl *drawable_format; const Babl *cast_format; GeglNode *new_node; GeglNode *input; GeglNode *output; GeglNode *cast_before; GeglNode *cast_after; drawable_format = gimp_drawable_get_format (drawable); cast_format = gimp_babl_format (gimp_babl_format_get_base_type (drawable_format), gimp_babl_precision (gimp_babl_format_get_component_type (drawable_format), GIMP_TRC_LINEAR), babl_format_has_alpha (drawable_format), babl_format_get_space (drawable_format)); new_node = gegl_node_new (); gegl_node_add_child (new_node, node); g_object_unref (node); gimp_gegl_node_set_underlying_operation (new_node, node); input = gegl_node_get_input_proxy (new_node, "input"); output = gegl_node_get_output_proxy (new_node, "output"); cast_before = gegl_node_new_child (new_node, "operation", "gegl:cast-format", "input-format", drawable_format, "output-format", cast_format, NULL); cast_after = gegl_node_new_child (new_node, "operation", "gegl:cast-format", "input-format", cast_format, "output-format", drawable_format, NULL); gegl_node_link_many (input, cast_before, node, cast_after, output, NULL); return new_node; } else { return node; } } static GeglNode * create_buffer_source_node (GeglNode *parent, GimpDrawable *drawable) { GeglNode *new_node; GeglBuffer *buffer; buffer = gimp_drawable_get_buffer (drawable); g_object_ref (buffer); new_node = gegl_node_new_child (parent, "operation", "gegl:buffer-source", "buffer", buffer, NULL); g_object_unref (buffer); return new_node; } static gboolean bump_map (GimpDrawable *drawable, GimpDrawable *bump_map, gdouble azimuth, gdouble elevation, gint depth, gint offset_x, gint offset_y, gdouble waterlevel, gdouble ambient, gboolean compensate, gboolean invert, gint type, gboolean tiled, GimpProgress *progress, GError **error) { if (gimp_pdb_item_is_attached (GIMP_ITEM (drawable), NULL, GIMP_PDB_ITEM_CONTENT, error) && gimp_pdb_item_is_not_group (GIMP_ITEM (drawable), error)) { GeglNode *graph; GeglNode *node; GeglNode *src_node; node = gegl_node_new_child (NULL, "operation", "gegl:bump-map", "tiled", tiled, "type", type, "compensate", compensate, "invert", invert, "azimuth", azimuth, "elevation", elevation, "depth", depth, "offset_x", offset_x, "offset_y", offset_y, "waterlevel", waterlevel, "ambient", ambient, NULL); graph = wrap_in_graph (node); src_node = create_buffer_source_node (graph, bump_map); gegl_node_connect_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_median_blur plug_in_mosaic plug_in_neon plug_in_newsprint plug_in_normalize plug_in_nova plug_in_oilify plug_in_oilify_enhanced plug_in_papertile plug_in_photocopy plug_in_pixelize plug_in_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;