Update Chinese (China) translation
[gegl.git] / operations / common / exposure.c
blob3fbe49b7382631982edb6eb8a77ab6598b9f8593
1 /* This file is an image processing operation for GEGL
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.
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.
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/>.
16 * Copyright 2012,2013 Felix Ulber <felix.ulber@gmx.de>
17 * 2013 Øyvind Kolås <pippin@gimp.org>
18 * 2017 Red Hat, Inc.
21 #include "config.h"
22 #include <glib/gi18n-lib.h>
24 #ifdef GEGL_PROPERTIES
26 property_double (black_level, _("Black level"), 0.0)
27 description (_("Adjust the black level"))
28 value_range (-0.1, 0.1)
30 property_double (exposure, _("Exposure"), 0.0)
31 description (_("Relative brightness change in stops"))
32 ui_range (-10.0, 10.0)
34 #else
36 #define GEGL_OP_POINT_FILTER
37 #define GEGL_OP_NAME exposure
38 #define GEGL_OP_C_SOURCE exposure.c
40 #include "gegl-op.h"
41 #include "opencl/gegl-cl.h"
43 #ifdef _MSC_VER
44 #define exp2f (b) ((gfloat) pow (2.0, b))
45 #endif
47 typedef void (*ProcessFunc) (GeglOperation *operation,
48 void *in_buf,
49 void *out_buf,
50 glong n_pixels,
51 const GeglRectangle *roi,
52 gint level);
54 typedef struct
56 GeglClRunData **cl_data_ptr;
57 ProcessFunc process;
58 const char *kernel_name;
59 const char *kernel_source;
60 } EParamsType;
62 static GeglClRunData *cl_data_rgb = NULL;
63 static GeglClRunData *cl_data_rgba = NULL;
64 static GeglClRunData *cl_data_y = NULL;
65 static GeglClRunData *cl_data_ya = NULL;
67 static const char* kernel_source_rgb =
68 "__kernel void kernel_exposure_rgb(__global const float *in, \n"
69 " __global float *out, \n"
70 " float black_level, \n"
71 " float gain) \n"
72 "{ \n"
73 " int gid = get_global_id(0); \n"
74 " int offset = 3 * gid; \n"
75 " float3 in_v = (float3) (in[offset], in[offset + 1], in[offset+2]); \n"
76 " float3 out_v; \n"
77 " out_v.xyz = ((in_v.xyz - black_level) * gain); \n"
78 " out[offset] = out_v.x; \n"
79 " out[offset + 1] = out_v.y; \n"
80 " out[offset + 2] = out_v.z; \n"
81 "} \n";
83 static const char* kernel_source_rgba =
84 "__kernel void kernel_exposure_rgba(__global const float4 *in, \n"
85 " __global float4 *out, \n"
86 " float black_level, \n"
87 " float gain) \n"
88 "{ \n"
89 " int gid = get_global_id(0); \n"
90 " float4 in_v = in[gid]; \n"
91 " float4 out_v; \n"
92 " out_v.xyz = ((in_v.xyz - black_level) * gain); \n"
93 " out_v.w = in_v.w; \n"
94 " out[gid] = out_v; \n"
95 "} \n";
97 static const char* kernel_source_y =
98 "__kernel void kernel_exposure_y(__global const float *in, \n"
99 " __global float *out, \n"
100 " float black_level, \n"
101 " float gain) \n"
102 "{ \n"
103 " int gid = get_global_id(0); \n"
104 " float in_v = in[gid]; \n"
105 " float out_v; \n"
106 " out_v = ((in_v - black_level) * gain); \n"
107 " out[gid] = out_v; \n"
108 "} \n";
110 static const char* kernel_source_ya =
111 "__kernel void kernel_exposure_ya(__global const float2 *in, \n"
112 " __global float2 *out, \n"
113 " float black_level, \n"
114 " float gain) \n"
115 "{ \n"
116 " int gid = get_global_id(0); \n"
117 " float2 in_v = in[gid]; \n"
118 " float2 out_v; \n"
119 " out_v.x = ((in_v.x - black_level) * gain); \n"
120 " out_v.y = in_v.y; \n"
121 " out[gid] = out_v; \n"
122 "} \n";
124 static void
125 process_rgb (GeglOperation *op,
126 void *in_buf,
127 void *out_buf,
128 glong n_pixels,
129 const GeglRectangle *roi,
130 gint level)
132 GeglProperties *o = GEGL_PROPERTIES (op);
133 gfloat *in_pixel;
134 gfloat *out_pixel;
135 gfloat black_level = (gfloat) o->black_level;
136 gfloat diff;
137 gfloat exposure_negated = (gfloat) -o->exposure;
138 gfloat gain;
139 gfloat white;
141 glong i;
143 in_pixel = in_buf;
144 out_pixel = out_buf;
146 white = exp2f (exposure_negated);
147 diff = MAX (white - black_level, 0.000001);
148 gain = 1.0f / diff;
150 for (i=0; i<n_pixels; i++)
152 out_pixel[0] = (in_pixel[0] - black_level) * gain;
153 out_pixel[1] = (in_pixel[1] - black_level) * gain;
154 out_pixel[2] = (in_pixel[2] - black_level) * gain;
156 out_pixel += 3;
157 in_pixel += 3;
161 static void
162 process_rgba (GeglOperation *op,
163 void *in_buf,
164 void *out_buf,
165 glong n_pixels,
166 const GeglRectangle *roi,
167 gint level)
169 GeglProperties *o = GEGL_PROPERTIES (op);
170 gfloat *in_pixel;
171 gfloat *out_pixel;
172 gfloat black_level = (gfloat) o->black_level;
173 gfloat diff;
174 gfloat exposure_negated = (gfloat) -o->exposure;
175 gfloat gain;
176 gfloat white;
178 glong i;
180 in_pixel = in_buf;
181 out_pixel = out_buf;
183 white = exp2f (exposure_negated);
184 diff = MAX (white - black_level, 0.000001);
185 gain = 1.0f / diff;
187 for (i=0; i<n_pixels; i++)
189 out_pixel[0] = (in_pixel[0] - black_level) * gain;
190 out_pixel[1] = (in_pixel[1] - black_level) * gain;
191 out_pixel[2] = (in_pixel[2] - black_level) * gain;
192 out_pixel[3] = in_pixel[3];
194 out_pixel += 4;
195 in_pixel += 4;
199 static void
200 process_y (GeglOperation *op,
201 void *in_buf,
202 void *out_buf,
203 glong n_pixels,
204 const GeglRectangle *roi,
205 gint level)
207 GeglProperties *o = GEGL_PROPERTIES (op);
208 gfloat *in_pixel;
209 gfloat *out_pixel;
210 gfloat black_level = (gfloat) o->black_level;
211 gfloat diff;
212 gfloat exposure_negated = (gfloat) -o->exposure;
213 gfloat gain;
214 gfloat white;
216 glong i;
218 in_pixel = in_buf;
219 out_pixel = out_buf;
221 white = exp2f (exposure_negated);
222 diff = MAX (white - black_level, 0.000001);
223 gain = 1.0f / diff;
225 for (i=0; i<n_pixels; i++)
227 out_pixel[0] = (in_pixel[0] - black_level) * gain;
229 out_pixel++;
230 in_pixel++;
234 static void
235 process_ya (GeglOperation *op,
236 void *in_buf,
237 void *out_buf,
238 glong n_pixels,
239 const GeglRectangle *roi,
240 gint level)
242 GeglProperties *o = GEGL_PROPERTIES (op);
243 gfloat *in_pixel;
244 gfloat *out_pixel;
245 gfloat black_level = (gfloat) o->black_level;
246 gfloat diff;
247 gfloat exposure_negated = (gfloat) -o->exposure;
248 gfloat gain;
249 gfloat white;
251 glong i;
253 in_pixel = in_buf;
254 out_pixel = out_buf;
256 white = exp2f (exposure_negated);
257 diff = MAX (white - black_level, 0.000001);
258 gain = 1.0f / diff;
260 for (i=0; i<n_pixels; i++)
262 out_pixel[0] = (in_pixel[0] - black_level) * gain;
263 out_pixel[1] = in_pixel[1];
265 out_pixel += 2;
266 in_pixel += 2;
270 static void
271 prepare (GeglOperation *operation)
273 GeglProperties *o = GEGL_PROPERTIES (operation);
274 const Babl *space = gegl_operation_get_source_space (operation, "input");
275 EParamsType *params;
276 const Babl *format;
277 const Babl *input_format;
278 const Babl *input_model;
279 const Babl *y_model;
281 if (o->user_data == NULL)
282 o->user_data = g_slice_new0 (EParamsType);
284 params = (EParamsType *) o->user_data;
286 input_format = gegl_operation_get_source_format (operation, "input");
287 if (input_format == NULL)
289 format = babl_format ("RGBA float");
291 params->process = process_rgba;
293 params->cl_data_ptr = &cl_data_rgba;
294 params->kernel_name = "kernel_exposure_rgba";
295 params->kernel_source = kernel_source_rgba;
296 goto out;
299 input_model = babl_format_get_model (input_format);
301 if (babl_format_has_alpha (input_format))
303 y_model = babl_model_with_space ("YA", space);
304 if (input_model == y_model)
306 format = babl_format_with_space ("YA float", space);
308 params->process = process_ya;
310 params->cl_data_ptr = &cl_data_ya;
311 params->kernel_name = "kernel_exposure_ya";
312 params->kernel_source = kernel_source_ya;
314 else
316 format = babl_format_with_space ("RGBA float", space);
318 params->process = process_rgba;
320 params->cl_data_ptr = &cl_data_rgba;
321 params->kernel_name = "kernel_exposure_rgba";
322 params->kernel_source = kernel_source_rgba;
325 else
327 y_model = babl_model_with_space ("Y", space);
328 if (input_model == y_model)
330 format = babl_format_with_space ("Y float", space);
332 params->process = process_y;
334 params->cl_data_ptr = &cl_data_y;
335 params->kernel_name = "kernel_exposure_y";
336 params->kernel_source = kernel_source_y;
338 else
340 format = babl_format_with_space ("RGB float", space);
342 params->process = process_rgb;
344 params->cl_data_ptr = &cl_data_rgb;
345 params->kernel_name = "kernel_exposure_rgb";
346 params->kernel_source = kernel_source_rgb;
350 out:
351 gegl_operation_set_format (operation, "input", format);
352 gegl_operation_set_format (operation, "output", format);
355 /* GeglOperationPointFilter gives us a linear buffer to operate on
356 * in our requested pixel format
358 static gboolean
359 process (GeglOperation *operation,
360 void *in_buf,
361 void *out_buf,
362 glong n_pixels,
363 const GeglRectangle *roi,
364 gint level)
366 GeglProperties *o = GEGL_PROPERTIES (operation);
367 EParamsType *params = (EParamsType *) o->user_data;
369 params->process (operation, in_buf, out_buf, n_pixels, roi, level);
370 return TRUE;
373 /* OpenCL processing function */
374 static cl_int
375 cl_process (GeglOperation *op,
376 cl_mem in_tex,
377 cl_mem out_tex,
378 size_t global_worksize,
379 const GeglRectangle *roi,
380 gint level)
382 /* Retrieve a pointer to GeglProperties structure which contains all the
383 * chanted properties
386 GeglProperties *o = GEGL_PROPERTIES (op);
387 EParamsType *params = (EParamsType *) o->user_data;
389 gfloat black_level = (gfloat) o->black_level;
390 gfloat diff;
391 gfloat exposure_negated = (gfloat) -o->exposure;
392 gfloat gain;
393 gfloat white;
395 GeglClRunData *cl_data_local;
396 cl_int cl_err = 0;
398 if (*params->cl_data_ptr == NULL)
400 const char *kernel_name[] = {NULL, NULL};
402 kernel_name[0] = params->kernel_name;
403 *params->cl_data_ptr = gegl_cl_compile_and_build (params->kernel_source, kernel_name);
405 if (*params->cl_data_ptr == NULL) return 1;
407 cl_data_local = *params->cl_data_ptr;
409 white = exp2f (exposure_negated);
410 diff = MAX (white - black_level, 0.000001);
411 gain = 1.0f / diff;
413 cl_err |= gegl_clSetKernelArg(cl_data_local->kernel[0], 0, sizeof(cl_mem), (void*)&in_tex);
414 cl_err |= gegl_clSetKernelArg(cl_data_local->kernel[0], 1, sizeof(cl_mem), (void*)&out_tex);
415 cl_err |= gegl_clSetKernelArg(cl_data_local->kernel[0], 2, sizeof(cl_float), (void*)&black_level);
416 cl_err |= gegl_clSetKernelArg(cl_data_local->kernel[0], 3, sizeof(cl_float), (void*)&gain);
417 if (cl_err != CL_SUCCESS) return cl_err;
419 cl_err = gegl_clEnqueueNDRangeKernel(gegl_cl_get_command_queue (),
420 cl_data_local->kernel[0], 1,
421 NULL, &global_worksize, NULL,
422 0, NULL, NULL);
423 if (cl_err != CL_SUCCESS) return cl_err;
425 return cl_err;
428 static void
429 finalize (GObject *object)
431 GeglOperation *op = GEGL_OPERATION (object);
432 GeglProperties *o = GEGL_PROPERTIES (op);
434 if (o->user_data)
435 g_slice_free (EParamsType, o->user_data);
437 G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
440 static void
441 gegl_op_class_init (GeglOpClass *klass)
443 GObjectClass *object_class;
444 GeglOperationClass *operation_class;
445 GeglOperationPointFilterClass *point_filter_class;
446 gchar *composition =
447 "<?xml version='1.0' encoding='UTF-8'?>"
448 "<gegl>"
449 " <node operation='gegl:crop' width='200' height='200'/>"
450 " <node operation='gegl:over'>"
451 " <node operation='gegl:exposure'>"
452 " <params>"
453 " <param name='exposure'>1.5</param>"
454 " </params>"
455 " </node>"
456 " <node operation='gegl:load' path='standard-input.png'/>"
457 " </node>"
458 " <node operation='gegl:checkerboard'>"
459 " <params>"
460 " <param name='color1'>rgb(0.25,0.25,0.25)</param>"
461 " <param name='color2'>rgb(0.75,0.75,0.75)</param>"
462 " </params>"
463 " </node>"
464 "</gegl>";
466 object_class = G_OBJECT_CLASS (klass);
467 operation_class = GEGL_OPERATION_CLASS (klass);
468 point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
470 object_class->finalize = finalize;
472 operation_class->opencl_support = TRUE;
473 operation_class->prepare = prepare;
475 point_filter_class->process = process;
476 point_filter_class->cl_process = cl_process;
478 gegl_operation_class_set_keys (operation_class,
479 "name", "gegl:exposure",
480 "title", _("Exposure"),
481 "categories", "color",
482 "reference-hash", "a4ae5d7f933046aa462e0f7659bd1261",
483 "reference-composition", composition,
484 "description", _("Change exposure of an image in shutter speed stops"),
485 "op-version", "1:0",
486 NULL);
489 #endif