1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <cairo.h>
21 #include <gdk-pixbuf/gdk-pixbuf.h>
22 #include <gegl.h>
23
24 #include "libgimpcolor/gimpcolor.h"
25
26 #include "core-types.h"
27
28 #include "gegl/gimp-babl.h"
29 #include "gegl/gimp-gegl-apply-operation.h"
30 #include "gegl/gimp-gegl-loops.h"
31 #include "gegl/gimp-gegl-utils.h"
32
33 #include "operations/layer-modes/gimp-layer-modes.h"
34
35 #include "gimp-utils.h"
36 #include "gimpbezierdesc.h"
37 #include "gimpchannel.h"
38 #include "gimpdrawable-fill.h"
39 #include "gimperror.h"
40 #include "gimpfilloptions.h"
41 #include "gimpimage.h"
42 #include "gimppattern.h"
43 #include "gimppickable.h"
44 #include "gimpscanconvert.h"
45
46 #include "vectors/gimpvectors.h"
47
48 #include "gimp-intl.h"
49
50
51 /* public functions */
52
53 void
gimp_drawable_fill(GimpDrawable * drawable,GimpContext * context,GimpFillType fill_type)54 gimp_drawable_fill (GimpDrawable *drawable,
55 GimpContext *context,
56 GimpFillType fill_type)
57 {
58 GimpRGB color;
59 GimpPattern *pattern;
60
61 g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
62 g_return_if_fail (GIMP_IS_CONTEXT (context));
63
64 if (fill_type == GIMP_FILL_TRANSPARENT &&
65 ! gimp_drawable_has_alpha (drawable))
66 {
67 fill_type = GIMP_FILL_BACKGROUND;
68 }
69
70 if (! gimp_get_fill_params (context, fill_type, &color, &pattern, NULL))
71 return;
72
73 gimp_drawable_fill_buffer (drawable,
74 gimp_drawable_get_buffer (drawable),
75 &color, pattern, 0, 0);
76
77 gimp_drawable_update (drawable, 0, 0, -1, -1);
78 }
79
80 void
gimp_drawable_fill_buffer(GimpDrawable * drawable,GeglBuffer * buffer,const GimpRGB * color,GimpPattern * pattern,gint pattern_offset_x,gint pattern_offset_y)81 gimp_drawable_fill_buffer (GimpDrawable *drawable,
82 GeglBuffer *buffer,
83 const GimpRGB *color,
84 GimpPattern *pattern,
85 gint pattern_offset_x,
86 gint pattern_offset_y)
87 {
88 g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
89 g_return_if_fail (GEGL_IS_BUFFER (buffer));
90 g_return_if_fail (color != NULL || pattern != NULL);
91 g_return_if_fail (pattern == NULL || GIMP_IS_PATTERN (pattern));
92
93 if (pattern)
94 {
95 GeglBuffer *src_buffer;
96 GeglBuffer *dest_buffer;
97 GimpColorProfile *src_profile;
98 GimpColorProfile *dest_profile;
99
100 src_buffer = gimp_pattern_create_buffer (pattern);
101
102 src_profile = gimp_babl_format_get_color_profile (
103 gegl_buffer_get_format (src_buffer));
104 dest_profile = gimp_color_managed_get_color_profile (
105 GIMP_COLOR_MANAGED (drawable));
106
107 if (gimp_color_transform_can_gegl_copy (src_profile, dest_profile))
108 {
109 dest_buffer = g_object_ref (src_buffer);
110 }
111 else
112 {
113 dest_buffer = gegl_buffer_new (gegl_buffer_get_extent (src_buffer),
114 gegl_buffer_get_format (buffer));
115
116 gimp_gegl_convert_color_profile (
117 src_buffer, NULL, src_profile,
118 dest_buffer, NULL, dest_profile,
119 GIMP_COLOR_RENDERING_INTENT_PERCEPTUAL,
120 TRUE,
121 NULL);
122 }
123
124 gegl_buffer_set_pattern (buffer, NULL, dest_buffer,
125 pattern_offset_x, pattern_offset_y);
126
127 g_object_unref (src_buffer);
128 g_object_unref (dest_buffer);
129 }
130 else
131 {
132 GimpRGB image_color;
133 GeglColor *gegl_color;
134
135 gimp_pickable_srgb_to_image_color (GIMP_PICKABLE (drawable),
136 color, &image_color);
137
138 if (! gimp_drawable_has_alpha (drawable))
139 gimp_rgb_set_alpha (&image_color, 1.0);
140
141 gegl_color = gimp_gegl_color_new (&image_color);
142 gegl_buffer_set_color (buffer, NULL, gegl_color);
143 g_object_unref (gegl_color);
144 }
145 }
146
147 void
gimp_drawable_fill_boundary(GimpDrawable * drawable,GimpFillOptions * options,const GimpBoundSeg * bound_segs,gint n_bound_segs,gint offset_x,gint offset_y,gboolean push_undo)148 gimp_drawable_fill_boundary (GimpDrawable *drawable,
149 GimpFillOptions *options,
150 const GimpBoundSeg *bound_segs,
151 gint n_bound_segs,
152 gint offset_x,
153 gint offset_y,
154 gboolean push_undo)
155 {
156 GimpScanConvert *scan_convert;
157
158 g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
159 g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
160 g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));
161 g_return_if_fail (bound_segs == NULL || n_bound_segs != 0);
162 g_return_if_fail (gimp_fill_options_get_style (options) !=
163 GIMP_FILL_STYLE_PATTERN ||
164 gimp_context_get_pattern (GIMP_CONTEXT (options)) != NULL);
165
166 scan_convert = gimp_scan_convert_new_from_boundary (bound_segs, n_bound_segs,
167 offset_x, offset_y);
168
169 if (scan_convert)
170 {
171 gimp_drawable_fill_scan_convert (drawable, options,
172 scan_convert, push_undo);
173 gimp_scan_convert_free (scan_convert);
174 }
175 }
176
177 gboolean
gimp_drawable_fill_vectors(GimpDrawable * drawable,GimpFillOptions * options,GimpVectors * vectors,gboolean push_undo,GError ** error)178 gimp_drawable_fill_vectors (GimpDrawable *drawable,
179 GimpFillOptions *options,
180 GimpVectors *vectors,
181 gboolean push_undo,
182 GError **error)
183 {
184 const GimpBezierDesc *bezier;
185
186 g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
187 g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
188 g_return_val_if_fail (GIMP_IS_FILL_OPTIONS (options), FALSE);
189 g_return_val_if_fail (GIMP_IS_VECTORS (vectors), FALSE);
190 g_return_val_if_fail (gimp_fill_options_get_style (options) !=
191 GIMP_FILL_STYLE_PATTERN ||
192 gimp_context_get_pattern (GIMP_CONTEXT (options)) != NULL,
193 FALSE);
194 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
195
196 bezier = gimp_vectors_get_bezier (vectors);
197
198 if (bezier && bezier->num_data > 4)
199 {
200 GimpScanConvert *scan_convert = gimp_scan_convert_new ();
201
202 gimp_scan_convert_add_bezier (scan_convert, bezier);
203 gimp_drawable_fill_scan_convert (drawable, options,
204 scan_convert, push_undo);
205
206 gimp_scan_convert_free (scan_convert);
207
208 return TRUE;
209 }
210
211 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
212 _("Not enough points to fill"));
213
214 return FALSE;
215 }
216
217 void
gimp_drawable_fill_scan_convert(GimpDrawable * drawable,GimpFillOptions * options,GimpScanConvert * scan_convert,gboolean push_undo)218 gimp_drawable_fill_scan_convert (GimpDrawable *drawable,
219 GimpFillOptions *options,
220 GimpScanConvert *scan_convert,
221 gboolean push_undo)
222 {
223 GimpContext *context;
224 GeglBuffer *buffer;
225 GeglBuffer *mask_buffer;
226 gint x, y, w, h;
227 gint off_x;
228 gint off_y;
229
230 g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
231 g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
232 g_return_if_fail (GIMP_IS_FILL_OPTIONS (options));
233 g_return_if_fail (scan_convert != NULL);
234 g_return_if_fail (gimp_fill_options_get_style (options) !=
235 GIMP_FILL_STYLE_PATTERN ||
236 gimp_context_get_pattern (GIMP_CONTEXT (options)) != NULL);
237
238 context = GIMP_CONTEXT (options);
239
240 if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), &x, &y, &w, &h))
241 return;
242
243 /* fill a 1-bpp GeglBuffer with black, this will describe the shape
244 * of the stroke.
245 */
246 mask_buffer = gegl_buffer_new (GEGL_RECTANGLE (0, 0, w, h),
247 babl_format ("Y u8"));
248
249 /* render the stroke into it */
250 gimp_item_get_offset (GIMP_ITEM (drawable), &off_x, &off_y);
251
252 gimp_scan_convert_render (scan_convert, mask_buffer,
253 x + off_x, y + off_y,
254 gimp_fill_options_get_antialias (options));
255
256 buffer = gimp_fill_options_create_buffer (options, drawable,
257 GEGL_RECTANGLE (0, 0, w, h),
258 -x, -y);
259
260 gimp_gegl_apply_opacity (buffer, NULL, NULL, buffer,
261 mask_buffer, 0, 0, 1.0);
262 g_object_unref (mask_buffer);
263
264 /* Apply to drawable */
265 gimp_drawable_apply_buffer (drawable, buffer,
266 GEGL_RECTANGLE (0, 0, w, h),
267 push_undo, C_("undo-type", "Render Stroke"),
268 gimp_context_get_opacity (context),
269 gimp_context_get_paint_mode (context),
270 GIMP_LAYER_COLOR_SPACE_AUTO,
271 GIMP_LAYER_COLOR_SPACE_AUTO,
272 gimp_layer_mode_get_paint_composite_mode (
273 gimp_context_get_paint_mode (context)),
274 NULL, x, y);
275
276 g_object_unref (buffer);
277
278 gimp_drawable_update (drawable, x, y, w, h);
279 }
280