1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995 Spencer Kimball and Peter Mattis
3 *
4 * gimpdrawable-stroke.c
5 * Copyright (C) 2003 Simon Budig <simon@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 "libgimpbase/gimpbase.h"
28
29 #include "core-types.h"
30
31 #include "gimpchannel.h"
32 #include "gimpdrawable-fill.h"
33 #include "gimpdrawable-stroke.h"
34 #include "gimperror.h"
35 #include "gimpimage.h"
36 #include "gimpscanconvert.h"
37 #include "gimpstrokeoptions.h"
38
39 #include "vectors/gimpvectors.h"
40
41 #include "gimp-intl.h"
42
43
44 /* public functions */
45
46 void
gimp_drawable_stroke_boundary(GimpDrawable * drawable,GimpStrokeOptions * options,const GimpBoundSeg * bound_segs,gint n_bound_segs,gint offset_x,gint offset_y,gboolean push_undo)47 gimp_drawable_stroke_boundary (GimpDrawable *drawable,
48 GimpStrokeOptions *options,
49 const GimpBoundSeg *bound_segs,
50 gint n_bound_segs,
51 gint offset_x,
52 gint offset_y,
53 gboolean push_undo)
54 {
55 GimpScanConvert *scan_convert;
56
57 g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
58 g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
59 g_return_if_fail (GIMP_IS_STROKE_OPTIONS (options));
60 g_return_if_fail (bound_segs == NULL || n_bound_segs != 0);
61 g_return_if_fail (gimp_fill_options_get_style (GIMP_FILL_OPTIONS (options)) !=
62 GIMP_FILL_STYLE_PATTERN ||
63 gimp_context_get_pattern (GIMP_CONTEXT (options)) != NULL);
64
65 scan_convert = gimp_scan_convert_new_from_boundary (bound_segs, n_bound_segs,
66 offset_x, offset_y);
67
68 if (scan_convert)
69 {
70 gimp_drawable_stroke_scan_convert (drawable, options,
71 scan_convert, push_undo);
72 gimp_scan_convert_free (scan_convert);
73 }
74 }
75
76 gboolean
gimp_drawable_stroke_vectors(GimpDrawable * drawable,GimpStrokeOptions * options,GimpVectors * vectors,gboolean push_undo,GError ** error)77 gimp_drawable_stroke_vectors (GimpDrawable *drawable,
78 GimpStrokeOptions *options,
79 GimpVectors *vectors,
80 gboolean push_undo,
81 GError **error)
82 {
83 const GimpBezierDesc *bezier;
84
85 g_return_val_if_fail (GIMP_IS_DRAWABLE (drawable), FALSE);
86 g_return_val_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)), FALSE);
87 g_return_val_if_fail (GIMP_IS_STROKE_OPTIONS (options), FALSE);
88 g_return_val_if_fail (GIMP_IS_VECTORS (vectors), FALSE);
89 g_return_val_if_fail (gimp_fill_options_get_style (GIMP_FILL_OPTIONS (options)) !=
90 GIMP_FILL_STYLE_PATTERN ||
91 gimp_context_get_pattern (GIMP_CONTEXT (options)) != NULL,
92 FALSE);
93 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
94
95 bezier = gimp_vectors_get_bezier (vectors);
96
97 if (bezier && bezier->num_data >= 2)
98 {
99 GimpScanConvert *scan_convert = gimp_scan_convert_new ();
100
101 gimp_scan_convert_add_bezier (scan_convert, bezier);
102 gimp_drawable_stroke_scan_convert (drawable, options,
103 scan_convert, push_undo);
104
105 gimp_scan_convert_free (scan_convert);
106
107 return TRUE;
108 }
109
110 g_set_error_literal (error, GIMP_ERROR, GIMP_FAILED,
111 _("Not enough points to stroke"));
112
113 return FALSE;
114 }
115
116 void
gimp_drawable_stroke_scan_convert(GimpDrawable * drawable,GimpStrokeOptions * options,GimpScanConvert * scan_convert,gboolean push_undo)117 gimp_drawable_stroke_scan_convert (GimpDrawable *drawable,
118 GimpStrokeOptions *options,
119 GimpScanConvert *scan_convert,
120 gboolean push_undo)
121 {
122 gdouble width;
123 GimpUnit unit;
124
125 g_return_if_fail (GIMP_IS_DRAWABLE (drawable));
126 g_return_if_fail (gimp_item_is_attached (GIMP_ITEM (drawable)));
127 g_return_if_fail (GIMP_IS_STROKE_OPTIONS (options));
128 g_return_if_fail (scan_convert != NULL);
129 g_return_if_fail (gimp_fill_options_get_style (GIMP_FILL_OPTIONS (options)) !=
130 GIMP_FILL_STYLE_PATTERN ||
131 gimp_context_get_pattern (GIMP_CONTEXT (options)) != NULL);
132
133 if (! gimp_item_mask_intersect (GIMP_ITEM (drawable), NULL, NULL, NULL, NULL))
134 return;
135
136 width = gimp_stroke_options_get_width (options);
137 unit = gimp_stroke_options_get_unit (options);
138
139 if (unit != GIMP_UNIT_PIXEL)
140 {
141 GimpImage *image = gimp_item_get_image (GIMP_ITEM (drawable));
142 gdouble xres;
143 gdouble yres;
144
145 gimp_image_get_resolution (image, &xres, &yres);
146
147 gimp_scan_convert_set_pixel_ratio (scan_convert, yres / xres);
148
149 width = gimp_units_to_pixels (width, unit, yres);
150 }
151
152 gimp_scan_convert_stroke (scan_convert, width,
153 gimp_stroke_options_get_join_style (options),
154 gimp_stroke_options_get_cap_style (options),
155 gimp_stroke_options_get_miter_limit (options),
156 gimp_stroke_options_get_dash_offset (options),
157 gimp_stroke_options_get_dash_info (options));
158
159 gimp_drawable_fill_scan_convert (drawable, GIMP_FILL_OPTIONS (options),
160 scan_convert, push_undo);
161 }
162