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 Øyvind Kolås <pippin@gimp.org>
17  */
18 
19 
20 #include "config.h"
21 #include <glib/gi18n-lib.h>
22 
23 #define EPSILON 1e-6
24 
25 #ifdef GEGL_PROPERTIES
26 
27 property_double (in_low, _("Low input"), 0.0)
28     description ( _("Input luminance level to become lowest output"))
29     ui_range    (0.0, 1.0)
30 
31 property_double (in_high, _("High input"), 1.0)
32     description (_("Input luminance level to become white"))
33     ui_range    (0.0, 1.0)
34 
35 property_double (out_low, _("Low output"), 0.0)
36     description (_("Lowest luminance level in output"))
37     ui_range    (0.0, 1.0)
38 
39 property_double (out_high, _("High output"), 1.0)
40     description (_("Highest luminance level in output"))
41     ui_range    (0.0, 1.0)
42 
43 #else
44 
45 #define GEGL_OP_POINT_FILTER
46 #define GEGL_OP_NAME     levels
47 #define GEGL_OP_C_SOURCE levels.c
48 
49 #include "gegl-op.h"
50 
51 /* GeglOperationPointFilter gives us a linear buffer to operate on
52  * in our requested pixel format
53  */
54 static gboolean
55 process (GeglOperation       *op,
56          void                *in_buf,
57          void                *out_buf,
58          glong                n_pixels,
59          const GeglRectangle *roi,
60          gint                 level)
61 {
62   GeglProperties *o = GEGL_PROPERTIES (op);
63   gfloat     *in_pixel;
64   gfloat     *out_pixel;
65   gfloat      in_range;
66   gfloat      out_range;
67   gfloat      in_offset;
68   gfloat      out_offset;
69   gfloat      scale;
70   glong       i;
71 
72   in_pixel = in_buf;
73   out_pixel = out_buf;
74 
75   in_offset = o->in_low * 1.0;
76   out_offset = o->out_low * 1.0;
77   in_range = o->in_high-o->in_low;
78   out_range = o->out_high-o->out_low;
79 
80   if (fabsf (in_range) <= EPSILON)
81     in_range = copysignf (EPSILON, in_range);
82 
83   scale = out_range/in_range;
84 
85   for (i=0; i<n_pixels; i++)
86     {
87       int c;
88       for (c=0;c<3;c++)
89         out_pixel[c] = (in_pixel[c]- in_offset) * scale + out_offset;
90       out_pixel[3] = in_pixel[3];
91       out_pixel += 4;
92       in_pixel += 4;
93     }
94   return TRUE;
95 }
96 
97 #include "opencl/gegl-cl.h"
98 
99 #include "opencl/levels.cl.h"
100 
101 static GeglClRunData *cl_data = NULL;
102 
103 /* OpenCL processing function */
104 static gboolean
105 cl_process (GeglOperation       *op,
106             cl_mem               in_tex,
107             cl_mem               out_tex,
108             size_t               global_worksize,
109             const GeglRectangle *roi,
110             gint                 level)
111 {
112   /* Retrieve a pointer to GeglProperties structure which contains all the
113    * chanted properties
114    */
115 
116   GeglProperties *o = GEGL_PROPERTIES (op);
117 
118   gfloat      in_range;
119   gfloat      out_range;
120   gfloat      in_offset;
121   gfloat      out_offset;
122   gfloat      scale;
123 
124   cl_int cl_err = 0;
125 
126   in_offset = o->in_low * 1.0;
127   out_offset = o->out_low * 1.0;
128   in_range = o->in_high-o->in_low;
129   out_range = o->out_high-o->out_low;
130 
131   if (in_range == 0.0)
132     in_range = 0.00000001;
133 
134   scale = out_range/in_range;
135 
136   if (!cl_data)
137     {
138       const char *kernel_name[] = {"kernel_levels", NULL};
139       cl_data = gegl_cl_compile_and_build (levels_cl_source, kernel_name);
140     }
141   if (!cl_data) return TRUE;
142 
143   cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 0, sizeof(cl_mem),   (void*)&in_tex);
144   CL_CHECK;
145   cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 1, sizeof(cl_mem),   (void*)&out_tex);
146   CL_CHECK;
147   cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 2, sizeof(cl_float), (void*)&in_offset);
148   CL_CHECK;
149   cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 3, sizeof(cl_float), (void*)&out_offset);
150   CL_CHECK;
151   cl_err = gegl_clSetKernelArg(cl_data->kernel[0], 4, sizeof(cl_float), (void*)&scale);
152   CL_CHECK;
153 
154   cl_err = gegl_clEnqueueNDRangeKernel(gegl_cl_get_command_queue (),
155                                         cl_data->kernel[0], 1,
156                                         NULL, &global_worksize, NULL,
157                                         0, NULL, NULL);
158   CL_CHECK;
159 
160   return FALSE;
161 
162 error:
163   return TRUE;
164 }
165 
166 
167 
168 static void
169 gegl_op_class_init (GeglOpClass *klass)
170 {
171   GeglOperationClass            *operation_class;
172   GeglOperationPointFilterClass *point_filter_class;
173   gchar                         *composition =
174     "<?xml version='1.0' encoding='UTF-8'?>"
175     "<gegl>"
176     "  <node operation='gegl:crop' width='200' height='200'/>"
177     "  <node operation='gegl:over'>"
178     "    <node operation='gegl:levels'>"
179     "      <params>"
180     "        <param name='in-low'>0.54</param>"
181     "        <param name='in-high'>0.60</param>"
182     "        <param name='out-low'>0.57</param>"
183     "        <param name='out-high'>0.68</param>"
184     "      </params>"
185     "    </node>"
186     "    <node operation='gegl:load' path='standard-input.png'/>"
187     "  </node>"
188     "  <node operation='gegl:checkerboard'>"
189     "    <params>"
190     "      <param name='color1'>rgb(0.25,0.25,0.25)</param>"
191     "      <param name='color2'>rgb(0.75,0.75,0.75)</param>"
192     "    </params>"
193     "  </node>"
194     "</gegl>";
195 
196   operation_class    = GEGL_OPERATION_CLASS (klass);
197   point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
198 
199   point_filter_class->process = process;
200   point_filter_class->cl_process = cl_process;
201 
202   operation_class->opencl_support = TRUE;
203 
204   gegl_operation_class_set_keys (operation_class,
205     "name",        "gegl:levels",
206     "title",       _("Levels"),
207     "categories" , "color",
208     "description", _("Remaps the intensity range of the image"),
209     "reference-hash", "b26ace9ce32e98b8ffa2a57f10a42e0d",
210     "reference-composition", composition,
211     NULL);
212 }
213 
214 #endif
215