1. Hue rotation
2. Gaussian Blur blended by a blend mode
3. Denoise dct
Then it is followed by a normal softglow, sharpen and black color overlay at 10% opacity that applies to everything
Source code for the latest update that includes Gaussian blur with blend modes (nicked named orton) is here
/* This file is an image processing operation for GEGL
*
* GEGL is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* GEGL 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
*
* Copyright 2006 Øyvind Kolås <pippin@gimp.org>
* 2024 Beaver, Hacky Mask
Plugin recreated as a GEGL graph here -
assumes gaussian blur is being used and you have my file path.
id=1
gaussian-blur std-dev-x=33 std-dev-y=33
dst-in aux=[ layer src=/home/USERNAME/Pictures/Magic/pattern_fills/pattern_christmas-tree-1_1_2_0-0_0_1__ffffff00_ffffff_ffec3d_f44034_53910d.png ]
dst-over aux=[ ref=1 ]
*/
#include "config.h"
#include <glib/gi18n-lib.h>
#ifdef GEGL_PROPERTIES
enum_start (orton_time)
enum_value (HARDLIGHT, "hardlight",
N_("Hard Light"))
enum_value (OVERLAY, "overlay",
N_("Overlay"))
enum_value (MULTIPLY, "multiply",
N_("Multiply"))
enum_value (ADD, "add",
N_("Add"))
enum_end (ortontime)
enum_start (invert_hackmask)
enum_value (MASK, "standard",
N_("Default Mask"))
enum_value (INVERT_MASK, "invert",
N_("Invert Mask"))
enum_end (inverthackmask)
property_boolean (invertmask, _("Invert Mask"), FALSE)
description (_("Invert Mask"))
/*
property_enum (invertmask, _("Default or inverted"),
inverthackmask, invert_hackmask,
MASK)
description (_("Optionally invert the mask"))
*/
property_file_path(imagemask, _("Image File (layer mask)"), "")
description (_("Image file that functions as a layer mask...)"))
property_enum (filterselect, _("Select a filter"),
maskhack, mask_hack,
adjustments)
description (_("Choose a filter for the hacky layer mask."))
enum_start (mask_hack)
enum_value (adjustments, "adjustments",
N_("Adjustments"))
enum_value (blur, "blur",
N_("Blur"))
enum_value (sharpen, "sharpen",
N_("Sharpen"))
enum_value (denoise, "denoise",
N_("Denoise"))
enum_value (orton, "orton",
N_("Orton (blur blended)"))
enum_end (maskhack)
property_double (saturation, _("Saturation"), 1)
value_range (0.0, 5.0)
ui_range (0.0, 4.0)
ui_meta ("unit", "pixel-distance")
description (_("Saturation filter"))
ui_meta ("visible", "!filterselect {blur, sharpen, denoise, orton }" )
property_double (lightness, _("Lightness"), 0)
value_range (-200.0, 200.0)
ui_range (-100.0, 100.0)
ui_meta ("unit", "pixel-distance")
description (_("Lightness filter "))
ui_meta ("visible", "!filterselect {blur, sharpen, denoise, orton }" )
property_double (hue, _("Hue"), 0)
value_range (-180.0, 180.0)
ui_range (-180.0, 180.0)
ui_meta ("unit", "pixel-distance")
description (_("Hue rotation filter "))
ui_meta ("visible", "!filterselect {blur, sharpen, denoise, orton }" )
property_double (blur, _("Blur"), 0)
value_range (0.0, 300.0)
ui_range (0.0, 200.0)
ui_meta ("unit", "pixel-distance")
description (_("Gaussian Blur filter"))
ui_meta ("visible", "!filterselect {adjustments, sharpen, denoise }" )
property_double (sharpenradius, _("Sharpen Radius"), 0.0)
description(_("Sharpen radius"))
value_range (0.0, 150)
ui_range (0.0, 40.0)
ui_gamma (3.0)
ui_meta ("unit", "pixel-distance")
ui_meta ("visible", "!filterselect {adjustments, blur, denoise, orton }" )
property_double (sharpenscale, _("Sharpen Amount"), 0.5)
description(_("Scaling factor for unsharp-mask, the strength of effect"))
value_range (0.0, 300.0)
ui_range (0.0, 10.0)
ui_gamma (3.0)
ui_meta ("visible", "!filterselect {adjustments, blur, denoise, orton }" )
property_int (denoise, _("Denoise Strength"), 1)
description (_("Noise standard deviation"))
ui_range (1, 30)
value_range (1, 100)
ui_meta ("visible", "!filterselect {adjustments, blur, sharpen, orton }" )
property_enum (ortonblendmode, _("Select a blend mode for the orton (gaussian blur blended)"),
ortontime, orton_time,
HARDLIGHT)
description (_("Choose a blend mode for the gaussian blur to blend with"))
ui_meta ("visible", "!filterselect {adjustments, blur, sharpen, denoise }" )
#else
#define GEGL_OP_META
#define GEGL_OP_NAME maskhack
#define GEGL_OP_C_SOURCE maskhack.c
#include "gegl-op.h"
typedef struct
{
GeglNode *input;
GeglNode *saturation;
GeglNode *lighthue;
GeglNode *eraseblendmode;
GeglNode *behindblendmode;
GeglNode *imagemask;
GeglNode *color;
GeglNode *blur;
GeglNode *sharpen;
GeglNode *hardlight;
GeglNode *multiply;
GeglNode *overlay;
GeglNode *add;
GeglNode *denoise;
GeglNode *output;
}State;
static void attach (GeglOperation *operation)
{
GeglNode *gegl = operation->node;
GeglProperties *o = GEGL_PROPERTIES (operation);
State *state = o->user_data = g_malloc0 (sizeof (State));
state->input = gegl_node_get_input_proxy (gegl, "input");
state->output = gegl_node_get_output_proxy (gegl, "output");
state->eraseblendmode = gegl_node_new_child (gegl,
"operation", "gegl:dst-in",
NULL);
state->behindblendmode = gegl_node_new_child (gegl,
"operation", "gegl:dst-over",
NULL);
state->imagemask = gegl_node_new_child (gegl,
"operation", "gegl:layer",
NULL);
state->saturation = gegl_node_new_child (gegl,
"operation", "gegl:saturation",
NULL);
state->hardlight = gegl_node_new_child (gegl,
"operation", "gegl:hard-light", "srgb", TRUE,
NULL);
state->overlay = gegl_node_new_child (gegl,
"operation", "gegl:overlay", "srgb", TRUE,
NULL);
state->multiply = gegl_node_new_child (gegl,
"operation", "gegl:multiply",
NULL);
state->add = gegl_node_new_child (gegl,
"operation", "gegl:add",
NULL);
state->lighthue = gegl_node_new_child (gegl,
"operation", "gegl:hue-chroma",
NULL);
state->blur = gegl_node_new_child (gegl,
"operation", "gegl:gaussian-blur",
NULL);
state->sharpen = gegl_node_new_child (gegl,
"operation", "gegl:unsharp-mask",
NULL);
state->denoise = gegl_node_new_child (gegl,
"operation", "gegl:denoise-dct",
NULL);
/*
state->denoise = gegl_node_new_child (gegl,
"operation", "gegl:denoise-dct", "sigma", 1,
NULL);
state->noisereduction = gegl_node_new_child (gegl,
"operation", "gegl:noise-reduction", "iterations", 1,
NULL);
state->meancurvatureblur = gegl_node_new_child (gegl,
"operation", "gegl:mean-curvature-blur", "iterations", 1,
NULL);
*/
gegl_operation_meta_redirect (operation, "imagemask", state->imagemask, "src");
gegl_operation_meta_redirect (operation, "saturation", state->saturation, "scale");
gegl_operation_meta_redirect (operation, "lightness", state->lighthue, "lightness");
gegl_operation_meta_redirect (operation, "hue", state->lighthue, "hue");
gegl_operation_meta_redirect (operation, "blur", state->blur, "std-dev-x");
gegl_operation_meta_redirect (operation, "blur", state->blur, "std-dev-y");
gegl_operation_meta_redirect (operation, "sharpenradius", state->sharpen, "std-dev");
gegl_operation_meta_redirect (operation, "sharpenscale", state->sharpen, "scale");
gegl_operation_meta_redirect (operation, "denoise", state->denoise, "sigma");
/*
gegl_operation_meta_redirect (operation, "noisereduction", state->noisereduction, "iterations");
*/
}
static void update_graph (GeglOperation *operation)
{
GeglProperties *o = GEGL_PROPERTIES (operation);
State *state = o->user_data;
if (!state) return;
const char *mask_op = "gegl:nop";
switch (o->invertmask) {
case MASK: mask_op = "gegl:dst-in"; break;
case INVERT_MASK: mask_op = "gegl:dst-out"; break;
}
gegl_node_set (state->eraseblendmode, "operation", mask_op, NULL);
GeglNode *hardlight = state->hardlight;
switch (o->ortonblendmode) {
case HARDLIGHT: hardlight = state->hardlight; break;
case OVERLAY: hardlight = state->overlay; break;
case MULTIPLY: hardlight = state->multiply; break;
case ADD: hardlight = state->add; break;
default: hardlight = state->hardlight;
}
switch (o->filterselect) {
break;
case adjustments:
gegl_node_link_many (state->input, state->saturation, state->lighthue, state->eraseblendmode, state->behindblendmode, state->output, NULL);
gegl_node_connect (state->eraseblendmode, "aux", state->imagemask, "output");
gegl_node_connect (state->behindblendmode, "aux", state->input, "output");
break;
case blur:
gegl_node_link_many (state->input, state->blur, state->eraseblendmode, state->behindblendmode, state->output, NULL);
gegl_node_connect (state->eraseblendmode, "aux", state->imagemask, "output");
gegl_node_connect (state->behindblendmode, "aux", state->input, "output");
break;
case sharpen:
gegl_node_link_many (state->input, state->sharpen, state->eraseblendmode, state->behindblendmode, state->output, NULL);
gegl_node_connect (state->eraseblendmode, "aux", state->imagemask, "output");
gegl_node_connect (state->behindblendmode, "aux", state->input, "output");
break;
case denoise:
gegl_node_link_many (state->input, state->denoise, state->eraseblendmode, state->behindblendmode, state->output, NULL);
gegl_node_connect (state->eraseblendmode, "aux", state->imagemask, "output");
gegl_node_connect (state->behindblendmode, "aux", state->input, "output");
break;
case orton:
gegl_node_link_many (state->input, hardlight, state->eraseblendmode, state->behindblendmode, state->output, NULL);
gegl_node_connect (hardlight, "aux", state->blur, "output");
gegl_node_link_many (state->input, state->blur, NULL);
gegl_node_connect (state->eraseblendmode, "aux", state->imagemask, "output");
gegl_node_connect (state->behindblendmode, "aux", state->input, "output");
}
}
static void
gegl_op_class_init (GeglOpClass *klass)
{
GeglOperationClass *operation_class;
GeglOperationMetaClass *operation_meta_class = GEGL_OPERATION_META_CLASS (klass);
operation_class = GEGL_OPERATION_CLASS (klass);
operation_class->attach = attach;
operation_meta_class->update = update_graph;
gegl_operation_class_set_keys (operation_class,
"name", "lb:mask-hack",
"title", _("Mask Hack"),
"reference-hash", "gimp29919devworld",
"description", _("Create a layer mask for non-destructive filters in early GIMP 3 by uploading image files as a mask. "),
"gimp:menu-path", "<Image>/Filters/Generic",
"gimp:menu-label", _("Non-Destructive filter layer mask hack"),
NULL);
}
#endif