Update Chinese (China) translation
[gegl.git] / operations / seamless-clone / seamless-clone.c
blob07874a29d1a8bd7f1b819cf707b3ac747add1463
1 /* This file is an image processing operation for GEGL
3 * seamless-clone.c
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")
30 ui_meta ("axis", "x")
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")
36 ui_meta ("axis", "y")
38 property_string (error_msg, _("Error message"), "")
39 description (_("An error message in case of a failure"))
41 #else
43 #define GEGL_OP_COMPOSER
44 #define GEGL_OP_NAME seamless_clone
45 #define GEGL_OP_C_FILE "seamless-clone.c"
47 #include "config.h"
48 #include <glib/gi18n-lib.h>
49 #include "gegl-op.h"
51 #include "sc-context.h"
52 #include "sc-common.h"
54 typedef struct SCProps_
56 GMutex mutex;
57 gboolean first_processing;
58 gboolean is_valid;
59 GeglScContext *context;
60 } SCProps;
62 static GeglRectangle
63 get_required_for_output (GeglOperation *operation,
64 const gchar *input_pad,
65 const GeglRectangle *region)
67 GeglRectangle *temp = NULL;
68 GeglRectangle result;
70 if (g_strcmp0 (input_pad, "input") || g_strcmp0 (input_pad, "aux"))
71 temp = gegl_operation_source_get_bounding_box (operation, input_pad);
72 else
73 g_warning ("seamless-clone::Unknown input pad \"%s\"\n", input_pad);
75 if (temp != NULL)
76 result = *temp;
77 else
79 result.width = result.height = 0;
82 return result;
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
89 static void
90 prepare (GeglOperation *operation)
92 const Babl *format = babl_format (GEGL_SC_COLOR_BABL_NAME);
93 GeglProperties *o = GEGL_PROPERTIES (operation);
94 SCProps *props;
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);
117 if (o->user_data)
119 SCProps *props = (SCProps*) o->user_data;
120 g_mutex_clear (&props->mutex);
121 if (props->context)
122 gegl_sc_context_free (props->context);
123 g_slice_free (SCProps, props);
124 o->user_data = NULL;
126 G_OBJECT_CLASS (gegl_op_parent_class)->finalize (object);
129 static gboolean
130 process (GeglOperation *operation,
131 GeglBuffer *input,
132 GeglBuffer *aux,
133 GeglBuffer *output,
134 const GeglRectangle *result,
135 gint level)
137 GeglProperties *o = GEGL_PROPERTIES (operation);
138 SCProps *props;
139 GeglScCreationError error;
140 GeglScRenderInfo info;
141 gboolean return_val;
143 g_assert (o->user_data != NULL);
145 info.bg = input;
146 info.bg_rect = *gegl_operation_source_get_bounding_box (operation, "input");
147 info.fg = aux;
148 info.fg_rect = *gegl_operation_source_get_bounding_box (operation, "aux");
149 info.xoff = o->xoff;
150 info.yoff = o->yoff;
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"),
163 0.5,
164 o->max_refine_scale,
165 &error);
166 gegl_sc_context_set_uvt_cache (props->context, TRUE);
168 else
170 gegl_sc_context_update (props->context,
171 aux,
172 gegl_operation_source_get_bounding_box (operation, "aux"),
173 0.5,
174 o->max_refine_scale,
175 &error);
178 switch (error)
180 case GEGL_SC_CREATION_ERROR_NONE:
181 props->is_valid = TRUE;
182 break;
183 case GEGL_SC_CREATION_ERROR_EMPTY:
184 error_msg = _("The foreground does not contain opaque parts");
185 break;
186 case GEGL_SC_CREATION_ERROR_TOO_SMALL:
187 error_msg = _("The foreground is too small to use");
188 break;
189 case GEGL_SC_CREATION_ERROR_HOLED_OR_SPLIT:
190 error_msg = _("The foreground contains holes and/or several unconnected parts");
191 break;
192 default:
193 g_warning ("Unknown preprocessing status %d", error);
194 break;
197 if (props->is_valid)
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);
213 if (props->is_valid)
214 return gegl_sc_context_render (props->context, &info, result, output);
215 else
216 return FALSE;
217 return return_val;
220 static void
221 notify (GObject *object,
222 GParamSpec *pspec)
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);
235 static void
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",
252 "license", "GPL3+",
253 NULL);
254 operation_class->get_required_for_output = get_required_for_output;
257 #endif