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 2020 Ell 17 */ 18 19 #include "config.h" 20 #include <glib/gi18n-lib.h> 21 22 /* #define MANUAL_CONTROL */ 23 24 #define MAX_GAMMA 1000.0 25 26 #ifdef GEGL_PROPERTIES 27 28 enum_start (gegl_focus_blur_type) 29 enum_value (GEGL_FOCUS_BLUR_TYPE_GAUSSIAN, "gaussian", N_("Gaussian Blur")) 30 enum_value (GEGL_FOCUS_BLUR_TYPE_LENS, "lens", N_("Lens Blur")) 31 enum_end (GeglFocusBlurType) 32 33 enum_start (gegl_focus_blur_shape) 34 enum_value (GEGL_FOCUS_BLUR_SHAPE_CIRCLE, "circle", N_("Circle")) 35 enum_value (GEGL_FOCUS_BLUR_SHAPE_SQUARE, "square", N_("Square")) 36 enum_value (GEGL_FOCUS_BLUR_SHAPE_DIAMOND, "diamond", N_("Diamond")) 37 enum_value (GEGL_FOCUS_BLUR_SHAPE_HORIZONTAL, "horizontal", N_("Horizontal")) 38 enum_value (GEGL_FOCUS_BLUR_SHAPE_VERTICAL, "vertical", N_("Vertical")) 39 enum_end (GeglFocusBlurShape) 40 41 property_enum (blur_type, _("Blur type"), 42 GeglFocusBlurType, gegl_focus_blur_type, 43 GEGL_FOCUS_BLUR_TYPE_GAUSSIAN) 44 45 property_double (blur_radius, _("Blur radius"), 25.0) 46 description (_("Out-of-focus blur radius")) 47 value_range (0.0, 1500.0) 48 ui_range (0.0, 100.0) 49 ui_gamma (2.0) 50 ui_meta ("unit", "pixel-distance") 51 52 property_double (highlight_factor, _("Highlight factor"), 0.0) 53 description (_("Relative highlight strength")) 54 value_range (0.0, 1.0) 55 ui_meta ("visible", "blur-type {lens}") 56 57 property_double (highlight_threshold_low, _("Highlight threshold (low)"), 0.0) 58 ui_range (0.0, 1.0) 59 ui_meta ("role", "range-start") 60 ui_meta ("unit", "luminance") 61 ui_meta ("range-label", _("Highlight threshold")) 62 ui_meta ("visible", "$highlight-factor.visible") 63 64 property_double (highlight_threshold_high, _("Highlight threshold (high)"), 1.0) 65 ui_range (0.0, 1.0) 66 ui_meta ("role", "range-end") 67 ui_meta ("unit", "luminance") 68 ui_meta ("visible", "$highlight-threshold-low.visible") 69 70 property_enum (shape, _("Shape"), 71 GeglFocusBlurShape, 72 gegl_focus_blur_shape, 73 GEGL_FOCUS_BLUR_SHAPE_CIRCLE) 74 75 property_double (x, _("Center X"), 0.5) 76 ui_range (0, 1.0) 77 ui_meta ("unit", "relative-coordinate") 78 ui_meta ("axis", "x") 79 80 property_double (y, _("Center Y"), 0.5) 81 ui_range (0, 1.0) 82 ui_meta ("unit", "relative-coordinate") 83 ui_meta ("axis", "y") 84 85 property_double (radius, _("Radius"), 0.75) 86 description (_("Focus-region outer radius")) 87 value_range (0.0, G_MAXDOUBLE) 88 ui_range (0.0, 5.0) 89 ui_meta ("unit", "relative-distance") 90 91 property_double (focus, _("Sharpness"), 0.25) 92 description (_("Focus-region inner limit")) 93 value_range (0.0, 1.0) 94 95 property_double (midpoint, _("Midpoint"), 0.5) 96 description (_("Focus-transition midpoint")) 97 value_range (0.0, 1.0) 98 99 property_double (aspect_ratio, _("Aspect ratio"), 0.0) 100 value_range (-1.0, +1.0) 101 102 property_double (rotation, _("Rotation"), 0.0) 103 value_range (-180.0, +180.0) 104 ui_meta ("unit", "degree") 105 ui_meta ("direction", "cw") 106 107 #ifdef MANUAL_CONTROL 108 109 property_int (blur_levels, _("Blur levels"), 8) 110 description (_("Number of blur levels")) 111 value_range (2, 16) 112 ui_meta ("visible", "blur-type {gaussian}") 113 114 property_double (blur_gamma, _("Blur gamma"), 1.5) 115 description (_("Gamma factor for blur-level spacing")) 116 value_range (0.0, G_MAXDOUBLE) 117 ui_range (0.1, 10.0) 118 ui_meta ("visible", "blur-type {gaussian}") 119 120 #else 121 122 property_boolean (high_quality, _("High quality"), FALSE) 123 description (_("Generate more accurate and consistent output (slower)")) 124 ui_meta ("visible", "blur-type {gaussian}") 125 126 #endif 127 128 #else 129 130 #define GEGL_OP_META 131 #define GEGL_OP_NAME focus_blur 132 #define GEGL_OP_C_SOURCE focus-blur.c 133 134 #include "gegl-op.h" 135 136 typedef struct 137 { 138 GeglFocusBlurType blur_type; 139 140 GeglNode *input; 141 GeglNode *output; 142 143 GeglNode *color; 144 GeglNode *crop; 145 GeglNode *vignette; 146 147 GeglNode *blur; 148 } Nodes; 149 150 static void 151 update (GeglOperation *operation) 152 { 153 GeglProperties *o = GEGL_PROPERTIES (operation); 154 Nodes *nodes = o->user_data; 155 156 gdouble scale; 157 gdouble squeeze; 158 159 if (o->aspect_ratio >= 0.0) 160 scale = 1.0 - o->aspect_ratio; 161 else 162 scale = 1.0 / (1.0 + o->aspect_ratio); 163 164 if (scale <= 1.0) 165 squeeze = +2.0 * atan (1.0 / scale - 1.0) / G_PI; 166 else 167 squeeze = -2.0 * atan (scale - 1.0) / G_PI; 168 169 gegl_node_set (nodes->vignette, 170 "shape", o->shape, 171 "radius", o->radius, 172 "softness", 1.0 - o->focus, 173 "gamma", o->midpoint < 1.0 ? 174 MIN (log (0.5) / log (o->midpoint), 175 MAX_GAMMA) : 176 MAX_GAMMA, 177 "squeeze", squeeze, 178 "x", o->x, 179 "y", o->y, 180 "rotation", fmod (o->rotation + 360.0, 360.0), 181 NULL); 182 183 if (o->blur_type != nodes->blur_type) 184 { 185 nodes->blur_type = o->blur_type; 186 187 switch (nodes->blur_type) 188 { 189 case GEGL_FOCUS_BLUR_TYPE_GAUSSIAN: 190 gegl_node_set (nodes->blur, 191 "operation", "gegl:variable-blur", 192 "linear-mask", TRUE, 193 NULL); 194 195 gegl_operation_meta_redirect (operation, "blur-radius", 196 nodes->blur, "radius"); 197 #ifdef MANUAL_CONTROLS 198 gegl_operation_meta_redirect (operation, "blur-levels", 199 nodes->blur, "levels"); 200 gegl_operation_meta_redirect (operation, "blur-gamma", 201 nodes->blur, "gamma"); 202 #else 203 gegl_operation_meta_redirect (operation, "high-quality", 204 nodes->blur, "high-quality"); 205 #endif 206 break; 207 208 case GEGL_FOCUS_BLUR_TYPE_LENS: 209 gegl_node_set (nodes->blur, 210 "operation", "gegl:lens-blur", 211 "linear-mask", TRUE, 212 NULL); 213 214 gegl_operation_meta_redirect (operation, "blur-radius", 215 nodes->blur, "radius"); 216 gegl_operation_meta_redirect (operation, "highlight-factor", 217 nodes->blur, "highlight-factor"); 218 gegl_operation_meta_redirect (operation, "highlight-threshold-low", 219 nodes->blur, "highlight-threshold-low"); 220 gegl_operation_meta_redirect (operation, "highlight-threshold-high", 221 nodes->blur, "highlight-threshold-high"); 222 break; 223 } 224 } 225 } 226 227 static void 228 attach (GeglOperation *operation) 229 { 230 GeglProperties *o = GEGL_PROPERTIES (operation); 231 Nodes *nodes; 232 GeglColor *black = gegl_color_new ("black"); 233 GeglColor *white = gegl_color_new ("white"); 234 235 if (! o->user_data) 236 o->user_data = g_slice_new (Nodes); 237 238 nodes = o->user_data; 239 240 nodes->blur_type = -1; 241 242 nodes->input = gegl_node_get_input_proxy (operation->node, "input"); 243 nodes->output = gegl_node_get_output_proxy (operation->node, "output"); 244 245 nodes->color = gegl_node_new_child ( 246 operation->node, 247 "operation", "gegl:color", 248 "value", black, 249 NULL); 250 251 nodes->crop = gegl_node_new_child ( 252 operation->node, 253 "operation", "gegl:crop", 254 NULL); 255 256 nodes->vignette = gegl_node_new_child ( 257 operation->node, 258 "operation", "gegl:vignette", 259 "color", white, 260 "proportion", 0.0, 261 NULL); 262 263 nodes->blur = gegl_node_new_child ( 264 operation->node, 265 "operation", "gegl:variable-blur", 266 NULL); 267 268 gegl_node_link_many (nodes->input, 269 nodes->blur, 270 nodes->output, 271 NULL); 272 273 gegl_node_link_many (nodes->color, 274 nodes->crop, 275 nodes->vignette, 276 NULL); 277 278 gegl_node_connect_to (nodes->input, "output", 279 nodes->crop, "aux"); 280 281 gegl_node_connect_to (nodes->vignette, "output", 282 nodes->blur, "aux"); 283 284 g_object_unref (white); 285 g_object_unref (black); 286 } 287 288 static void 289 dispose (GObject *object) 290 { 291 GeglProperties *o = GEGL_PROPERTIES (object); 292 293 if (o->user_data) 294 { 295 g_slice_free (Nodes, o->user_data); 296 297 o->user_data = NULL; 298 } 299 300 G_OBJECT_CLASS (gegl_op_parent_class)->dispose (object); 301 } 302 303 static void 304 gegl_op_class_init (GeglOpClass *klass) 305 { 306 GObjectClass *object_class; 307 GeglOperationClass *operation_class; 308 GeglOperationMetaClass *operation_meta_class; 309 310 object_class = G_OBJECT_CLASS (klass); 311 operation_class = GEGL_OPERATION_CLASS (klass); 312 operation_meta_class = GEGL_OPERATION_META_CLASS (klass); 313 314 object_class->dispose = dispose; 315 operation_class->attach = attach; 316 operation_meta_class->update = update; 317 318 gegl_operation_class_set_keys (operation_class, 319 "name", "gegl:focus-blur", 320 "title", _("Focus Blur"), 321 "categories", "blur", 322 "reference-hash", "a6f7a6425769c7d8b1d277a5c3f25973", 323 "description", _("Blur the image around a focal point"), 324 NULL); 325 } 326 327 #endif 328