1 /* This file is an image processing operation for GEGL
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation; either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This program 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
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
15  *
16  * Copyright 1997 Miles O'Neal <meo@rru.com>  http://www.rru.com/~meo/
17  * Copyright 2012 Maxime Nicco <maxime.nicco@gmail.com>
18  */
19 
20 /*
21  *  SLUR Operation
22  *  We replace the current pixel by:
23  *      80% chance it's from directly above,
24  *      10% from above left,
25  *      10% from above right.
26  */
27 
28 #include "config.h"
29 
30 #include <glib/gi18n-lib.h>
31 
32 #ifdef GEGL_PROPERTIES
33 
34 property_double (pct_random, _("Randomization (%)"), 50.0)
35     value_range (0.0, 100.0)
36 
37 property_int    (repeat, _("Repeat"), 1)
38     value_range (1, 100)
39 
40 property_seed (seed, _("Random seed"), rand)
41 
42 #else
43 
44 #define GEGL_OP_AREA_FILTER
45 #define GEGL_OP_NAME     noise_slur
46 #define GEGL_OP_C_SOURCE noise-slur.c
47 
48 #include "gegl-op.h"
49 
50 static void
51 prepare (GeglOperation *operation)
52 {
53   GeglOperationAreaFilter *op_area = GEGL_OPERATION_AREA_FILTER (operation);
54   GeglProperties          *o       = GEGL_PROPERTIES (operation);
55   const Babl              *format;
56 
57   op_area->left   =
58   op_area->right  =
59   op_area->top    = o->repeat;
60   op_area->bottom = 0;
61 
62   format = gegl_operation_get_source_format (operation, "input");
63 
64   gegl_operation_set_format (operation, "input", format);
65   gegl_operation_set_format (operation, "output", format);
66 }
67 
68 /* We avoid unecessary calls to gegl_random
69  * by recomputing a small part ourselves.
70  * see gegl/gegl-random.c for details */
71 #define RAND_UINT_TO_FLOAT(x) (((x) & 0xffff) * 0.00001525902189669642175)
72 
73 static gboolean
74 process (GeglOperation       *operation,
75          GeglBuffer          *input,
76          GeglBuffer          *output,
77          const GeglRectangle *result,
78          gint                 level)
79 {
80   GeglProperties     *o;
81   const Babl         *format;
82   gint                bpp;
83   GeglBufferIterator *gi;
84   GeglSampler        *sampler;
85 
86   o = GEGL_PROPERTIES (operation);
87 
88   format = gegl_operation_get_source_format (operation, "input");
89   bpp = babl_format_get_bytes_per_pixel (format);
90 
91   gi = gegl_buffer_iterator_new (output, result, 0, format,
92                                  GEGL_ACCESS_WRITE, GEGL_ABYSS_CLAMP, 1);
93 
94   sampler = gegl_buffer_sampler_new_at_level (input, format, GEGL_SAMPLER_NEAREST, level);
95 
96   while (gegl_buffer_iterator_next (gi))
97     {
98       gchar        *data = gi->items[0].data;
99       GeglRectangle roi  = gi->items[0].roi;
100       gint          i, j;
101 
102       for (j = roi.y; j < roi.y + roi.height ; j++)
103         for (i = roi.x; i < roi.x + roi.width ; i++)
104           {
105             gint r;
106             gint pos_x = i, pos_y = j;
107 
108             for (r = 0; r < o->repeat; r++)
109               {
110                 guint  rand = gegl_random_int (o->rand, pos_x, pos_y, 0, r);
111                 gfloat pct  = RAND_UINT_TO_FLOAT (rand) * 100.0;
112 
113                 if (pct <= o->pct_random)
114                   {
115                     gint rand2 = (gint) (rand % 10);
116 
117                     pos_y--;
118 
119                     switch (rand2)
120                       {
121                       case 0:
122                         pos_x--;
123                         break;
124                       case 9:
125                         pos_x++;
126                         break;
127                       default:
128                         break;
129                       }
130                   }
131               }
132 
133             gegl_sampler_get (sampler, pos_x, pos_y, NULL, data, GEGL_ABYSS_CLAMP);
134             data += bpp;
135           }
136     }
137 
138   g_object_unref (sampler);
139 
140   return TRUE;
141 }
142 
143 static void
144 gegl_op_class_init (GeglOpClass *klass)
145 {
146   GeglOperationClass       *operation_class;
147   GeglOperationFilterClass *filter_class;
148 
149   operation_class = GEGL_OPERATION_CLASS (klass);
150   filter_class    = GEGL_OPERATION_FILTER_CLASS (klass);
151 
152   operation_class->prepare = prepare;
153   filter_class->process    = process;
154 
155   gegl_operation_class_set_keys (operation_class,
156     "name",        "gegl:noise-slur",
157     "title",       _("Noise Slur"),
158     "categories",  "noise",
159     "reference-hash", "8d921285191c7e1bfac09acb7ed67f21",
160     "license",     "GPL3+",
161     "description", _("Randomly slide some pixels downward (similar to melting)"),
162     NULL);
163 }
164 
165 #endif
166