1use crate::engine::{FontManager, ZplForgeBackend};
2use crate::forge::png::PngBackend;
3use crate::{ZplError, ZplResult};
4use printpdf::*;
5
6pub struct PdfBackend {
12 png_backend: PngBackend,
13 width_dots: f64,
14 height_dots: f64,
15 resolution: f32,
16}
17
18impl Default for PdfBackend {
19 fn default() -> Self {
20 Self::new()
21 }
22}
23
24impl PdfBackend {
25 pub fn new() -> Self {
27 Self {
28 png_backend: PngBackend::new(),
29 width_dots: 0.0,
30 height_dots: 0.0,
31 resolution: 0.0,
32 }
33 }
34}
35
36impl ZplForgeBackend for PdfBackend {
37 fn setup_page(&mut self, width: f64, height: f64, resolution: f32) {
38 self.width_dots = width;
39 self.height_dots = height;
40 self.resolution = resolution;
41 self.png_backend.setup_page(width, height, resolution);
42 }
43
44 fn setup_font_manager(&mut self, font_manager: &FontManager) {
45 self.png_backend.setup_font_manager(font_manager);
46 }
47
48 fn draw_text(
49 &mut self,
50 x: u32,
51 y: u32,
52 font: char,
53 height: Option<u32>,
54 width: Option<u32>,
55 text: String,
56 reverse_print: bool,
57 color: Option<String>,
58 ) -> ZplResult<()> {
59 self.png_backend
60 .draw_text(x, y, font, height, width, text, reverse_print, color)
61 }
62
63 fn draw_graphic_box(
64 &mut self,
65 x: u32,
66 y: u32,
67 width: u32,
68 height: u32,
69 thickness: u32,
70 color: char,
71 custom_color: Option<String>,
72 rounding: u32,
73 reverse_print: bool,
74 ) -> ZplResult<()> {
75 self.png_backend.draw_graphic_box(
76 x,
77 y,
78 width,
79 height,
80 thickness,
81 color,
82 custom_color,
83 rounding,
84 reverse_print,
85 )
86 }
87
88 fn draw_graphic_circle(
89 &mut self,
90 x: u32,
91 y: u32,
92 radius: u32,
93 thickness: u32,
94 color: char,
95 custom_color: Option<String>,
96 reverse_print: bool,
97 ) -> ZplResult<()> {
98 self.png_backend.draw_graphic_circle(
99 x,
100 y,
101 radius,
102 thickness,
103 color,
104 custom_color,
105 reverse_print,
106 )
107 }
108
109 fn draw_graphic_ellipse(
110 &mut self,
111 x: u32,
112 y: u32,
113 width: u32,
114 height: u32,
115 thickness: u32,
116 color: char,
117 custom_color: Option<String>,
118 reverse_print: bool,
119 ) -> ZplResult<()> {
120 self.png_backend.draw_graphic_ellipse(
121 x,
122 y,
123 width,
124 height,
125 thickness,
126 color,
127 custom_color,
128 reverse_print,
129 )
130 }
131
132 fn draw_graphic_field(
133 &mut self,
134 x: u32,
135 y: u32,
136 width: u32,
137 height: u32,
138 data: Vec<u8>,
139 reverse_print: bool,
140 ) -> ZplResult<()> {
141 self.png_backend
142 .draw_graphic_field(x, y, width, height, data, reverse_print)
143 }
144
145 fn draw_graphic_image_custom(
146 &mut self,
147 x: u32,
148 y: u32,
149 width: u32,
150 height: u32,
151 data: String,
152 ) -> ZplResult<()> {
153 self.png_backend
154 .draw_graphic_image_custom(x, y, width, height, data)
155 }
156
157 fn draw_code128(
158 &mut self,
159 x: u32,
160 y: u32,
161 orientation: char,
162 height: u32,
163 module_width: u32,
164 interpretation_line: char,
165 interpretation_line_above: char,
166 check_digit: char,
167 mode: char,
168 data: String,
169 reverse_print: bool,
170 ) -> ZplResult<()> {
171 self.png_backend.draw_code128(
172 x,
173 y,
174 orientation,
175 height,
176 module_width,
177 interpretation_line,
178 interpretation_line_above,
179 check_digit,
180 mode,
181 data,
182 reverse_print,
183 )
184 }
185
186 fn draw_qr_code(
187 &mut self,
188 x: u32,
189 y: u32,
190 orientation: char,
191 model: u32,
192 magnification: u32,
193 error_correction: char,
194 mask: u32,
195 data: String,
196 reverse_print: bool,
197 ) -> ZplResult<()> {
198 self.png_backend.draw_qr_code(
199 x,
200 y,
201 orientation,
202 model,
203 magnification,
204 error_correction,
205 mask,
206 data,
207 reverse_print,
208 )
209 }
210
211 fn draw_code39(
212 &mut self,
213 x: u32,
214 y: u32,
215 orientation: char,
216 check_digit: char,
217 height: u32,
218 module_width: u32,
219 interpretation_line: char,
220 interpretation_line_above: char,
221 data: String,
222 reverse_print: bool,
223 ) -> ZplResult<()> {
224 self.png_backend.draw_code39(
225 x,
226 y,
227 orientation,
228 check_digit,
229 height,
230 module_width,
231 interpretation_line,
232 interpretation_line_above,
233 data,
234 reverse_print,
235 )
236 }
237
238 fn finalize(&mut self) -> ZplResult<Vec<u8>> {
239 let png_data = self.png_backend.finalize()?;
240
241 let dpi = if self.resolution == 0.0 {
242 203.2
243 } else {
244 self.resolution as f64
245 };
246 let width_pt = (self.width_dots / dpi) * 72.0;
247 let height_pt = (self.height_dots / dpi) * 72.0;
248
249 let mut doc = PdfDocument::new("Label");
250
251 let mut warnings = Vec::new();
253 let image = RawImage::decode_from_bytes(&png_data, &mut warnings)
254 .map_err(|e| ZplError::BackendError(format!("Failed to decode image: {}", e)))?;
255
256 let image_id = doc.add_image(&image);
257
258 let transform = XObjectTransform {
259 translate_x: Some(Pt(0.0)),
260 translate_y: Some(Pt(0.0)),
261 rotate: None,
262 scale_x: None,
263 scale_y: None,
264 dpi: Some(dpi as f32),
265 };
266
267 let op = Op::UseXobject {
268 id: image_id,
269 transform,
270 };
271
272 let page = PdfPage::new(
273 Mm::from(Pt(width_pt as f32)),
274 Mm::from(Pt(height_pt as f32)),
275 vec![op],
276 );
277
278 doc.pages.push(page);
279
280 let save_options = PdfSaveOptions::default();
281 let pdf_bytes = doc.save(&save_options, &mut warnings);
282
283 Ok(pdf_bytes)
284 }
285}