1 /* GIMP - The GNU Image Manipulation Program
2  * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3  *
4  * gimp-gegl-utils.h
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 <string.h>
24 
25 #include <gegl.h>
26 #include <gegl-plugin.h>
27 
28 #include "gimp-gegl-types.h"
29 
30 #include "core/gimpprogress.h"
31 
32 #include "gimp-gegl-loops.h"
33 #include "gimp-gegl-utils.h"
34 
35 
36 GType
gimp_gegl_get_op_enum_type(const gchar * operation,const gchar * property)37 gimp_gegl_get_op_enum_type (const gchar *operation,
38                             const gchar *property)
39 {
40   GeglNode   *node;
41   GObject    *op;
42   GParamSpec *pspec;
43 
44   g_return_val_if_fail (operation != NULL, G_TYPE_NONE);
45   g_return_val_if_fail (property != NULL, G_TYPE_NONE);
46 
47   node = g_object_new (GEGL_TYPE_NODE,
48                        "operation", operation,
49                        NULL);
50   g_object_get (node, "gegl-operation", &op, NULL);
51   g_object_unref (node);
52 
53   g_return_val_if_fail (op != NULL, G_TYPE_NONE);
54 
55   pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (op), property);
56 
57   g_return_val_if_fail (G_IS_PARAM_SPEC_ENUM (pspec), G_TYPE_NONE);
58 
59   g_object_unref (op);
60 
61   return G_TYPE_FROM_CLASS (G_PARAM_SPEC_ENUM (pspec)->enum_class);
62 }
63 
64 GeglColor *
gimp_gegl_color_new(const GimpRGB * rgb)65 gimp_gegl_color_new (const GimpRGB *rgb)
66 {
67   GeglColor *color;
68 
69   g_return_val_if_fail (rgb != NULL, NULL);
70 
71   color = gegl_color_new (NULL);
72   gegl_color_set_pixel (color, babl_format ("R'G'B'A double"), rgb);
73 
74   return color;
75 }
76 
77 static void
gimp_gegl_progress_callback(GObject * object,gdouble value,GimpProgress * progress)78 gimp_gegl_progress_callback (GObject      *object,
79                              gdouble       value,
80                              GimpProgress *progress)
81 {
82   if (value == 0.0)
83     {
84       const gchar *text = g_object_get_data (object, "gimp-progress-text");
85 
86       if (gimp_progress_is_active (progress))
87         gimp_progress_set_text (progress, "%s", text);
88       else
89         gimp_progress_start (progress, FALSE, "%s", text);
90     }
91   else
92     {
93       gimp_progress_set_value (progress, value);
94 
95       if (value == 1.0)
96         gimp_progress_end (progress);
97     }
98 }
99 
100 void
gimp_gegl_progress_connect(GeglNode * node,GimpProgress * progress,const gchar * text)101 gimp_gegl_progress_connect (GeglNode     *node,
102                             GimpProgress *progress,
103                             const gchar  *text)
104 {
105   g_return_if_fail (GEGL_IS_NODE (node));
106   g_return_if_fail (GIMP_IS_PROGRESS (progress));
107   g_return_if_fail (text != NULL);
108 
109   g_signal_connect (node, "progress",
110                     G_CALLBACK (gimp_gegl_progress_callback),
111                     progress);
112 
113   g_object_set_data_full (G_OBJECT (node),
114                           "gimp-progress-text", g_strdup (text),
115                           (GDestroyNotify) g_free);
116 }
117 
118 gboolean
gimp_gegl_node_is_source_operation(GeglNode * node)119 gimp_gegl_node_is_source_operation (GeglNode *node)
120 {
121   GeglOperation *operation;
122 
123   g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);
124 
125   operation = gegl_node_get_gegl_operation (node);
126 
127   if (! operation)
128     return FALSE;
129 
130   return GEGL_IS_OPERATION_SOURCE (operation);
131 }
132 
133 gboolean
gimp_gegl_node_is_point_operation(GeglNode * node)134 gimp_gegl_node_is_point_operation (GeglNode *node)
135 {
136   GeglOperation *operation;
137 
138   g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);
139 
140   operation = gegl_node_get_gegl_operation (node);
141 
142   if (! operation)
143     return FALSE;
144 
145   return GEGL_IS_OPERATION_POINT_RENDER    (operation) ||
146          GEGL_IS_OPERATION_POINT_FILTER    (operation) ||
147          GEGL_IS_OPERATION_POINT_COMPOSER  (operation) ||
148          GEGL_IS_OPERATION_POINT_COMPOSER3 (operation);
149 }
150 
151 gboolean
gimp_gegl_node_is_area_filter_operation(GeglNode * node)152 gimp_gegl_node_is_area_filter_operation (GeglNode *node)
153 {
154   GeglOperation *operation;
155 
156   g_return_val_if_fail (GEGL_IS_NODE (node), FALSE);
157 
158   operation = gegl_node_get_gegl_operation (node);
159 
160   if (! operation)
161     return FALSE;
162 
163   return GEGL_IS_OPERATION_AREA_FILTER (operation) ||
164          /* be conservative and return TRUE for meta ops, since they may
165           * involve an area op
166           */
167          GEGL_IS_OPERATION_META (operation);
168 }
169 
170 const gchar *
gimp_gegl_node_get_key(GeglNode * node,const gchar * key)171 gimp_gegl_node_get_key (GeglNode    *node,
172                         const gchar *key)
173 {
174   const gchar *operation_name;
175 
176   g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
177 
178   operation_name = gegl_node_get_operation (node);
179 
180   if (operation_name)
181     return gegl_operation_get_key (operation_name, key);
182   else
183     return NULL;
184 }
185 
186 gboolean
gimp_gegl_node_has_key(GeglNode * node,const gchar * key)187 gimp_gegl_node_has_key (GeglNode    *node,
188                         const gchar *key)
189 {
190   return gimp_gegl_node_get_key (node, key) != NULL;
191 }
192 
193 const Babl *
gimp_gegl_node_get_format(GeglNode * node,const gchar * pad_name)194 gimp_gegl_node_get_format (GeglNode    *node,
195                            const gchar *pad_name)
196 {
197   GeglOperation *op;
198   const Babl    *format = NULL;
199 
200   g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
201   g_return_val_if_fail (pad_name != NULL, NULL);
202 
203   g_object_get (node, "gegl-operation", &op, NULL);
204 
205   if (op)
206     {
207       format = gegl_operation_get_format (op, pad_name);
208 
209       g_object_unref (op);
210     }
211 
212   if (! format)
213     format = babl_format ("RGBA float");
214 
215   return format;
216 }
217 
218 void
gimp_gegl_node_set_underlying_operation(GeglNode * node,GeglNode * operation)219 gimp_gegl_node_set_underlying_operation (GeglNode *node,
220                                          GeglNode *operation)
221 {
222   g_return_if_fail (GEGL_IS_NODE (node));
223   g_return_if_fail (operation == NULL || GEGL_IS_NODE (operation));
224 
225   g_object_set_data (G_OBJECT (node),
226                      "gimp-gegl-node-underlying-operation", operation);
227 }
228 
229 GeglNode *
gimp_gegl_node_get_underlying_operation(GeglNode * node)230 gimp_gegl_node_get_underlying_operation (GeglNode *node)
231 {
232   GeglNode *operation;
233 
234   g_return_val_if_fail (GEGL_IS_NODE (node), NULL);
235 
236   operation = g_object_get_data (G_OBJECT (node),
237                                  "gimp-gegl-node-underlying-operation");
238 
239   if (operation)
240     return gimp_gegl_node_get_underlying_operation (operation);
241   else
242     return node;
243 }
244 
245 gboolean
gimp_gegl_param_spec_has_key(GParamSpec * pspec,const gchar * key,const gchar * value)246 gimp_gegl_param_spec_has_key (GParamSpec  *pspec,
247                               const gchar *key,
248                               const gchar *value)
249 {
250   const gchar *v = gegl_param_spec_get_property_key (pspec, key);
251 
252   if (v && ! strcmp (v, value))
253     return TRUE;
254 
255   return FALSE;
256 }
257 
258 GeglBuffer *
gimp_gegl_buffer_dup(GeglBuffer * buffer)259 gimp_gegl_buffer_dup (GeglBuffer *buffer)
260 {
261   GeglBuffer          *new_buffer;
262   const GeglRectangle *extent;
263   const GeglRectangle *abyss;
264   GeglRectangle        rect;
265   gint                 shift_x;
266   gint                 shift_y;
267   gint                 tile_width;
268   gint                 tile_height;
269 
270   g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
271 
272   extent = gegl_buffer_get_extent (buffer);
273   abyss  = gegl_buffer_get_abyss  (buffer);
274 
275   g_object_get (buffer,
276                 "shift-x",     &shift_x,
277                 "shift-y",     &shift_y,
278                 "tile-width",  &tile_width,
279                 "tile-height", &tile_height,
280                 NULL);
281 
282   new_buffer = g_object_new (GEGL_TYPE_BUFFER,
283                              "format",       gegl_buffer_get_format (buffer),
284                              "x",            extent->x,
285                              "y",            extent->y,
286                              "width",        extent->width,
287                              "height",       extent->height,
288                              "abyss-x",      abyss->x,
289                              "abyss-y",      abyss->y,
290                              "abyss-width",  abyss->width,
291                              "abyss-height", abyss->height,
292                              "shift-x",      shift_x,
293                              "shift-y",      shift_y,
294                              "tile-width",   tile_width,
295                              "tile-height",  tile_height,
296                              NULL);
297 
298   gegl_rectangle_align_to_buffer (&rect, extent, buffer,
299                                   GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
300 
301   gimp_gegl_buffer_copy (buffer, &rect, GEGL_ABYSS_NONE,
302                          new_buffer, &rect);
303 
304   return new_buffer;
305 }
306 
307 gboolean
gimp_gegl_buffer_set_extent(GeglBuffer * buffer,const GeglRectangle * extent)308 gimp_gegl_buffer_set_extent (GeglBuffer          *buffer,
309                              const GeglRectangle *extent)
310 {
311   GeglRectangle aligned_old_extent;
312   GeglRectangle aligned_extent;
313   GeglRectangle old_extent_rem;
314   GeglRectangle diff_rects[4];
315   gint          n_diff_rects;
316   gint          i;
317 
318   g_return_val_if_fail (GEGL_IS_BUFFER (buffer), FALSE);
319   g_return_val_if_fail (extent != NULL, FALSE);
320 
321   gegl_rectangle_align_to_buffer (&aligned_old_extent,
322                                   gegl_buffer_get_extent (buffer), buffer,
323                                   GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
324   gegl_rectangle_align_to_buffer (&aligned_extent,
325                                   extent, buffer,
326                                   GEGL_RECTANGLE_ALIGNMENT_SUPERSET);
327 
328   n_diff_rects = gegl_rectangle_subtract (diff_rects,
329                                           &aligned_old_extent,
330                                           &aligned_extent);
331 
332   for (i = 0; i < n_diff_rects; i++)
333     gegl_buffer_clear (buffer, &diff_rects[i]);
334 
335   if (gegl_rectangle_intersect (&old_extent_rem,
336                                 gegl_buffer_get_extent (buffer),
337                                 &aligned_extent))
338     {
339       n_diff_rects = gegl_rectangle_subtract (diff_rects,
340                                               &old_extent_rem,
341                                               extent);
342 
343       for (i = 0; i < n_diff_rects; i++)
344         gegl_buffer_clear (buffer, &diff_rects[i]);
345     }
346 
347   return gegl_buffer_set_extent (buffer, extent);
348 }
349