Skip to main content

magick_rust/wand/
drawing.rs

1/*
2 * Copyright 2016 Mattis Marjak
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *     http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16use std::ffi::{CStr, CString};
17use std::fmt;
18
19use crate::bindings;
20
21use crate::result::MagickError;
22use crate::result::Result;
23use crate::{
24    AlignType, ClipPathUnits, DecorationType, DirectionType, FillRule, GravityType, LineCap,
25    LineJoin, PaintMethod, StretchType, StyleType,
26};
27
28wand_common!(
29    DrawingWand,
30    NewDrawingWand,
31    ClearDrawingWand,
32    IsDrawingWand,
33    CloneDrawingWand,
34    DestroyDrawingWand,
35    DrawClearException,
36    DrawGetExceptionType,
37    DrawGetException
38);
39
40impl DrawingWand {
41    /// Draw the given `text` at `(x, y)` using the current font and fill color.
42    pub fn draw_annotation(&mut self, x: f64, y: f64, text: &str) -> Result<()> {
43        let c_string = CString::new(text).map_err(|_| "could not convert to cstring")?;
44        unsafe { bindings::DrawAnnotation(self.wand, x, y, c_string.as_ptr() as *const _) };
45        Ok(())
46    }
47
48    /// Draw a circle centered at `(ox, oy)` with `(px, py)` a point on its
49    /// perimeter.
50    pub fn draw_circle(&mut self, ox: f64, oy: f64, px: f64, py: f64) {
51        unsafe {
52            bindings::DrawCircle(self.wand, ox, oy, px, py);
53        }
54    }
55
56    /// Draw a rectangle from the upper-left corner `(upper_left_x, upper_left_y)`
57    /// to the lower-right corner `(lower_right_x, lower_right_y)`.
58    pub fn draw_rectangle(
59        &mut self,
60        upper_left_x: f64,
61        upper_left_y: f64,
62        lower_right_x: f64,
63        lower_right_y: f64,
64    ) {
65        unsafe {
66            bindings::DrawRectangle(
67                self.wand,
68                upper_left_x,
69                upper_left_y,
70                lower_right_x,
71                lower_right_y,
72            );
73        }
74    }
75
76    /// Draw a rectangle with rounded corners, where `rx` and `ry` are the corner
77    /// radii in the x and y directions.
78    pub fn draw_round_rectangle(
79        &mut self,
80        upper_left_x: f64,
81        upper_left_y: f64,
82        lower_right_x: f64,
83        lower_right_y: f64,
84        rx: f64,
85        ry: f64,
86    ) {
87        unsafe {
88            bindings::DrawRoundRectangle(
89                self.wand,
90                upper_left_x,
91                upper_left_y,
92                lower_right_x,
93                lower_right_y,
94                rx,
95                ry,
96            );
97        }
98    }
99
100    /// Draw a line from `(sx, sy)` to `(ex, ey)` using the current stroke color
101    /// and width.
102    pub fn draw_line(&mut self, sx: f64, sy: f64, ex: f64, ey: f64) {
103        unsafe {
104            bindings::DrawLine(self.wand, sx, sy, ex, ey);
105        }
106    }
107
108    /// Draw a single point at `(x, y)` using the current fill color.
109    pub fn draw_point(&mut self, x: f64, y: f64) {
110        unsafe {
111            bindings::DrawPoint(self.wand, x, y);
112        }
113    }
114
115    /// Draw an arc within the bounding rectangle `(sx, sy)`-`(ex, ey)`, sweeping
116    /// from `start_degrees` to `end_degrees`.
117    pub fn draw_arc(
118        &mut self,
119        sx: f64,
120        sy: f64,
121        ex: f64,
122        ey: f64,
123        start_degrees: f64,
124        end_degrees: f64,
125    ) {
126        unsafe {
127            bindings::DrawArc(self.wand, sx, sy, ex, ey, start_degrees, end_degrees);
128        }
129    }
130
131    /// Draw an ellipse centered at `(ox, oy)` with radii `rx` and `ry`, sweeping
132    /// from `start_degrees` to `end_degrees` (use 0 and 360 for a full ellipse).
133    pub fn draw_ellipse(
134        &mut self,
135        ox: f64,
136        oy: f64,
137        rx: f64,
138        ry: f64,
139        start_degrees: f64,
140        end_degrees: f64,
141    ) {
142        unsafe {
143            bindings::DrawEllipse(self.wand, ox, oy, rx, ry, start_degrees, end_degrees);
144        }
145    }
146
147    /// Draw a closed polygon connecting the given `(x, y)` coordinates.
148    pub fn draw_polygon(&mut self, coordinates: &[(f64, f64)]) {
149        let points = Self::to_point_info(coordinates);
150        unsafe {
151            bindings::DrawPolygon(self.wand, points.len(), points.as_ptr());
152        }
153    }
154
155    /// Draw an open series of line segments connecting the given `(x, y)`
156    /// coordinates.
157    pub fn draw_polyline(&mut self, coordinates: &[(f64, f64)]) {
158        let points = Self::to_point_info(coordinates);
159        unsafe {
160            bindings::DrawPolyline(self.wand, points.len(), points.as_ptr());
161        }
162    }
163
164    /// Draw a Bezier curve through the given `(x, y)` control points.
165    pub fn draw_bezier(&mut self, coordinates: &[(f64, f64)]) {
166        let points = Self::to_point_info(coordinates);
167        unsafe {
168            bindings::DrawBezier(self.wand, points.len(), points.as_ptr());
169        }
170    }
171
172    /// Paint at `(x, y)` using the current fill color and the given paint method
173    /// (for example flood-filling a region).
174    pub fn draw_color(&mut self, x: f64, y: f64, paint_method: PaintMethod) {
175        unsafe {
176            bindings::DrawColor(self.wand, x, y, paint_method);
177        }
178    }
179
180    fn to_point_info(coordinates: &[(f64, f64)]) -> Vec<bindings::PointInfo> {
181        coordinates
182            .iter()
183            .map(|&(x, y)| bindings::PointInfo { x, y })
184            .collect()
185    }
186
187    string_set_get!(
188        get_font,                   set_font,                     DrawGetFont,                  DrawSetFont
189        get_font_family,            set_font_family,              DrawGetFontFamily,            DrawSetFontFamily
190        get_vector_graphics,        set_vector_graphics,          DrawGetVectorGraphics,        DrawSetVectorGraphics
191        get_clip_path,              set_clip_path,                DrawGetClipPath,              DrawSetClipPath
192    );
193
194    string_set_get_unchecked!(
195        get_text_encoding,
196        set_text_encoding,
197        DrawGetTextEncoding,
198        DrawSetTextEncoding
199    );
200
201    pixel_set_get!(
202        get_border_color,           set_border_color,             DrawGetBorderColor,           DrawSetBorderColor
203        get_fill_color,             set_fill_color,               DrawGetFillColor,             DrawSetFillColor
204        get_stroke_color,           set_stroke_color,             DrawGetStrokeColor,           DrawSetStrokeColor
205        get_text_under_color,       set_text_under_color,         DrawGetTextUnderColor,        DrawSetTextUnderColor
206    );
207
208    set_get_unchecked!(
209        get_gravity,                set_gravity,                  DrawGetGravity,               DrawSetGravity,               GravityType
210        get_opacity,                set_opacity,                  DrawGetOpacity,               DrawSetOpacity,               f64
211        get_clip_rule,              set_clip_rule,                DrawGetClipRule,              DrawSetClipRule,              FillRule
212        get_clip_units,             set_clip_units,               DrawGetClipUnits,             DrawSetClipUnits,             ClipPathUnits
213        get_fill_rule,              set_fill_rule,                DrawGetFillRule,              DrawSetFillRule,              FillRule
214        get_fill_opacity,           set_fill_opacity,             DrawGetFillOpacity,           DrawSetFillOpacity,           f64
215
216        get_font_size,              set_font_size,                DrawGetFontSize,              DrawSetFontSize,              f64
217        get_font_style,             set_font_style,               DrawGetFontStyle,             DrawSetFontStyle,             StyleType
218        get_font_weight,            set_font_weight,              DrawGetFontWeight,            DrawSetFontWeight,            usize
219        get_font_stretch,           set_font_stretch,             DrawGetFontStretch,           DrawSetFontStretch,           StretchType
220
221        get_stroke_dash_offset,     set_stroke_dash_offset,       DrawGetStrokeDashOffset,      DrawSetStrokeDashOffset,      f64
222        get_stroke_line_cap,        set_stroke_line_cap,          DrawGetStrokeLineCap,         DrawSetStrokeLineCap,         LineCap
223        get_stroke_line_join,       set_stroke_line_join,         DrawGetStrokeLineJoin,        DrawSetStrokeLineJoin,        LineJoin
224        get_stroke_miter_limit,     set_stroke_miter_limit,       DrawGetStrokeMiterLimit,      DrawSetStrokeMiterLimit,      usize
225        get_stroke_opacity,         set_stroke_opacity,           DrawGetStrokeOpacity,         DrawSetStrokeOpacity,         f64
226        get_stroke_width,           set_stroke_width,             DrawGetStrokeWidth,           DrawSetStrokeWidth,           f64
227        get_stroke_antialias,       set_stroke_antialias,         DrawGetStrokeAntialias,       DrawSetStrokeAntialias,       bindings::MagickBooleanType
228
229        get_text_alignment,         set_text_alignment,           DrawGetTextAlignment,         DrawSetTextAlignment,         AlignType
230        get_text_antialias,         set_text_antialias,           DrawGetTextAntialias,         DrawSetTextAntialias,         bindings::MagickBooleanType
231        get_text_decoration,        set_text_decoration,          DrawGetTextDecoration,        DrawSetTextDecoration,        DecorationType
232        get_text_direction,         set_text_direction,           DrawGetTextDirection,         DrawSetTextDirection,         DirectionType
233        get_text_kerning,           set_text_kerning,             DrawGetTextKerning,           DrawSetTextKerning,           f64
234        get_text_interline_spacing, set_text_interline_spacing,   DrawGetTextInterlineSpacing,  DrawSetTextInterlineSpacing,  f64
235        get_text_interword_spacing, set_text_interword_spacing,   DrawGetTextInterwordSpacing,  DrawSetTextInterwordSpacing,  f64
236    );
237}
238
239impl fmt::Debug for DrawingWand {
240    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
241        writeln!(f, "DrawingWand {{")?;
242        writeln!(f, "    Exception: {:?}", self.get_exception())?;
243        writeln!(f, "    IsWand: {:?}", self.is_wand())?;
244        self.fmt_unchecked_settings(f, "    ")?;
245        self.fmt_string_settings(f, "    ")?;
246        self.fmt_string_unchecked_settings(f, "    ")?;
247        self.fmt_pixel_settings(f, "    ")?;
248        writeln!(f, "}}")
249    }
250}