1 /* This file is an image processing operation for GEGL
2  *
3  * GEGL is free software; you can redistribute it and/or
4  * modify it under the terms of the GNU Lesser General Public
5  * License as published by the Free Software Foundation; either
6  * version 3 of the License, or (at your option) any later version.
7  *
8  * GEGL is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * Lesser General Public License for more details.
12  *
13  * You should have received a copy of the GNU Lesser General Public
14  * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
15  *
16  * Copyright 2006, 2010 Øyvind Kolås <pippin@gimp.org>
17  */
18 
19 #include "config.h"
20 #include <glib/gi18n-lib.h>
21 
22 
23 #ifdef GEGL_PROPERTIES
24 
25 /* Should correspond to GeglMedianBlurNeighborhood in median-blur.c */
26 enum_start (gegl_dropshadow_grow_shape)
27   enum_value (GEGL_DROPSHADOW_GROW_SHAPE_SQUARE,  "square",  N_("Square"))
28   enum_value (GEGL_DROPSHADOW_GROW_SHAPE_CIRCLE,  "circle",  N_("Circle"))
29   enum_value (GEGL_DROPSHADOW_GROW_SHAPE_DIAMOND, "diamond", N_("Diamond"))
30 enum_end (GeglDropshadowGrowShape)
31 
32 property_double (x, _("X"), 20.0)
33   description   (_("Horizontal shadow offset"))
34   ui_range      (-40.0, 40.0)
35   ui_steps      (1, 10)
36   ui_meta       ("unit", "pixel-distance")
37   ui_meta       ("axis", "x")
38 
39 property_double (y, _("Y"), 20.0)
40   description   (_("Vertical shadow offset"))
41   ui_range      (-40.0, 40.0)
42   ui_steps      (1, 10)
43   ui_meta       ("unit", "pixel-distance")
44   ui_meta       ("axis", "y")
45 
46 property_double (radius, _("Blur radius"), 10.0)
47   value_range   (0.0, G_MAXDOUBLE)
48   ui_range      (0.0, 300.0)
49   ui_steps      (1, 5)
50   ui_gamma      (1.5)
51   ui_meta       ("unit", "pixel-distance")
52 
53 property_enum   (grow_shape, _("Grow shape"),
54                  GeglDropshadowGrowShape, gegl_dropshadow_grow_shape,
55                  GEGL_DROPSHADOW_GROW_SHAPE_CIRCLE)
56   description   (_("The shape to expand or contract the shadow in"))
57 
58 property_double (grow_radius, _("Grow radius"), 0.0)
59   value_range   (-100.0, 100.0)
60   ui_range      (-50.0, 50.0)
61   ui_digits     (0)
62   ui_steps      (1, 5)
63   ui_gamma      (1.5)
64   ui_meta       ("unit", "pixel-distance")
65   description (_("The distance to expand the shadow before blurring; a negative value will contract the shadow instead"))
66 
67 property_color  (color, _("Color"), "black")
68     /* TRANSLATORS: the string 'black' should not be translated */
69   description   (_("The shadow's color (defaults to 'black')"))
70 
71 /* It does make sense to sometimes have opacities > 1 (see GEGL logo
72  * for example)
73  */
74 property_double (opacity, _("Opacity"), 0.5)
75   value_range   (0.0, 2.0)
76   ui_steps      (0.01, 0.10)
77 
78 #else
79 
80 #define GEGL_OP_META
81 #define GEGL_OP_NAME     dropshadow
82 #define GEGL_OP_C_SOURCE dropshadow.c
83 
84 #include "gegl-op.h"
85 
86 typedef struct
87 {
88   GeglNode *input;
89   GeglNode *grow;
90   GeglNode *darken;
91 } State;
92 
93 static void
94 update_graph (GeglOperation *operation)
95 {
96   GeglProperties *o = GEGL_PROPERTIES (operation);
97   State *state = o->user_data;
98   if (!state) return;
99 
100   if (o->grow_radius > 0.0001)
101   {
102     gegl_node_link_many (state->input, state->grow, state->darken, NULL);
103   }
104   else
105   {
106     gegl_node_link_many (state->input, state->darken, NULL);
107   }
108 }
109 
110 
111 /* in attach we hook into graph adding the needed nodes */
112 static void
113 attach (GeglOperation *operation)
114 {
115   GeglProperties *o = GEGL_PROPERTIES (operation);
116   GeglNode  *gegl = operation->node;
117   GeglNode  *input, *output, *over, *translate, *opacity, *grow, *blur, *darken, *color;
118   GeglColor *black_color = gegl_color_new ("rgb(0.0,0.0,0.0)");
119 
120   input     = gegl_node_get_input_proxy (gegl, "input");
121   output    = gegl_node_get_output_proxy (gegl, "output");
122   over      = gegl_node_new_child (gegl, "operation", "gegl:over", NULL);
123   translate = gegl_node_new_child (gegl, "operation", "gegl:translate", NULL);
124   opacity   = gegl_node_new_child (gegl, "operation", "gegl:opacity", NULL);
125   blur      = gegl_node_new_child (gegl, "operation", "gegl:gaussian-blur",
126                                          "clip-extent", FALSE,
127                                          "abyss-policy", 0,
128                                          NULL);
129   grow      = gegl_node_new_child (gegl, "operation", "gegl:median-blur",
130                                          "percentile",       100.0,
131                                          "alpha-percentile", 100.0,
132                                          "abyss-policy",     GEGL_ABYSS_NONE,
133                                          NULL);
134   darken    = gegl_node_new_child (gegl, "operation", "gegl:src-in", NULL);
135   color     = gegl_node_new_child (gegl, "operation", "gegl:color",
136                                    "value", black_color,
137                                    NULL);
138   State *state = g_malloc0 (sizeof (State));
139   o->user_data = state;
140   state->input = input;
141   state->grow = grow;
142   state->darken = darken;
143 
144   g_object_unref (black_color);
145 
146   gegl_node_link_many (input, grow, darken, blur, opacity, translate, over, output,
147                        NULL);
148   gegl_node_connect_from (over, "aux", input, "output");
149   gegl_node_connect_from (darken, "aux", color, "output");
150 
151   gegl_operation_meta_redirect (operation, "grow-shape", grow, "neighborhood");
152   gegl_operation_meta_redirect (operation, "grow-radius", grow, "radius");
153   gegl_operation_meta_redirect (operation, "radius", blur, "std-dev-x");
154   gegl_operation_meta_redirect (operation, "radius", blur, "std-dev-y");
155   gegl_operation_meta_redirect (operation, "x", translate, "x");
156   gegl_operation_meta_redirect (operation, "y", translate, "y");
157   gegl_operation_meta_redirect (operation, "color", color, "value");
158   gegl_operation_meta_redirect (operation, "opacity", opacity, "value");
159 }
160 
161 static void
162 dispose (GObject *object)
163 {
164    GeglProperties  *o = GEGL_PROPERTIES (object);
165    g_clear_pointer (&o->user_data, g_free);
166    G_OBJECT_CLASS (gegl_op_parent_class)->dispose (object);
167 }
168 
169 static void
170 gegl_op_class_init (GeglOpClass *klass)
171 {
172   GObjectClass           *object_class;
173   GeglOperationClass     *operation_class      = GEGL_OPERATION_CLASS (klass);
174   GeglOperationMetaClass *operation_meta_class = GEGL_OPERATION_META_CLASS (klass);
175 
176   operation_class->attach      = attach;
177   operation_meta_class->update = update_graph;
178 
179   object_class               = G_OBJECT_CLASS (klass);
180   object_class->dispose      = dispose;
181 
182   gegl_operation_class_set_keys (operation_class,
183     "name",        "gegl:dropshadow",
184     "title",       _("Dropshadow"),
185     "categories",  "light",
186     "reference-hash", "1784365a0e801041189309f3a4866b1a",
187     "description",
188     _("Creates a dropshadow effect on the input buffer"),
189     NULL);
190 }
191 
192 #endif
193