1mod path;
2mod color;
3mod image;
4
5pub use path::{PathBuilder, LineJoin, LineCap};
6pub use color::Color;
7pub use image::{Image, ImageFormat, ColorSpace as ImageColorSpace};
8
9use crate::error::Result;
10use std::fmt::Write;
11
12#[derive(Clone)]
13pub struct GraphicsContext {
14 operations: String,
15 current_color: Color,
16 stroke_color: Color,
17 line_width: f64,
18}
19
20impl GraphicsContext {
21 pub fn new() -> Self {
22 Self {
23 operations: String::new(),
24 current_color: Color::black(),
25 stroke_color: Color::black(),
26 line_width: 1.0,
27 }
28 }
29
30 pub fn move_to(&mut self, x: f64, y: f64) -> &mut Self {
31 write!(&mut self.operations, "{:.2} {:.2} m\n", x, y).unwrap();
32 self
33 }
34
35 pub fn line_to(&mut self, x: f64, y: f64) -> &mut Self {
36 write!(&mut self.operations, "{:.2} {:.2} l\n", x, y).unwrap();
37 self
38 }
39
40 pub fn curve_to(&mut self, x1: f64, y1: f64, x2: f64, y2: f64, x3: f64, y3: f64) -> &mut Self {
41 write!(&mut self.operations, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} c\n",
42 x1, y1, x2, y2, x3, y3).unwrap();
43 self
44 }
45
46 pub fn rect(&mut self, x: f64, y: f64, width: f64, height: f64) -> &mut Self {
47 write!(&mut self.operations, "{:.2} {:.2} {:.2} {:.2} re\n",
48 x, y, width, height).unwrap();
49 self
50 }
51
52 pub fn circle(&mut self, cx: f64, cy: f64, radius: f64) -> &mut Self {
53 let k = 0.552284749831;
54 let r = radius;
55
56 self.move_to(cx + r, cy);
57 self.curve_to(cx + r, cy + k * r, cx + k * r, cy + r, cx, cy + r);
58 self.curve_to(cx - k * r, cy + r, cx - r, cy + k * r, cx - r, cy);
59 self.curve_to(cx - r, cy - k * r, cx - k * r, cy - r, cx, cy - r);
60 self.curve_to(cx + k * r, cy - r, cx + r, cy - k * r, cx + r, cy);
61 self.close_path()
62 }
63
64 pub fn close_path(&mut self) -> &mut Self {
65 self.operations.push_str("h\n");
66 self
67 }
68
69 pub fn stroke(&mut self) -> &mut Self {
70 self.apply_stroke_color();
71 self.operations.push_str("S\n");
72 self
73 }
74
75 pub fn fill(&mut self) -> &mut Self {
76 self.apply_fill_color();
77 self.operations.push_str("f\n");
78 self
79 }
80
81 pub fn fill_stroke(&mut self) -> &mut Self {
82 self.apply_fill_color();
83 self.apply_stroke_color();
84 self.operations.push_str("B\n");
85 self
86 }
87
88 pub fn set_stroke_color(&mut self, color: Color) -> &mut Self {
89 self.stroke_color = color;
90 self
91 }
92
93 pub fn set_fill_color(&mut self, color: Color) -> &mut Self {
94 self.current_color = color;
95 self
96 }
97
98 pub fn set_line_width(&mut self, width: f64) -> &mut Self {
99 self.line_width = width;
100 write!(&mut self.operations, "{:.2} w\n", width).unwrap();
101 self
102 }
103
104 pub fn set_line_cap(&mut self, cap: LineCap) -> &mut Self {
105 write!(&mut self.operations, "{} J\n", cap as u8).unwrap();
106 self
107 }
108
109 pub fn set_line_join(&mut self, join: LineJoin) -> &mut Self {
110 write!(&mut self.operations, "{} j\n", join as u8).unwrap();
111 self
112 }
113
114 pub fn save_state(&mut self) -> &mut Self {
115 self.operations.push_str("q\n");
116 self
117 }
118
119 pub fn restore_state(&mut self) -> &mut Self {
120 self.operations.push_str("Q\n");
121 self
122 }
123
124 pub fn translate(&mut self, tx: f64, ty: f64) -> &mut Self {
125 write!(&mut self.operations, "1 0 0 1 {:.2} {:.2} cm\n", tx, ty).unwrap();
126 self
127 }
128
129 pub fn scale(&mut self, sx: f64, sy: f64) -> &mut Self {
130 write!(&mut self.operations, "{:.2} 0 0 {:.2} 0 0 cm\n", sx, sy).unwrap();
131 self
132 }
133
134 pub fn rotate(&mut self, angle: f64) -> &mut Self {
135 let cos = angle.cos();
136 let sin = angle.sin();
137 write!(&mut self.operations, "{:.6} {:.6} {:.6} {:.6} 0 0 cm\n",
138 cos, sin, -sin, cos).unwrap();
139 self
140 }
141
142 pub fn transform(&mut self, a: f64, b: f64, c: f64, d: f64, e: f64, f: f64) -> &mut Self {
143 write!(&mut self.operations, "{:.2} {:.2} {:.2} {:.2} {:.2} {:.2} cm\n",
144 a, b, c, d, e, f).unwrap();
145 self
146 }
147
148 pub fn rectangle(&mut self, x: f64, y: f64, width: f64, height: f64) -> &mut Self {
149 self.rect(x, y, width, height)
150 }
151
152 pub fn draw_image(&mut self, image_name: &str, x: f64, y: f64, width: f64, height: f64) -> &mut Self {
153 self.save_state();
155
156 write!(&mut self.operations, "{:.2} 0 0 {:.2} {:.2} {:.2} cm\n",
159 width, height, x, y).unwrap();
160
161 write!(&mut self.operations, "/{} Do\n", image_name).unwrap();
163
164 self.restore_state();
166
167 self
168 }
169
170 fn apply_stroke_color(&mut self) {
171 match self.stroke_color {
172 Color::Rgb(r, g, b) => {
173 write!(&mut self.operations, "{:.3} {:.3} {:.3} RG\n", r, g, b).unwrap();
174 }
175 Color::Gray(g) => {
176 write!(&mut self.operations, "{:.3} G\n", g).unwrap();
177 }
178 Color::Cmyk(c, m, y, k) => {
179 write!(&mut self.operations, "{:.3} {:.3} {:.3} {:.3} K\n", c, m, y, k).unwrap();
180 }
181 }
182 }
183
184 fn apply_fill_color(&mut self) {
185 match self.current_color {
186 Color::Rgb(r, g, b) => {
187 write!(&mut self.operations, "{:.3} {:.3} {:.3} rg\n", r, g, b).unwrap();
188 }
189 Color::Gray(g) => {
190 write!(&mut self.operations, "{:.3} g\n", g).unwrap();
191 }
192 Color::Cmyk(c, m, y, k) => {
193 write!(&mut self.operations, "{:.3} {:.3} {:.3} {:.3} k\n", c, m, y, k).unwrap();
194 }
195 }
196 }
197
198 pub(crate) fn generate_operations(&self) -> Result<Vec<u8>> {
199 Ok(self.operations.as_bytes().to_vec())
200 }
201}