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 2015 Thomas Manni <thomas.manni@free.fr>
17  */
18 
19 #include "config.h"
20 #include <glib/gi18n-lib.h>
21 
22 #ifdef GEGL_PROPERTIES
23 
24 enum_start (gegl_component_extract)
25   enum_value (GEGL_COMPONENT_EXTRACT_RGB_RED, "rgb-r", N_("RGB Red"))
26   enum_value (GEGL_COMPONENT_EXTRACT_RGB_GREEN, "rgb-g", N_("RGB Green"))
27   enum_value (GEGL_COMPONENT_EXTRACT_RGB_BLUE, "rgb-b", N_("RGB Blue"))
28   enum_value (GEGL_COMPONENT_EXTRACT_HUE, "hue", N_("Hue"))
29   enum_value (GEGL_COMPONENT_EXTRACT_HSV_SATURATION, "hsv-s", N_("HSV Saturation"))
30   enum_value (GEGL_COMPONENT_EXTRACT_HSV_VALUE, "hsv-v", N_("HSV Value"))
31   enum_value (GEGL_COMPONENT_EXTRACT_HSL_SATURATION, "hsl-s", N_("HSL Saturation"))
32   enum_value (GEGL_COMPONENT_EXTRACT_HSL_LIGHTNESS, "hsl-l", N_("HSL Lightness"))
33   enum_value (GEGL_COMPONENT_EXTRACT_CMYK_CYAN, "cmyk-c", N_("CMYK Cyan"))
34   enum_value (GEGL_COMPONENT_EXTRACT_CMYK_MAGENTA, "cmyk-m", N_("CMYK Magenta"))
35   enum_value (GEGL_COMPONENT_EXTRACT_CMYK_YELLOW, "cmyk-y", N_("CMYK Yellow"))
36   enum_value (GEGL_COMPONENT_EXTRACT_CMYK_KEY, "cmyk-k", N_("CMYK Key"))
37   enum_value (GEGL_COMPONENT_EXTRACT_YCBCR_Y, "ycbcr-y", N_("Y'CbCr Y'"))
38   enum_value (GEGL_COMPONENT_EXTRACT_YCBCR_CB, "ycbcr-cb", N_("Y'CbCr Cb"))
39   enum_value (GEGL_COMPONENT_EXTRACT_YCBCR_CR, "ycbcr-cr", N_("Y'CbCr Cr"))
40   enum_value (GEGL_COMPONENT_EXTRACT_LAB_L, "lab-l", N_("LAB L"))
41   enum_value (GEGL_COMPONENT_EXTRACT_LAB_A, "lab-a", N_("LAB A"))
42   enum_value (GEGL_COMPONENT_EXTRACT_LAB_B, "lab-b", N_("LAB B"))
43   enum_value (GEGL_COMPONENT_EXTRACT_LCH_C, "lch-c", N_("LCH C(ab)"))
44   enum_value (GEGL_COMPONENT_EXTRACT_LCH_H, "lch-h", N_("LCH H(ab)"))
45   enum_value (GEGL_COMPONENT_EXTRACT_ALPHA, "alpha", N_("Alpha"))
46 enum_end (GeglComponentExtract)
47 
48 property_enum (component, _("Component"),
49                GeglComponentExtract, gegl_component_extract,
50                GEGL_COMPONENT_EXTRACT_RGB_RED)
51   description (_("Component to extract"))
52 
53 property_boolean (invert, _("Invert component"), FALSE)
54      description (_("Invert the extracted component"))
55 
56 property_boolean (linear, _("Linear output"), FALSE)
57      description (_("Use linear output instead of gamma corrected"))
58 
59 #else
60 
61 #define GEGL_OP_POINT_FILTER
62 #define GEGL_OP_NAME component_extract
63 #define GEGL_OP_C_SOURCE  component-extract.c
64 
65 #include "gegl-op.h"
66 
67 static void
68 prepare (GeglOperation *operation)
69 {
70   const Babl *space = gegl_operation_get_source_space (operation, "input");
71   GeglProperties *o             = GEGL_PROPERTIES (operation);
72   const Babl     *input_format  = NULL;
73   const Babl     *output_format = (o->linear ?
74                                    babl_format_with_space ("Y float", space) :
75                                    babl_format_with_space ("Y' float", space));
76 
77   switch (o->component)
78     {
79     case GEGL_COMPONENT_EXTRACT_ALPHA:
80       input_format = babl_format_with_space ("YA float", space);
81       break;
82 
83     case GEGL_COMPONENT_EXTRACT_RGB_RED:
84     case GEGL_COMPONENT_EXTRACT_RGB_GREEN:
85     case GEGL_COMPONENT_EXTRACT_RGB_BLUE:
86       input_format = babl_format_with_space ("R'G'B' float", space);
87       break;
88 
89     case GEGL_COMPONENT_EXTRACT_HUE:
90     case GEGL_COMPONENT_EXTRACT_HSV_SATURATION:
91     case GEGL_COMPONENT_EXTRACT_HSV_VALUE:
92       input_format = babl_format_with_space ("HSV float", space);
93       break;
94 
95     case GEGL_COMPONENT_EXTRACT_HSL_LIGHTNESS:
96     case GEGL_COMPONENT_EXTRACT_HSL_SATURATION:
97       input_format = babl_format_with_space ("HSL float", space);
98       break;
99 
100     case GEGL_COMPONENT_EXTRACT_CMYK_CYAN:
101     case GEGL_COMPONENT_EXTRACT_CMYK_MAGENTA:
102     case GEGL_COMPONENT_EXTRACT_CMYK_YELLOW:
103     case GEGL_COMPONENT_EXTRACT_CMYK_KEY:
104       input_format = babl_format_with_space ("CMYK float", space);
105       break;
106 
107     case GEGL_COMPONENT_EXTRACT_YCBCR_Y:
108     case GEGL_COMPONENT_EXTRACT_YCBCR_CB:
109     case GEGL_COMPONENT_EXTRACT_YCBCR_CR:
110       input_format = babl_format_with_space ("Y'CbCr float", space);
111       break;
112 
113     case GEGL_COMPONENT_EXTRACT_LAB_L:
114     case GEGL_COMPONENT_EXTRACT_LAB_A:
115     case GEGL_COMPONENT_EXTRACT_LAB_B:
116       input_format = babl_format_with_space ("CIE Lab float", space);
117       break;
118 
119     case GEGL_COMPONENT_EXTRACT_LCH_C:
120     case GEGL_COMPONENT_EXTRACT_LCH_H:
121       input_format = babl_format_with_space ("CIE LCH(ab) float", space);
122       break;
123     }
124 
125   gegl_operation_set_format (operation, "input", input_format);
126   gegl_operation_set_format (operation, "output", output_format);
127 }
128 
129 static gboolean
130 process (GeglOperation       *operation,
131          void                *in_buf,
132          void                *out_buf,
133          glong                samples,
134          const GeglRectangle *roi,
135          gint                 level)
136 {
137   GeglProperties *o      = GEGL_PROPERTIES (operation);
138   const Babl     *format = gegl_operation_get_format (operation, "input");
139   gfloat         *in     = in_buf;
140   gfloat         *out    = out_buf;
141   gint            component_index = 0;
142   gint            n_components;
143   gdouble         min = 0.0;
144   gdouble         max = 1.0;
145 
146   n_components = babl_format_get_n_components (format);
147 
148   switch (o->component)
149     {
150     case GEGL_COMPONENT_EXTRACT_RGB_RED:
151     case GEGL_COMPONENT_EXTRACT_HUE:
152     case GEGL_COMPONENT_EXTRACT_CMYK_CYAN:
153     case GEGL_COMPONENT_EXTRACT_YCBCR_Y:
154     case GEGL_COMPONENT_EXTRACT_LAB_L:
155       component_index = 0;
156 
157       if (o->component == GEGL_COMPONENT_EXTRACT_LAB_L)
158         {
159           max = 100.0;
160         }
161       break;
162 
163     case GEGL_COMPONENT_EXTRACT_RGB_GREEN:
164     case GEGL_COMPONENT_EXTRACT_HSV_SATURATION:
165     case GEGL_COMPONENT_EXTRACT_HSL_SATURATION:
166     case GEGL_COMPONENT_EXTRACT_CMYK_MAGENTA:
167     case GEGL_COMPONENT_EXTRACT_YCBCR_CB:
168     case GEGL_COMPONENT_EXTRACT_LAB_A:
169     case GEGL_COMPONENT_EXTRACT_LCH_C:
170     case GEGL_COMPONENT_EXTRACT_ALPHA:
171       component_index = 1;
172 
173       if (o->component == GEGL_COMPONENT_EXTRACT_YCBCR_CB)
174         {
175           min = -0.5;
176           max =  0.5;
177         }
178       else if (o->component == GEGL_COMPONENT_EXTRACT_LAB_A)
179         {
180           min = -127.5;
181           max =  127.5;
182         }
183       else if (o->component == GEGL_COMPONENT_EXTRACT_LCH_C)
184         {
185           max = 200.0;
186         }
187       break;
188 
189     case GEGL_COMPONENT_EXTRACT_RGB_BLUE:
190     case GEGL_COMPONENT_EXTRACT_HSV_VALUE:
191     case GEGL_COMPONENT_EXTRACT_HSL_LIGHTNESS:
192     case GEGL_COMPONENT_EXTRACT_CMYK_YELLOW:
193     case GEGL_COMPONENT_EXTRACT_YCBCR_CR:
194     case GEGL_COMPONENT_EXTRACT_LAB_B:
195     case GEGL_COMPONENT_EXTRACT_LCH_H:
196       component_index = 2;
197 
198       if (o->component == GEGL_COMPONENT_EXTRACT_YCBCR_CR)
199         {
200           min = -0.5;
201           max =  0.5;
202         }
203       else if (o->component == GEGL_COMPONENT_EXTRACT_LAB_B)
204         {
205           min = -127.5;
206           max =  127.5;
207         }
208       else if (o->component == GEGL_COMPONENT_EXTRACT_LCH_H)
209         {
210           min = 0.0;
211           max = 360.0;
212         }
213       break;
214 
215     case GEGL_COMPONENT_EXTRACT_CMYK_KEY:
216       component_index = 3;
217       break;
218     }
219 
220     while (samples--)
221       {
222         gdouble value = in[component_index];
223 
224         if (min != 0.0 || max != 1.0)
225           {
226             gdouble scale  = 1.0 / (max - min);
227             gdouble offset = -min;
228 
229             value = CLAMP ((value + offset) * scale, 0.0, 1.0);
230           }
231 
232         if (o->invert)
233           out[0] = 1.0 - value;
234         else
235           out[0] = value;
236 
237         in  += n_components;
238         out += 1;
239       }
240 
241 
242   return TRUE;
243 }
244 
245 static void
246 gegl_op_class_init (GeglOpClass *klass)
247 {
248   GeglOperationClass            *operation_class;
249   GeglOperationPointFilterClass *point_filter_class;
250 
251   operation_class    = GEGL_OPERATION_CLASS (klass);
252   point_filter_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
253 
254   operation_class->prepare        = prepare;
255   operation_class->opencl_support = FALSE;
256   point_filter_class->process     = process;
257 
258   gegl_operation_class_set_keys (operation_class,
259     "name",            "gegl:component-extract",
260     "title",           _("Extract Component"),
261     "reference-hash",  "9e9128c635e84fd177d733ba300d6ef5",
262     "reference-hashB", "1ad6d3caf43fd510eddb8b890103b5c9",
263     "categories",  "color",
264     "description", _("Extract a color model component"),
265     NULL);
266 }
267 
268 #endif
269