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  *
17  * Exchange one color with the other (settable threshold to convert from
18  * one color-shade to another...might do wonders on certain images, or be
19  * totally useless on others).
20  *
21  * Author: Adam D. Moss <adam@foxbox.org>
22  *
23  * GEGL port: Thomas Manni <thomas.manni@free.fr>
24  *
25  */
26 
27 #include "config.h"
28 #include <glib/gi18n-lib.h>
29 
30 #ifdef GEGL_PROPERTIES
31 
32 enum_start (gegl_video_degradation_type)
33   enum_value (GEGL_VIDEO_DEGRADATION_TYPE_STAGGERED, "staggered",
34               N_("Staggered"))
35   enum_value (GEGL_VIDEO_DEGRADATION_TYPE_LARGE_STAGGERED, "large-staggered",
36               N_("Large staggered"))
37   enum_value (GEGL_VIDEO_DEGRADATION_TYPE_STRIPED, "striped",
38               N_("Striped"))
39   enum_value (GEGL_VIDEO_DEGRADATION_TYPE_WIDE_STRIPED, "wide-striped",
40               N_("Wide striped"))
41   enum_value (GEGL_VIDEO_DEGRADATION_TYPE_LONG_STAGGERED, "long-staggered",
42               N_("Long staggered"))
43   enum_value (GEGL_VIDEO_DEGRADATION_TYPE_3X3, "3x3",
44               N_("3x3"))
45   enum_value (GEGL_VIDEO_DEGRADATION_TYPE_LARGE_3X3, "large-3x3",
46               N_("Large 3x3"))
47   enum_value (GEGL_VIDEO_DEGRADATION_TYPE_Hex, "hex",
48               N_("Hex"))
49   enum_value (GEGL_VIDEO_DEGRADATION_TYPE_DOTS, "dots",
50               N_("Dots"))
51 enum_end (GeglVideoDegradationType)
52 
53 property_enum (pattern, _("Pattern"), GeglVideoDegradationType,
54                gegl_video_degradation_type,
55                GEGL_VIDEO_DEGRADATION_TYPE_STRIPED)
56   description (_("Type of RGB pattern to use"))
57 
58 property_boolean (additive, _("Additive"), TRUE)
59   description(_("Whether the function adds the result to the original image."))
60 
61 property_boolean (rotated, _("Rotated"), FALSE)
62   description(_("Whether to rotate the RGB pattern by ninety degrees."))
63 
64 #else
65 
66 #define GEGL_OP_POINT_FILTER
67 #define GEGL_OP_NAME     video_degradation
68 #define GEGL_OP_C_SOURCE video-degradation.c
69 
70 #include "gegl-op.h"
71 
72 #define MAX_PATTERNS       9
73 #define MAX_PATTERN_SIZE 108
74 
75 static const gint   pattern_width[MAX_PATTERNS] = { 2, 4, 1, 1, 2, 3, 6, 6, 5 };
76 static const gint   pattern_height[MAX_PATTERNS] = { 6, 12, 3, 6, 12, 3, 6,
77                                                      18, 15 };
78 
79 static const gint pattern[MAX_PATTERNS][MAX_PATTERN_SIZE] =
80 {
81   {
82     0, 1,
83     0, 2,
84     1, 2,
85     1, 0,
86     2, 0,
87     2, 1,
88   },
89   {
90     0, 0, 1, 1,
91     0, 0, 1, 1,
92     0, 0, 2, 2,
93     0, 0, 2, 2,
94     1, 1, 2, 2,
95     1, 1, 2, 2,
96     1, 1, 0, 0,
97     1, 1, 0, 0,
98     2, 2, 0, 0,
99     2, 2, 0, 0,
100     2, 2, 1, 1,
101     2, 2, 1, 1,
102   },
103   {
104     0,
105     1,
106     2,
107   },
108   {
109     0,
110     0,
111     1,
112     1,
113     2,
114     2,
115   },
116   {
117     0, 1,
118     0, 1,
119     0, 2,
120     0, 2,
121     1, 2,
122     1, 2,
123     1, 0,
124     1, 0,
125     2, 0,
126     2, 0,
127     2, 1,
128     2, 1,
129   },
130   {
131     0, 1, 2,
132     2, 0, 1,
133     1, 2, 0,
134   },
135   {
136     0, 0, 1, 1, 2, 2,
137     0, 0, 1, 1, 2, 2,
138     2, 2, 0, 0, 1, 1,
139     2, 2, 0, 0, 1, 1,
140     1, 1, 2, 2, 0, 0,
141     1, 1, 2, 2, 0, 0,
142   },
143   {
144     2, 2, 0, 0, 0, 0,
145     2, 2, 2, 0, 0, 2,
146     2, 2, 2, 2, 2, 2,
147     2, 2, 2, 1, 1, 2,
148     2, 2, 1, 1, 1, 1,
149     1, 1, 1, 1, 1, 1,
150     0, 0, 1, 1, 1, 1,
151     0, 0, 0, 1, 1, 0,
152     0, 0, 0, 0, 0, 0,
153     0, 0, 0, 2, 2, 0,
154     0, 0, 2, 2, 2, 2,
155     2, 2, 2, 2, 2, 2,
156     1, 1, 2, 2, 2, 2,
157     1, 1, 1, 2, 2, 1,
158     1, 1, 1, 1, 1, 1,
159     1, 1, 1, 0, 0, 1,
160     1, 1, 0, 0, 0, 0,
161     0, 0, 0, 0, 0, 0,
162   },
163   {
164     0, 1, 2, 0, 0,
165     1, 1, 1, 2, 0,
166     0, 1, 2, 2, 2,
167     0, 0, 1, 2, 0,
168     0, 1, 1, 1, 2,
169     2, 0, 1, 2, 2,
170     0, 0, 0, 1, 2,
171     2, 0, 1, 1, 1,
172     2, 2, 0, 1, 2,
173     2, 0, 0, 0, 1,
174     1, 2, 0, 1, 1,
175     2, 2, 2, 0, 1,
176     1, 2, 0, 0, 0,
177     1, 1, 2, 0, 1,
178     1, 2, 2, 2, 0,
179   }
180 };
181 
182 static void
183 prepare (GeglOperation *operation)
184 {
185   const Babl     *format = babl_format_with_space ("R'G'B'A float", gegl_operation_get_source_space (operation, "input"));
186 
187   gegl_operation_set_format (operation, "input", format);
188   gegl_operation_set_format (operation, "output", format);
189 }
190 
191 static gboolean
192 cl_process (GeglOperation       *operation,
193             cl_mem               in_buf,
194             cl_mem               out_buf,
195             const size_t         n_pixels,
196             const GeglRectangle *roi,
197             gint                 level)
198 {
199   GeglOperationClass *operation_class = GEGL_OPERATION_GET_CLASS (operation);
200   GeglClRunData *cl_data = operation_class->cl_data;
201   GeglProperties *o = GEGL_PROPERTIES (operation);
202   const size_t gbl_size[2] = {roi->width, roi->height};
203   const size_t gbl_off[2]  = {roi->x, roi->y};
204   cl_int cl_err = 0;
205   cl_mem filter_pat = NULL;
206 
207   if (!cl_data)
208     goto error;
209   filter_pat = gegl_clCreateBuffer (gegl_cl_get_context (),
210                                     CL_MEM_READ_ONLY | CL_MEM_COPY_HOST_PTR,
211                                     pattern_width[o->pattern] *
212                                     pattern_height[o->pattern] * sizeof(cl_int),
213                                     (void*)pattern[o->pattern],
214                                     &cl_err);
215   CL_CHECK;
216   cl_err = gegl_cl_set_kernel_args (cl_data->kernel[0],
217                                     sizeof(cl_mem), &in_buf,
218                                     sizeof(cl_mem), &out_buf,
219                                     sizeof(cl_mem), &filter_pat,
220                                     sizeof(cl_int), &pattern_width[o->pattern],
221                                     sizeof(cl_int), &pattern_height[o->pattern],
222                                     sizeof(cl_int), &o->additive,
223                                     sizeof(cl_int), &o->rotated,
224                                     NULL);
225   CL_CHECK;
226   cl_err = gegl_clEnqueueNDRangeKernel (gegl_cl_get_command_queue (),
227                                         cl_data->kernel[0], 2,
228                                         gbl_off, gbl_size, NULL,
229                                         0, NULL, NULL);
230   CL_CHECK;
231   cl_err = gegl_clFinish (gegl_cl_get_command_queue ());
232   CL_CHECK;
233   cl_err = gegl_clReleaseMemObject (filter_pat);
234   CL_CHECK;
235   return FALSE;
236   error:
237     if (filter_pat)
238       gegl_clReleaseMemObject (filter_pat);
239     return TRUE;
240 }
241 
242 static gboolean
243 process (GeglOperation       *operation,
244          void                *in_buf,
245          void                *out_buf,
246          glong                n_pixels,
247          const GeglRectangle *roi,
248          gint                 level)
249 {
250   GeglProperties *o = GEGL_PROPERTIES (operation);
251   gfloat *input  = in_buf;
252   gfloat *output = out_buf;
253   gfloat value;
254   gint x, y;
255   gint real_x, real_y;
256   gint b;
257   gint sel_b;
258   gint idx;
259 
260   for (y = 0 ; y < roi->height ; y++)
261     {
262       real_y = roi->y + y;
263       for (x = 0 ; x < roi->width ; x++)
264         {
265           real_x = roi->x + x;
266 
267           if (o->rotated)
268             {
269               sel_b = pattern[o->pattern][pattern_width[o->pattern]*
270                 (real_x % pattern_height[o->pattern]) +
271                  real_y % pattern_width[o->pattern] ];
272             }
273           else
274             {
275               sel_b = pattern[o->pattern][pattern_width[o->pattern]*
276                  (real_y % pattern_height[o->pattern]) +
277                  real_x % pattern_width[o->pattern] ];
278             }
279 
280             for (b = 0; b < 4; b++)
281               {
282                 idx = (x + y * roi->width) * 4 + b;
283                 if (b < 3 )
284                   {
285                     value = (sel_b == b) ? input[idx] : 0.f;
286                     if (o->additive)
287                       {
288                         gfloat temp = value + input[idx];
289                         value = MIN (temp, 1.0);
290                       }
291                     output[idx] = value;
292                   }
293                 else
294                  {
295                    output[idx] = input[idx];
296                  }
297               }
298         }
299     }
300 
301   return TRUE;
302 }
303 
304 #include "opencl/video-degradation.cl.h"
305 
306 static void
307 gegl_op_class_init (GeglOpClass *klass)
308 {
309   GeglOperationClass            *operation_class;
310   GeglOperationPointFilterClass *filter_class;
311 
312   operation_class = GEGL_OPERATION_CLASS (klass);
313   filter_class    = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
314 
315   operation_class->prepare = prepare;
316 
317   filter_class->process    = process;
318   filter_class->cl_process = cl_process;
319 
320   gegl_operation_class_set_keys (operation_class,
321     "name",           "gegl:video-degradation",
322     "title",          _("Video Degradation"),
323     "categories",     "distort",
324     "license",        "GPL3+",
325     "reference-hash", "1f7ad41dc1c0595b9b90ad1f72e18d2f",
326     "description", _("This function simulates the degradation of "
327                      "being on an old low-dotpitch RGB video monitor."),
328     "cl-source"  , video_degradation_cl_source,
329     NULL);
330 }
331 
332 #endif
333