1 /* This file is an image processing operation for GEGL
4 * Copyright (C) 2011 Barak Itkin <lightningismyname@gmail.com>
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
20 #ifdef GEGL_PROPERTIES
22 property_int (max_refine_scale
, _("Refinement scale"), 5)
23 description (_("Maximal scale of refinement points to be used for the interpolation mesh"))
24 value_range (0, 100000)
26 property_int (xoff
, _("Offset X"), 0)
27 description (_("How much horizontal offset should applied to the paste"))
28 value_range (-100000, 100000)
29 ui_meta ("unit", "pixel-coordinate")
32 property_int (yoff
, _("Offset Y"), 0)
33 description (_("How much horizontal offset should applied to the paste"))
34 value_range (-100000, 100000)
35 ui_meta ("unit", "pixel-coordinate")
38 property_string (error_msg
, _("Error message"), "")
39 description (_("An error message in case of a failure"))
43 #define GEGL_OP_COMPOSER
44 #define GEGL_OP_NAME seamless_clone
45 #define GEGL_OP_C_FILE "seamless-clone.c"
48 #include <glib/gi18n-lib.h>
51 #include "sc-context.h"
52 #include "sc-common.h"
54 typedef struct SCProps_
57 gboolean first_processing
;
59 GeglScContext
*context
;
63 get_required_for_output (GeglOperation
*operation
,
64 const gchar
*input_pad
,
65 const GeglRectangle
*region
)
67 GeglRectangle
*temp
= NULL
;
70 if (g_strcmp0 (input_pad
, "input") || g_strcmp0 (input_pad
, "aux"))
71 temp
= gegl_operation_source_get_bounding_box (operation
, input_pad
);
73 g_warning ("seamless-clone::Unknown input pad \"%s\"\n", input_pad
);
79 result
.width
= result
.height
= 0;
85 /* The prepare function is called at least once before every processing.
86 * So, this is the right place to mark a flag to indicate the first
87 * processing so that the context object will be updated
90 prepare (GeglOperation
*operation
)
92 const Babl
*format
= babl_format (GEGL_SC_COLOR_BABL_NAME
);
93 GeglProperties
*o
= GEGL_PROPERTIES (operation
);
96 if ((props
= (SCProps
*) o
->user_data
) == NULL
)
98 props
= g_slice_new (SCProps
);
99 g_mutex_init (&props
->mutex
);
100 props
->first_processing
= TRUE
;
101 props
->is_valid
= FALSE
;
102 props
->context
= NULL
;
103 o
->user_data
= props
;
105 props
->first_processing
= TRUE
;
106 props
->is_valid
= FALSE
;
107 gegl_operation_set_format (operation
, "input", format
);
108 gegl_operation_set_format (operation
, "aux", format
);
109 gegl_operation_set_format (operation
, "output", format
);
112 static void finalize (GObject
*object
)
114 GeglOperation
*op
= (void*) object
;
115 GeglProperties
*o
= GEGL_PROPERTIES (op
);
119 SCProps
*props
= (SCProps
*) o
->user_data
;
120 g_mutex_clear (&props
->mutex
);
122 gegl_sc_context_free (props
->context
);
123 g_slice_free (SCProps
, props
);
126 G_OBJECT_CLASS (gegl_op_parent_class
)->finalize (object
);
130 process (GeglOperation
*operation
,
134 const GeglRectangle
*result
,
137 GeglProperties
*o
= GEGL_PROPERTIES (operation
);
139 GeglScCreationError error
;
140 GeglScRenderInfo info
;
143 g_assert (o
->user_data
!= NULL
);
146 info
.bg_rect
= *gegl_operation_source_get_bounding_box (operation
, "input");
148 info
.fg_rect
= *gegl_operation_source_get_bounding_box (operation
, "aux");
151 info
.render_bg
= FALSE
;
153 props
= (SCProps
*) o
->user_data
;
155 g_mutex_lock (&props
->mutex
);
156 if (props
->first_processing
)
158 const gchar
*error_msg
= "";
159 if (props
->context
== NULL
)
161 props
->context
= gegl_sc_context_new (aux
,
162 gegl_operation_source_get_bounding_box (operation
, "aux"),
166 gegl_sc_context_set_uvt_cache (props
->context
, TRUE
);
170 gegl_sc_context_update (props
->context
,
172 gegl_operation_source_get_bounding_box (operation
, "aux"),
180 case GEGL_SC_CREATION_ERROR_NONE
:
181 props
->is_valid
= TRUE
;
183 case GEGL_SC_CREATION_ERROR_EMPTY
:
184 error_msg
= _("The foreground does not contain opaque parts");
186 case GEGL_SC_CREATION_ERROR_TOO_SMALL
:
187 error_msg
= _("The foreground is too small to use");
189 case GEGL_SC_CREATION_ERROR_HOLED_OR_SPLIT
:
190 error_msg
= _("The foreground contains holes and/or several unconnected parts");
193 g_warning ("Unknown preprocessing status %d", error
);
199 if (! gegl_sc_context_prepare_render (props
->context
, &info
))
201 error_msg
= _("The opaque parts of the foreground are not above the background!");
202 props
->is_valid
= FALSE
;
206 g_free (o
->error_msg
);
207 o
->error_msg
= g_strdup (error_msg
);
209 props
->first_processing
= FALSE
;
211 g_mutex_unlock (&props
->mutex
);
214 return gegl_sc_context_render (props
->context
, &info
, result
, output
);
221 notify (GObject
*object
,
224 if (strcmp (pspec
->name
, "max-refine-steps") == 0)
226 GeglProperties
*o
= GEGL_PROPERTIES (object
);
228 g_clear_pointer (&o
->user_data
, g_free
);
231 if (G_OBJECT_CLASS (gegl_op_parent_class
)->notify
)
232 G_OBJECT_CLASS (gegl_op_parent_class
)->notify (object
, pspec
);
236 gegl_op_class_init (GeglOpClass
*klass
)
238 GeglOperationClass
*operation_class
= GEGL_OPERATION_CLASS (klass
);
239 GeglOperationComposerClass
*composer_class
= GEGL_OPERATION_COMPOSER_CLASS (klass
);
241 G_OBJECT_CLASS (klass
)->finalize
= finalize
;
242 G_OBJECT_CLASS (klass
)->notify
= notify
;
244 operation_class
->prepare
= prepare
;
245 composer_class
->process
= process
;
247 operation_class
->opencl_support
= FALSE
;
248 gegl_operation_class_set_keys (operation_class
,
249 "name", "gegl:seamless-clone",
250 "categories", "blend",
251 "description", "Seamless cloning operation",
254 operation_class
->get_required_for_output
= get_required_for_output
;