1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpoperationprofiletransform.c
5 * Copyright (C) 2016 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 <gdk-pixbuf/gdk-pixbuf.h>
25 #include <gegl.h>
26
27 #include "libgimpconfig/gimpconfig.h"
28 #include "libgimpcolor/gimpcolor.h"
29
30 #include "operations-types.h"
31
32 #include "gimpoperationprofiletransform.h"
33
34
35 enum
36 {
37 PROP_0,
38 PROP_SRC_PROFILE,
39 PROP_SRC_FORMAT,
40 PROP_DEST_PROFILE,
41 PROP_DEST_FORMAT,
42 PROP_RENDERING_INTENT,
43 PROP_BLACK_POINT_COMPENSATION
44 };
45
46
47 static void gimp_operation_profile_transform_finalize (GObject *object);
48
49 static void gimp_operation_profile_transform_get_property (GObject *object,
50 guint property_id,
51 GValue *value,
52 GParamSpec *pspec);
53 static void gimp_operation_profile_transform_set_property (GObject *object,
54 guint property_id,
55 const GValue *value,
56 GParamSpec *pspec);
57
58 static void gimp_operation_profile_transform_prepare (GeglOperation *operation);
59 static gboolean gimp_operation_profile_transform_process (GeglOperation *operation,
60 void *in_buf,
61 void *out_buf,
62 glong samples,
63 const GeglRectangle *roi,
64 gint level);
65
66
G_DEFINE_TYPE(GimpOperationProfileTransform,gimp_operation_profile_transform,GEGL_TYPE_OPERATION_POINT_FILTER)67 G_DEFINE_TYPE (GimpOperationProfileTransform, gimp_operation_profile_transform,
68 GEGL_TYPE_OPERATION_POINT_FILTER)
69
70 #define parent_class gimp_operation_profile_transform_parent_class
71
72
73 static void
74 gimp_operation_profile_transform_class_init (GimpOperationProfileTransformClass *klass)
75 {
76 GObjectClass *object_class = G_OBJECT_CLASS (klass);
77 GeglOperationClass *operation_class = GEGL_OPERATION_CLASS (klass);
78 GeglOperationPointFilterClass *point_class = GEGL_OPERATION_POINT_FILTER_CLASS (klass);
79
80 object_class->finalize = gimp_operation_profile_transform_finalize;
81 object_class->set_property = gimp_operation_profile_transform_set_property;
82 object_class->get_property = gimp_operation_profile_transform_get_property;
83
84 gegl_operation_class_set_keys (operation_class,
85 "name", "gimp:profile-transform",
86 "categories", "color",
87 "description",
88 "Transform between two color profiles",
89 NULL);
90
91 operation_class->prepare = gimp_operation_profile_transform_prepare;
92
93 point_class->process = gimp_operation_profile_transform_process;
94
95 g_object_class_install_property (object_class, PROP_SRC_PROFILE,
96 g_param_spec_object ("src-profile",
97 "Source Profile",
98 "Source Profile",
99 GIMP_TYPE_COLOR_PROFILE,
100 G_PARAM_READWRITE |
101 G_PARAM_CONSTRUCT));
102
103 g_object_class_install_property (object_class, PROP_SRC_FORMAT,
104 g_param_spec_pointer ("src-format",
105 "Source Format",
106 "Source Format",
107 G_PARAM_READWRITE |
108 G_PARAM_CONSTRUCT));
109
110 g_object_class_install_property (object_class, PROP_DEST_PROFILE,
111 g_param_spec_object ("dest-profile",
112 "Destination Profile",
113 "Destination Profile",
114 GIMP_TYPE_COLOR_PROFILE,
115 G_PARAM_READWRITE |
116 G_PARAM_CONSTRUCT));
117
118 g_object_class_install_property (object_class, PROP_DEST_FORMAT,
119 g_param_spec_pointer ("dest-format",
120 "Destination Format",
121 "Destination Format",
122 G_PARAM_READWRITE |
123 G_PARAM_CONSTRUCT));
124
125 g_object_class_install_property (object_class, PROP_RENDERING_INTENT,
126 g_param_spec_enum ("rendering-intent",
127 "Rendering Intent",
128 "Rendering Intent",
129 GIMP_TYPE_COLOR_RENDERING_INTENT,
130 GIMP_COLOR_RENDERING_INTENT_RELATIVE_COLORIMETRIC,
131 G_PARAM_READWRITE |
132 G_PARAM_CONSTRUCT));
133
134 g_object_class_install_property (object_class, PROP_BLACK_POINT_COMPENSATION,
135 g_param_spec_boolean ("black-point-compensation",
136 "Black Point Compensation",
137 "Black Point Compensation",
138 TRUE,
139 G_PARAM_READWRITE |
140 G_PARAM_CONSTRUCT));
141 }
142
143 static void
gimp_operation_profile_transform_init(GimpOperationProfileTransform * self)144 gimp_operation_profile_transform_init (GimpOperationProfileTransform *self)
145 {
146 }
147
148 static void
gimp_operation_profile_transform_finalize(GObject * object)149 gimp_operation_profile_transform_finalize (GObject *object)
150 {
151 GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (object);
152
153 g_clear_object (&self->src_profile);
154 g_clear_object (&self->dest_profile);
155 g_clear_object (&self->transform);
156
157 G_OBJECT_CLASS (parent_class)->finalize (object);
158 }
159
160 static void
gimp_operation_profile_transform_get_property(GObject * object,guint property_id,GValue * value,GParamSpec * pspec)161 gimp_operation_profile_transform_get_property (GObject *object,
162 guint property_id,
163 GValue *value,
164 GParamSpec *pspec)
165 {
166 GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (object);
167
168 switch (property_id)
169 {
170 case PROP_SRC_PROFILE:
171 g_value_set_object (value, self->src_profile);
172 break;
173
174 case PROP_SRC_FORMAT:
175 g_value_set_pointer (value, (gpointer) self->src_format);
176 break;
177
178 case PROP_DEST_PROFILE:
179 g_value_set_object (value, self->dest_profile);
180 break;
181
182 case PROP_DEST_FORMAT:
183 g_value_set_pointer (value, (gpointer) self->dest_format);
184 break;
185
186 case PROP_RENDERING_INTENT:
187 g_value_set_enum (value, self->rendering_intent);
188 break;
189
190 case PROP_BLACK_POINT_COMPENSATION:
191 g_value_set_boolean (value, self->black_point_compensation);
192 break;
193
194 default:
195 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
196 break;
197 }
198 }
199
200 static void
gimp_operation_profile_transform_set_property(GObject * object,guint property_id,const GValue * value,GParamSpec * pspec)201 gimp_operation_profile_transform_set_property (GObject *object,
202 guint property_id,
203 const GValue *value,
204 GParamSpec *pspec)
205 {
206 GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (object);
207
208 switch (property_id)
209 {
210 case PROP_SRC_PROFILE:
211 if (self->src_profile)
212 g_object_unref (self->src_profile);
213 self->src_profile = g_value_dup_object (value);
214 break;
215
216 case PROP_SRC_FORMAT:
217 self->src_format = g_value_get_pointer (value);
218 break;
219
220 case PROP_DEST_PROFILE:
221 if (self->dest_profile)
222 g_object_unref (self->dest_profile);
223 self->dest_profile = g_value_dup_object (value);
224 break;
225
226 case PROP_DEST_FORMAT:
227 self->dest_format = g_value_get_pointer (value);
228 break;
229
230 case PROP_RENDERING_INTENT:
231 self->rendering_intent = g_value_get_enum (value);
232 break;
233
234 case PROP_BLACK_POINT_COMPENSATION:
235 self->black_point_compensation = g_value_get_boolean (value);
236 break;
237
238 default:
239 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
240 break;
241 }
242 }
243
244 static void
gimp_operation_profile_transform_prepare(GeglOperation * operation)245 gimp_operation_profile_transform_prepare (GeglOperation *operation)
246 {
247 GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (operation);
248
249 g_clear_object (&self->transform);
250
251 if (! self->src_format)
252 self->src_format = babl_format ("RGBA float");
253
254 if (! self->dest_format)
255 self->dest_format = babl_format ("RGBA float");
256
257 if (self->src_profile && self->dest_profile)
258 {
259 GimpColorTransformFlags flags = 0;
260
261 if (self->black_point_compensation)
262 flags |= GIMP_COLOR_TRANSFORM_FLAGS_BLACK_POINT_COMPENSATION;
263
264 flags |= GIMP_COLOR_TRANSFORM_FLAGS_NOOPTIMIZE;
265
266 self->transform = gimp_color_transform_new (self->src_profile,
267 self->src_format,
268 self->dest_profile,
269 self->dest_format,
270 self->rendering_intent,
271 flags);
272 }
273
274 gegl_operation_set_format (operation, "input", self->src_format);
275 gegl_operation_set_format (operation, "output", self->dest_format);
276 }
277
278 static gboolean
gimp_operation_profile_transform_process(GeglOperation * operation,void * in_buf,void * out_buf,glong samples,const GeglRectangle * roi,gint level)279 gimp_operation_profile_transform_process (GeglOperation *operation,
280 void *in_buf,
281 void *out_buf,
282 glong samples,
283 const GeglRectangle *roi,
284 gint level)
285 {
286 GimpOperationProfileTransform *self = GIMP_OPERATION_PROFILE_TRANSFORM (operation);
287 gpointer *src = in_buf;
288 gpointer *dest = out_buf;
289
290 if (self->transform)
291 {
292 gimp_color_transform_process_pixels (self->transform,
293 self->src_format,
294 src,
295 self->dest_format,
296 dest,
297 samples);
298 }
299 else
300 {
301 babl_process (babl_fish (self->src_format,
302 self->dest_format),
303 src, dest, samples);
304 }
305
306 return TRUE;
307 }
308