Update Chinese (China) translation
[gegl.git] / operations / common / saturation.c
blobc79717d8080c7e11f9e1aa45849b41026ca60f0a
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 2016 Red Hat, Inc.
17 * 2019 Øyvind Kolås
20 #include "config.h"
21 #include <glib/gi18n-lib.h>
23 #ifdef GEGL_PROPERTIES
25 enum_start (gegl_saturation_type)
26 enum_value (GEGL_SATURATION_TYPE_NATIVE, "Native", N_("Native"))
27 enum_value (GEGL_SATURATION_TYPE_CIE_LAB, "CIE-Lab", N_("CIE Lab/Lch"))
28 enum_value (GEGL_SATURATION_TYPE_CIE_YUV, "CIE-Yuv", N_("CIE Yuv"))
29 enum_end (GeglSaturationType)
31 property_double (scale, _("Scale"), 1.0)
32 description(_("Scale, strength of effect"))
33 value_range (0.0, 10.0)
34 ui_range (0.0, 2.0)
36 property_enum (colorspace, _("Interpolation Color Space"),
37 description(_("Set at Native if uncertain, the CIE based spaces might introduce hue shifts."))
38 GeglSaturationType, gegl_saturation_type,
39 GEGL_SATURATION_TYPE_NATIVE)
41 #else
43 #define GEGL_OP_POINT_FILTER
44 #define GEGL_OP_NAME saturation
45 #define GEGL_OP_C_SOURCE saturation.c
47 #include "gegl-op.h"
49 typedef void (*ProcessFunc) (GeglOperation *operation,
50 void *in_buf,
51 void *out_buf,
52 glong n_pixels,
53 const GeglRectangle *roi,
54 gint level);
56 static void
57 process_lab (GeglOperation *operation,
58 void *in_buf,
59 void *out_buf,
60 glong n_pixels,
61 const GeglRectangle *roi,
62 gint level)
64 GeglProperties *o = GEGL_PROPERTIES (operation);
65 gfloat *in = in_buf;
66 gfloat *out = out_buf;
67 glong i;
69 for (i = 0; i < n_pixels; i++)
71 out[0] = in[0];
72 out[1] = in[1] * o->scale;
73 out[2] = in[2] * o->scale;
75 in += 3;
76 out += 3;
80 static void
81 process_lab_alpha (GeglOperation *operation,
82 void *in_buf,
83 void *out_buf,
84 glong n_pixels,
85 const GeglRectangle *roi,
86 gint level)
88 GeglProperties *o = GEGL_PROPERTIES (operation);
89 gfloat *in = in_buf;
90 gfloat *out = out_buf;
91 glong i;
93 for (i = 0; i < n_pixels; i++)
95 out[0] = in[0];
96 out[1] = in[1] * o->scale;
97 out[2] = in[2] * o->scale;
98 out[3] = in[3];
100 in += 4;
101 out += 4;
105 static void
106 process_lch (GeglOperation *operation,
107 void *in_buf,
108 void *out_buf,
109 glong n_pixels,
110 const GeglRectangle *roi,
111 gint level)
113 GeglProperties *o = GEGL_PROPERTIES (operation);
114 gfloat *in = in_buf;
115 gfloat *out = out_buf;
116 glong i;
118 for (i = 0; i < n_pixels; i++)
120 out[0] = in[0];
121 out[1] = in[1] * o->scale;
122 out[2] = in[2];
124 in += 3;
125 out += 3;
129 static void
130 process_lch_alpha (GeglOperation *operation,
131 void *in_buf,
132 void *out_buf,
133 glong n_pixels,
134 const GeglRectangle *roi,
135 gint level)
137 GeglProperties *o = GEGL_PROPERTIES (operation);
138 gfloat *in = in_buf;
139 gfloat *out = out_buf;
140 glong i;
142 for (i = 0; i < n_pixels; i++)
144 out[0] = in[0];
145 out[1] = in[1] * o->scale;
146 out[2] = in[2];
147 out[3] = in[3];
149 in += 4;
150 out += 4;
155 static void
156 process_cie_yuv_alpha (GeglOperation *operation,
157 void *in_buf,
158 void *out_buf,
159 glong n_pixels,
160 const GeglRectangle *roi,
161 gint level)
163 GeglProperties *o = GEGL_PROPERTIES (operation);
164 gfloat *in = in_buf;
165 gfloat *out = out_buf;
166 glong i;
167 float scale = o->scale;
169 #define CIE_u_origin (4/19.0f)
170 #define CIE_v_origin (9/19.0f)
172 for (i = 0; i < n_pixels; i++)
174 out[0] = in[0];
175 out[1] = (in[1] - CIE_u_origin) * scale + CIE_u_origin;
176 out[2] = (in[2] - CIE_v_origin) * scale + CIE_v_origin;
177 out[3] = in[3];
179 in += 4;
180 out += 4;
184 static void
185 process_rgb_alpha (GeglOperation *operation,
186 void *in_buf,
187 void *out_buf,
188 glong n_pixels,
189 const GeglRectangle *roi,
190 gint level)
192 GeglProperties *o = GEGL_PROPERTIES (operation);
193 const Babl *space = gegl_operation_get_source_space (operation, "input");
194 gfloat *in = in_buf;
195 gfloat *out = out_buf;
196 glong i;
197 float scale = o->scale;
198 float rscale = 1.0f - o->scale;
199 double luminance[3];
200 float luminance_f[3];
202 babl_space_get_rgb_luminance (space,
203 &luminance[0], &luminance[1], &luminance[2]);
204 for (int c = 0; c < 3; c ++)
205 luminance_f[c] = luminance[c];
207 for (i = 0; i < n_pixels; i++)
209 gfloat desaturated = (in[0] * luminance_f[0] +
210 in[1] * luminance_f[1] +
211 in[2] * luminance_f[2]) * rscale;
212 for (int c = 0; c < 3; c ++)
213 out[c] = desaturated + in[c] * scale;
214 out[3] = in[3];
216 in += 4;
217 out += 4;
221 #include <stdio.h>
223 static void
224 process_cmyk_alpha (GeglOperation *operation,
225 void *in_buf,
226 void *out_buf,
227 glong n_pixels,
228 const GeglRectangle *roi,
229 gint level)
231 GeglProperties *o = GEGL_PROPERTIES (operation);
232 const Babl *space = gegl_operation_get_source_space (operation, "input");
233 const Babl *in_format = gegl_operation_get_format (operation, "input");
234 gfloat *in = in_buf;
235 gfloat *out = out_buf;
236 glong i;
237 float scale = o->scale;
238 float rscale = 1.0f - o->scale;
239 const Babl *fish1 = babl_fish (in_format, babl_format_with_space ("YA float", space));
240 const Babl *fish2 = babl_fish (babl_format_with_space ("YA float", space),
241 babl_format_with_space ("CMYKA float", space));
242 float *grayA = gegl_malloc (n_pixels * 2 * sizeof (float));
243 float *cmykA = gegl_malloc (n_pixels * 5 * sizeof (float));
244 gfloat *desaturated = cmykA;
246 babl_process (fish1, in, grayA, n_pixels);
247 babl_process (fish2, grayA, cmykA, n_pixels);
248 gegl_free (grayA);
250 for (i = 0; i < n_pixels; i++)
252 for (int c = 0; c < 4; c ++)
253 out[c] = desaturated[c] * rscale + in[c] * scale;
254 out[4] = in[4];
256 in += 5;
257 out += 5;
258 desaturated += 5;
260 gegl_free (cmykA);
264 static void prepare (GeglOperation *operation)
266 const Babl *input_format = NULL;
267 const Babl *space = gegl_operation_get_source_space (operation, "input");
268 GeglProperties *o = GEGL_PROPERTIES (operation);
269 const Babl *format;
270 BablModelFlag model_flags;
272 input_format = gegl_operation_get_source_format (operation, "input");
274 switch (o->colorspace)
276 default:
277 case GEGL_SATURATION_TYPE_NATIVE:
278 format = babl_format_with_space ("RGBA float", space);
279 o->user_data = process_rgb_alpha;
280 if (input_format)
282 model_flags = babl_get_model_flags (input_format);
283 if (model_flags & BABL_MODEL_FLAG_CMYK && o->scale < 1.0)
285 /* we only use the CMYK code path when desaturating, it provides
286 the expected result, and retains the separation - wheras for
287 increasing saturation - to achieve expected behavior we need
288 to fall back to RGBA to achieve the desired result. */
289 format = babl_format_with_space ("CMYKA float", space);
290 o->user_data = process_cmyk_alpha;
292 else if (model_flags & BABL_MODEL_FLAG_CIE)
294 format = babl_format_with_space ("CIE Lab alpha float", space);
295 o->user_data = process_lab_alpha;
297 /* otherwise we use the RGB default */
299 break;
300 case GEGL_SATURATION_TYPE_CIE_YUV:
301 format = babl_format_with_space ("CIE Yuv alpha float", space);
302 o->user_data = process_cie_yuv_alpha;
303 break;
304 case GEGL_SATURATION_TYPE_CIE_LAB:
306 const Babl *lch_model;
307 const Babl *input_model;
309 if (input_format == NULL)
311 format = babl_format_with_space ("CIE Lab alpha float", space);
312 o->user_data = process_lab_alpha;
313 goto out;
316 input_model = babl_format_get_model (input_format);
318 if (babl_format_has_alpha (input_format))
320 lch_model = babl_model_with_space ("CIE LCH(ab) alpha", space);
321 if (input_model == lch_model)
323 format = babl_format_with_space ("CIE LCH(ab) alpha float", space);
324 o->user_data = process_lch_alpha;
326 else
328 format = babl_format_with_space ("CIE Lab alpha float", space);
329 o->user_data = process_lab_alpha;
332 else
334 lch_model = babl_model_with_space ("CIE LCH(ab)", space);
335 if (input_model == lch_model)
337 format = babl_format_with_space ("CIE LCH(ab) float", space);
338 o->user_data = process_lch;
340 else
342 format = babl_format_with_space ("CIE Lab float", space);
343 o->user_data = process_lab;
347 break;
349 out:
350 gegl_operation_set_format (operation, "input", format);
351 gegl_operation_set_format (operation, "output", format);
354 static gboolean
355 process (GeglOperation *operation,
356 void *in_buf,
357 void *out_buf,
358 glong n_pixels,
359 const GeglRectangle *roi,
360 gint level)
362 GeglProperties *o = GEGL_PROPERTIES (operation);
363 ProcessFunc real_process = (ProcessFunc) o->user_data;
365 real_process (operation, in_buf, out_buf, n_pixels, roi, level);
366 return TRUE;
369 static void
370 gegl_op_class_init (GeglOpClass *klass)
372 GeglOperationClass *operation_class;
373 GeglOperationPointFilterClass *point_filter_class;
374 gchar *composition =
375 "<?xml version='1.0' encoding='UTF-8'?>"
376 "<gegl>"
377 " <node operation='gegl:crop' width='200' height='200'/>"
378 " <node operation='gegl:over'>"
379 " <node operation='gegl:saturation'>"
380 " <params>"
381 " <param name='scale'>2.0</param>"
382 " </params>"
383 " </node>"
384 " <node operation='gegl:load' path='standard-input.png'/>"
385 " </node>"
386 " <node operation='gegl:checkerboard'>"
387 " <params>"
388 " <param name='color1'>rgb(0.25,0.25,0.25)</param>"
389 " <param name='color2'>rgb(0.75,0.75,0.75)</param>"
390 " </params>"
391 " </node>"
392 "</gegl>";
394 operation_class = GEGL_OPERATION_CLASS (klass);
395 point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
397 operation_class->prepare = prepare;
398 operation_class->opencl_support = FALSE;
400 point_filter_class->process = process;
402 gegl_operation_class_set_keys (operation_class,
403 "name" , "gegl:saturation",
404 "title", _("Saturation"),
405 "categories" , "color",
406 "opi", "1:0",
407 "reference-hash", "c93c29f810f7743c454e3d8171878eee",
408 "reference-composition", composition,
409 "description", _("Changes the saturation"),
410 NULL);
413 #endif