1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpoperationdesaturate.c
5 * Copyright (C) 2007 Michael Natterer <mitch@gimp.org>
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <https://www.gnu.org/licenses/>.
19 */
20
21 #include "config.h"
22
23 #include <cairo.h>
24 #include <gegl.h>
25 #include <gdk-pixbuf/gdk-pixbuf.h>
26
27 #include "libgimpcolor/gimpcolor.h"
28 #include "libgimpconfig/gimpconfig.h"
29
30 #include "operations-types.h"
31
32 #include "gimpoperationdesaturate.h"
33
34 #include "gimp-intl.h"
35
36
37 enum
38 {
39 PROP_0,
40 PROP_MODE
41 };
42
43
44 static void gimp_operation_desaturate_get_property (GObject *object,
45 guint property_id,
46 GValue *value,
47 GParamSpec *pspec);
48 static void gimp_operation_desaturate_set_property (GObject *object,
49 guint property_id,
50 const GValue *value,
51 GParamSpec *pspec);
52
53 static void gimp_operation_desaturate_prepare (GeglOperation *operation);
54 static gboolean gimp_operation_desaturate_process (GeglOperation *operation,
55 void *in_buf,
56 void *out_buf,
57 glong samples,
58 const GeglRectangle *roi,
59 gint level);
60
61
G_DEFINE_TYPE(GimpOperationDesaturate,gimp_operation_desaturate,GIMP_TYPE_OPERATION_POINT_FILTER)62 G_DEFINE_TYPE (GimpOperationDesaturate, gimp_operation_desaturate,
63 GIMP_TYPE_OPERATION_POINT_FILTER)
64
65 #define parent_class gimp_operation_desaturate_parent_class
66
67
68 static void
69 gimp_operation_desaturate_class_init (GimpOperationDesaturateClass *klass)
70 {
71 GObjectClass *object_class = G_OBJECT_CLASS (klass);
72 GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
73 GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
74
75 object_class->set_property = gimp_operation_desaturate_set_property;
76 object_class->get_property = gimp_operation_desaturate_get_property;
77
78 operation_class->prepare = gimp_operation_desaturate_prepare;
79
80 point_class->process = gimp_operation_desaturate_process;
81
82 gegl_operation_class_set_keys (operation_class,
83 "name", "gimp:desaturate",
84 "categories", "color",
85 "description", _("Turn colors into shades of gray"),
86 NULL);
87
88 GIMP_CONFIG_PROP_ENUM (object_class, PROP_MODE,
89 "mode",
90 _("Mode"),
91 _("Choose shade of gray based on"),
92 GIMP_TYPE_DESATURATE_MODE,
93 GIMP_DESATURATE_LUMINANCE,
94 GIMP_PARAM_STATIC_STRINGS);
95 }
96
97 static void
gimp_operation_desaturate_init(GimpOperationDesaturate * self)98 gimp_operation_desaturate_init (GimpOperationDesaturate *self)
99 {
100 }
101
102 static void
gimp_operation_desaturate_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)103 gimp_operation_desaturate_get_property (GObject *object,
104 guint property_id,
105 GValue *value,
106 GParamSpec *pspec)
107 {
108 GimpOperationDesaturate *desaturate = GIMP_OPERATION_DESATURATE (object);
109
110 switch (property_id)
111 {
112 case PROP_MODE:
113 g_value_set_enum (value, desaturate->mode);
114 break;
115
116 default:
117 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
118 break;
119 }
120 }
121
122 static void
gimp_operation_desaturate_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)123 gimp_operation_desaturate_set_property (GObject *object,
124 guint property_id,
125 const GValue *value,
126 GParamSpec *pspec)
127 {
128 GimpOperationDesaturate *desaturate = GIMP_OPERATION_DESATURATE (object);
129
130 switch (property_id)
131 {
132 case PROP_MODE:
133 desaturate->mode = g_value_get_enum (value);
134 break;
135
136 default:
137 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
138 break;
139 }
140 }
141
142 static void
gimp_operation_desaturate_prepare(GeglOperation * operation)143 gimp_operation_desaturate_prepare (GeglOperation *operation)
144 {
145 GimpOperationDesaturate *desaturate = GIMP_OPERATION_DESATURATE (operation);
146 const Babl *format = gegl_operation_get_source_format (operation, "input");
147
148 if (desaturate->mode == GIMP_DESATURATE_LUMINANCE)
149 {
150 format = babl_format_with_space ("RGBA float", format);
151 }
152 else
153 {
154 format = babl_format_with_space ("R'G'B'A float", format);
155 }
156
157 gegl_operation_set_format (operation, "input", format);
158 gegl_operation_set_format (operation, "output", format);
159 }
160
161 static gboolean
gimp_operation_desaturate_process(GeglOperation * operation,void * in_buf,void * out_buf,glong samples,const GeglRectangle * roi,gint level)162 gimp_operation_desaturate_process (GeglOperation *operation,
163 void *in_buf,
164 void *out_buf,
165 glong samples,
166 const GeglRectangle *roi,
167 gint level)
168 {
169 GimpOperationDesaturate *desaturate = GIMP_OPERATION_DESATURATE (operation);
170 gfloat *src = in_buf;
171 gfloat *dest = out_buf;
172
173 switch (desaturate->mode)
174 {
175 case GIMP_DESATURATE_LIGHTNESS:
176 /* This is the formula for Lightness in the HSL "bi-hexcone"
177 * model: https://en.wikipedia.org/wiki/HSL_and_HSV
178 */
179 while (samples--)
180 {
181 gfloat min, max, value;
182
183 max = MAX (src[0], src[1]);
184 max = MAX (max, src[2]);
185 min = MIN (src[0], src[1]);
186 min = MIN (min, src[2]);
187
188 value = (max + min) / 2;
189
190 dest[0] = value;
191 dest[1] = value;
192 dest[2] = value;
193 dest[3] = src[3];
194
195 src += 4;
196 dest += 4;
197 }
198 break;
199
200 case GIMP_DESATURATE_LUMA:
201 case GIMP_DESATURATE_LUMINANCE:
202 while (samples--)
203 {
204 gfloat value = GIMP_RGB_LUMINANCE (src[0], src[1], src[2]);
205
206 dest[0] = value;
207 dest[1] = value;
208 dest[2] = value;
209 dest[3] = src[3];
210
211 src += 4;
212 dest += 4;
213 }
214 break;
215
216 case GIMP_DESATURATE_AVERAGE:
217 /* This is the formula for Intensity in the HSI model:
218 * https://en.wikipedia.org/wiki/HSL_and_HSV
219 */
220 while (samples--)
221 {
222 gfloat value = (src[0] + src[1] + src[2]) / 3;
223
224 dest[0] = value;
225 dest[1] = value;
226 dest[2] = value;
227 dest[3] = src[3];
228
229 src += 4;
230 dest += 4;
231 }
232 break;
233
234 case GIMP_DESATURATE_VALUE:
235 /* This is the formula for Value in the HSV model:
236 * https://en.wikipedia.org/wiki/HSL_and_HSV
237 */
238 while (samples--)
239 {
240 gfloat value;
241
242 value = MAX (src[0], src[1]);
243 value = MAX (value, src[2]);
244
245 dest[0] = value;
246 dest[1] = value;
247 dest[2] = value;
248 dest[3] = src[3];
249
250 src += 4;
251 dest += 4;
252 }
253 break;
254 }
255
256 return TRUE;
257 }
258