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