1use std::cell;
19use std::io;
20use std::ops;
21use std::rc;
22
23use crate::error::{Context as _, Error, ErrorKind};
24use crate::fonts;
25use crate::style::{Color, LineStyle, Style};
26use crate::{Margins, Mm, Position, Size};
27
28#[cfg(feature = "images")]
29use crate::{Rotation, Scale};
30
31struct LayerPosition(Position);
33
34impl LayerPosition {
35 pub fn from_area(area: &Area<'_>, position: Position) -> Self {
36 Self(position + area.origin)
37 }
38}
39
40struct UserSpacePosition(Position);
42
43impl UserSpacePosition {
44 pub fn from_layer(layer: &Layer<'_>, position: LayerPosition) -> Self {
45 Self(Position::new(
46 position.0.x,
47 layer.page.size.height - position.0.y,
48 ))
49 }
50}
51
52impl From<UserSpacePosition> for printpdf::Point {
53 fn from(pos: UserSpacePosition) -> printpdf::Point {
54 printpdf::Point::new(pos.0.x.into(), pos.0.y.into())
55 }
56}
57
58impl ops::Deref for UserSpacePosition {
59 type Target = Position;
60
61 fn deref(&self) -> &Self::Target {
62 &self.0
63 }
64}
65
66pub struct Renderer {
72 doc: printpdf::PdfDocumentReference,
73 pages: Vec<Page>,
75}
76
77impl Renderer {
78 pub fn new(size: impl Into<Size>, title: impl AsRef<str>) -> Result<Renderer, Error> {
80 let size = size.into();
81 let (doc, page_idx, layer_idx) = printpdf::PdfDocument::new(
82 title.as_ref(),
83 size.width.into(),
84 size.height.into(),
85 "Layer 1",
86 );
87 let page_ref = doc.get_page(page_idx);
88 let layer_ref = page_ref.get_layer(layer_idx);
89 let page = Page::new(page_ref, layer_ref, size);
90
91 Ok(Renderer {
92 doc,
93 pages: vec![page],
94 })
95 }
96
97 pub fn with_conformance(mut self, conformance: printpdf::PdfConformance) -> Self {
99 self.doc = self.doc.with_conformance(conformance);
100 self
101 }
102
103 pub fn with_creation_date(mut self, date: printpdf::OffsetDateTime) -> Self {
105 self.doc = self.doc.with_creation_date(date);
106 self
107 }
108
109 pub fn with_modification_date(mut self, date: printpdf::OffsetDateTime) -> Self {
111 self.doc = self.doc.with_mod_date(date);
112 self
113 }
114
115 pub fn add_page(&mut self, size: impl Into<Size>) {
117 let size = size.into();
118 let (page_idx, layer_idx) =
119 self.doc
120 .add_page(size.width.into(), size.height.into(), "Layer 1");
121 let page_ref = self.doc.get_page(page_idx);
122 let layer_ref = page_ref.get_layer(layer_idx);
123 self.pages.push(Page::new(page_ref, layer_ref, size))
124 }
125
126 pub fn page_count(&self) -> usize {
128 self.pages.len()
129 }
130
131 pub fn get_page(&self, idx: usize) -> Option<&Page> {
133 self.pages.get(idx)
134 }
135
136 pub fn get_page_mut(&mut self, idx: usize) -> Option<&mut Page> {
138 self.pages.get_mut(idx)
139 }
140
141 pub fn first_page(&self) -> &Page {
143 &self.pages[0]
144 }
145
146 pub fn first_page_mut(&mut self) -> &mut Page {
148 &mut self.pages[0]
149 }
150
151 pub fn last_page(&self) -> &Page {
153 &self.pages[self.pages.len() - 1]
154 }
155
156 pub fn last_page_mut(&mut self) -> &mut Page {
158 let idx = self.pages.len() - 1;
159 &mut self.pages[idx]
160 }
161
162 pub fn add_builtin_font(
165 &self,
166 builtin: printpdf::BuiltinFont,
167 ) -> Result<printpdf::IndirectFontRef, Error> {
168 self.doc
169 .add_builtin_font(builtin)
170 .context("Failed to load PDF font")
171 }
172
173 pub fn add_embedded_font(&self, data: &[u8]) -> Result<printpdf::IndirectFontRef, Error> {
176 self.doc
177 .add_external_font(data)
178 .context("Failed to load PDF font")
179 }
180
181 pub fn write(self, w: impl io::Write) -> Result<(), Error> {
183 self.doc
184 .save(&mut io::BufWriter::new(w))
185 .context("Failed to save document")
186 }
187}
188
189pub struct Page {
195 page: printpdf::PdfPageReference,
196 size: Size,
197 layers: Layers,
198}
199
200impl Page {
201 fn new(
202 page: printpdf::PdfPageReference,
203 layer: printpdf::PdfLayerReference,
204 size: Size,
205 ) -> Page {
206 Page {
207 page,
208 size,
209 layers: Layers::new(layer),
210 }
211 }
212
213 pub fn add_layer(&mut self, name: impl Into<String>) {
215 let layer = self.page.add_layer(name);
216 self.layers.push(layer);
217 }
218
219 pub fn layer_count(&self) -> usize {
221 self.layers.len()
222 }
223
224 pub fn get_layer(&self, idx: usize) -> Option<Layer<'_>> {
226 self.layers.get(idx).map(|l| Layer::new(self, l))
227 }
228
229 pub fn first_layer(&self) -> Layer<'_> {
231 Layer::new(self, self.layers.first())
232 }
233
234 pub fn last_layer(&self) -> Layer<'_> {
236 Layer::new(self, self.layers.last())
237 }
238
239 fn next_layer(&self, layer: &printpdf::PdfLayerReference) -> Layer<'_> {
240 let layer = self.layers.next(layer).unwrap_or_else(|| {
241 let layer = self
242 .page
243 .add_layer(format!("Layer {}", self.layers.len() + 1));
244 self.layers.push(layer)
245 });
246 Layer::new(self, layer)
247 }
248}
249
250#[derive(Debug)]
251struct Layers(cell::RefCell<Vec<rc::Rc<LayerData>>>);
252
253impl Layers {
254 pub fn new(layer: printpdf::PdfLayerReference) -> Self {
255 Self(vec![LayerData::from(layer).into()].into())
256 }
257
258 pub fn len(&self) -> usize {
259 self.0.borrow().len()
260 }
261
262 pub fn first(&self) -> rc::Rc<LayerData> {
263 self.0.borrow().first().unwrap().clone()
264 }
265
266 pub fn last(&self) -> rc::Rc<LayerData> {
267 self.0.borrow().last().unwrap().clone()
268 }
269
270 pub fn get(&self, idx: usize) -> Option<rc::Rc<LayerData>> {
271 self.0.borrow().get(idx).cloned()
272 }
273
274 pub fn push(&self, layer: printpdf::PdfLayerReference) -> rc::Rc<LayerData> {
275 let layer_data = rc::Rc::from(LayerData::from(layer));
276 self.0.borrow_mut().push(layer_data.clone());
277 layer_data
278 }
279
280 pub fn next(&self, layer: &printpdf::PdfLayerReference) -> Option<rc::Rc<LayerData>> {
281 self.0
282 .borrow()
283 .iter()
284 .skip_while(|l| l.layer.layer != layer.layer)
285 .nth(1)
286 .cloned()
287 }
288}
289
290#[derive(Clone)]
296pub struct Layer<'p> {
297 page: &'p Page,
298 data: rc::Rc<LayerData>,
299}
300
301impl<'p> Layer<'p> {
302 fn new(page: &'p Page, data: rc::Rc<LayerData>) -> Layer<'p> {
303 Layer { page, data }
304 }
305
306 pub fn next(&self) -> Layer<'p> {
311 self.page.next_layer(&self.data.layer)
312 }
313
314 pub fn area(&self) -> Area<'p> {
316 Area::new(self.clone(), Position::default(), self.page.size)
317 }
318
319 #[cfg(feature = "images")]
320 fn add_image(
321 &self,
322 image: &printpdf::image_crate::DynamicImage,
323 position: LayerPosition,
324 scale: Scale,
325 rotation: Rotation,
326 dpi: Option<f64>,
327 ) {
328 let dynamic_image = printpdf::Image::from_dynamic_image(image);
329 let position = self.transform_position(position);
330 dynamic_image.add_to_layer(
331 self.data.layer.clone(),
332 printpdf::ImageTransform {
333 translate_x: Some(position.x.into()),
334 translate_y: Some(position.y.into()),
335 rotate: Some(printpdf::ImageRotation {
336 angle_ccw_degrees: -(rotation
338 .degrees()
339 .expect("Could not parse rotation into degrees")),
340 ..Default::default()
341 }),
342 scale_x: Some(scale.x),
343 scale_y: Some(scale.y),
344 dpi,
345 },
346 );
347 }
348
349 fn add_line_shape<I>(&self, points: I)
350 where
351 I: IntoIterator<Item = LayerPosition>,
352 {
353 let line_points: Vec<_> = points
354 .into_iter()
355 .map(|pos| (self.transform_position(pos).into(), false))
356 .collect();
357 let line = printpdf::Line {
358 points: line_points,
359 is_closed: false,
360 has_fill: false,
361 has_stroke: true,
362 is_clipping_path: false,
363 };
364 self.data.layer.add_shape(line);
365 }
366
367 fn set_fill_color(&self, color: Option<Color>) {
368 if self.data.update_fill_color(color) {
369 self.data
370 .layer
371 .set_fill_color(color.unwrap_or(Color::Rgb(0, 0, 0)).into());
372 }
373 }
374
375 fn set_outline_thickness(&self, thickness: Mm) {
376 if self.data.update_outline_thickness(thickness) {
377 self.data
378 .layer
379 .set_outline_thickness(printpdf::Pt::from(thickness).0);
380 }
381 }
382
383 fn set_outline_color(&self, color: Color) {
384 if self.data.update_outline_color(color) {
385 self.data.layer.set_outline_color(color.into());
386 }
387 }
388
389 fn set_text_cursor(&self, cursor: LayerPosition) {
390 let cursor = self.transform_position(cursor);
391 self.data
392 .layer
393 .set_text_cursor(cursor.x.into(), cursor.y.into());
394 }
395
396 fn begin_text_section(&self) {
397 self.data.layer.begin_text_section();
398 }
399
400 fn end_text_section(&self) {
401 self.data.layer.end_text_section();
402 }
403
404 fn add_line_break(&self) {
405 self.data.layer.add_line_break();
406 }
407
408 fn set_line_height(&self, line_height: Mm) {
409 self.data.layer.set_line_height(line_height.0);
410 }
411
412 fn set_font(&self, font: &printpdf::IndirectFontRef, font_size: u8) {
413 self.data.layer.set_font(font, font_size.into());
414 }
415
416 fn write_positioned_codepoints<P, C>(&self, positions: P, codepoints: C)
417 where
418 P: IntoIterator<Item = i64>,
419 C: IntoIterator<Item = u16>,
420 {
421 self.data
422 .layer
423 .write_positioned_codepoints(positions.into_iter().zip(codepoints.into_iter()));
424 }
425
426 fn transform_position(&self, position: LayerPosition) -> UserSpacePosition {
429 UserSpacePosition::from_layer(self, position)
430 }
431}
432
433#[derive(Debug)]
434struct LayerData {
435 layer: printpdf::PdfLayerReference,
436 fill_color: cell::Cell<Color>,
437 outline_color: cell::Cell<Color>,
438 outline_thickness: cell::Cell<Mm>,
439}
440
441impl LayerData {
442 pub fn update_fill_color(&self, color: Option<Color>) -> bool {
443 let color = color.unwrap_or(Color::Rgb(0, 0, 0));
444 self.fill_color.replace(color) != color
445 }
446
447 pub fn update_outline_color(&self, color: Color) -> bool {
448 self.outline_color.replace(color) != color
449 }
450
451 pub fn update_outline_thickness(&self, thickness: Mm) -> bool {
452 self.outline_thickness.replace(thickness) != thickness
453 }
454}
455
456impl From<printpdf::PdfLayerReference> for LayerData {
457 fn from(layer: printpdf::PdfLayerReference) -> Self {
458 Self {
459 layer,
460 fill_color: Color::Rgb(0, 0, 0).into(),
461 outline_color: Color::Rgb(0, 0, 0).into(),
462 outline_thickness: Mm::from(printpdf::Pt(1.0)).into(),
463 }
464 }
465}
466
467#[derive(Clone)]
474pub struct Area<'p> {
475 layer: Layer<'p>,
476 origin: Position,
477 size: Size,
478}
479
480impl<'p> Area<'p> {
481 fn new(layer: Layer<'p>, origin: Position, size: Size) -> Area<'p> {
482 Area {
483 layer,
484 origin,
485 size,
486 }
487 }
488
489 pub fn next_layer(&self) -> Self {
494 let layer = self.layer.next();
495 Self {
496 layer,
497 origin: self.origin,
498 size: self.size,
499 }
500 }
501
502 pub fn add_margins(&mut self, margins: impl Into<Margins>) {
504 let margins = margins.into();
505 self.origin.x += margins.left;
506 self.origin.y += margins.top;
507 self.size.width -= margins.left + margins.right;
508 self.size.height -= margins.top + margins.bottom;
509 }
510
511 pub fn size(&self) -> Size {
513 self.size
514 }
515
516 pub fn add_offset(&mut self, offset: impl Into<Position>) {
518 let offset = offset.into();
519 self.origin.x += offset.x;
520 self.origin.y += offset.y;
521 self.size.width -= offset.x;
522 self.size.height -= offset.y;
523 }
524
525 pub fn set_size(&mut self, size: impl Into<Size>) {
527 self.size = size.into();
528 }
529
530 pub fn set_width(&mut self, width: Mm) {
532 self.size.width = width;
533 }
534
535 pub fn set_height(&mut self, height: Mm) {
537 self.size.height = height;
538 }
539
540 pub fn split_horizontally(&self, weights: &[usize]) -> Vec<Area<'p>> {
546 let total_weight: usize = weights.iter().sum();
547 let factor = self.size.width / total_weight as f64;
548 let widths = weights.iter().map(|weight| factor * *weight as f64);
549 let mut offset = Mm(0.0);
550 let mut areas = Vec::new();
551 for width in widths {
552 let mut area = self.clone();
553 area.origin.x += offset;
554 area.size.width = width;
555 areas.push(area);
556 offset += width;
557 }
558 areas
559 }
560
561 #[cfg(feature = "images")]
572 pub fn add_image(
573 &self,
574 image: &printpdf::image_crate::DynamicImage,
575 position: Position,
576 scale: Scale,
577 rotation: Rotation,
578 dpi: Option<f64>,
579 ) {
580 self.layer
581 .add_image(image, self.position(position), scale, rotation, dpi);
582 }
583
584 pub fn draw_line<I>(&self, points: I, line_style: LineStyle)
588 where
589 I: IntoIterator<Item = Position>,
590 {
591 self.layer.set_outline_thickness(line_style.thickness());
592 self.layer.set_outline_color(line_style.color());
593 self.layer
594 .add_line_shape(points.into_iter().map(|pos| self.position(pos)));
595 }
596
597 pub fn print_str<S: AsRef<str>>(
603 &self,
604 font_cache: &fonts::FontCache,
605 position: Position,
606 style: Style,
607 s: S,
608 ) -> Result<bool, Error> {
609 if let Some(mut section) =
610 self.text_section(font_cache, position, style.metrics(font_cache))
611 {
612 section.print_str(s, style)?;
613 Ok(true)
614 } else {
615 Ok(false)
616 }
617 }
618
619 pub fn text_section<'f>(
625 &self,
626 font_cache: &'f fonts::FontCache,
627 position: Position,
628 metrics: fonts::Metrics,
629 ) -> Option<TextSection<'f, 'p>> {
630 let mut area = self.clone();
631 area.add_offset(position);
632 TextSection::new(font_cache, area, metrics)
633 }
634
635 fn position(&self, position: Position) -> LayerPosition {
637 LayerPosition::from_area(self, position)
638 }
639}
640
641pub struct TextSection<'f, 'p> {
643 font_cache: &'f fonts::FontCache,
644 area: Area<'p>,
645 is_first: bool,
646 metrics: fonts::Metrics,
647 font: Option<(printpdf::IndirectFontRef, u8)>,
648}
649
650impl<'f, 'p> TextSection<'f, 'p> {
651 fn new(
652 font_cache: &'f fonts::FontCache,
653 area: Area<'p>,
654 metrics: fonts::Metrics,
655 ) -> Option<TextSection<'f, 'p>> {
656 if metrics.glyph_height > area.size.height {
657 return None;
658 }
659
660 area.layer.begin_text_section();
661 area.layer.set_line_height(metrics.line_height);
662
663 Some(TextSection {
664 font_cache,
665 area,
666 is_first: true,
667 metrics,
668 font: None,
669 })
670 }
671
672 fn set_text_cursor(&self, x_offset: Mm) {
673 let cursor = self
674 .area
675 .position(Position::new(x_offset, self.metrics.ascent));
676 self.area.layer.set_text_cursor(cursor);
677 }
678
679 fn set_font(&mut self, font: &printpdf::IndirectFontRef, font_size: u8) {
680 let font_is_set = self
681 .font
682 .as_ref()
683 .map(|(font, font_size)| (font, *font_size))
684 .map(|data| data == (font, font_size))
685 .unwrap_or_default();
686 if !font_is_set {
687 self.font = Some((font.clone(), font_size));
688 self.area.layer.set_font(font, font_size);
689 }
690 }
691
692 #[must_use]
695 pub fn add_newline(&mut self) -> bool {
696 if self.metrics.line_height > self.area.size.height {
697 false
698 } else {
699 self.area.layer.add_line_break();
700 self.area.add_offset((0, self.metrics.line_height));
701 true
702 }
703 }
704
705 pub fn print_str(&mut self, s: impl AsRef<str>, style: Style) -> Result<(), Error> {
709 let font = style.font(self.font_cache);
710 let s = s.as_ref();
711
712 if self.is_first {
714 let x_offset = if let Some(first_c) = s.chars().next() {
715 style.char_left_side_bearing(self.font_cache, first_c) * -1.0
716 } else {
717 Mm(0.0)
718 };
719 self.set_text_cursor(x_offset);
720 }
721 self.is_first = false;
722
723 let positions = font
724 .kerning(self.font_cache, s.chars())
725 .into_iter()
726 .map(|pos| pos * -1000.0)
728 .map(|pos| pos as i64);
729 let codepoints = if font.is_builtin() {
730 encode_win1252(s)?
732 } else {
733 font.glyph_ids(self.font_cache, s.chars())
734 };
735
736 let font = self
737 .font_cache
738 .get_pdf_font(font)
739 .expect("Could not find PDF font in font cache");
740 self.area.layer.set_fill_color(style.color());
741 self.set_font(font, style.font_size());
742
743 self.area
744 .layer
745 .write_positioned_codepoints(positions, codepoints);
746 Ok(())
747 }
748}
749
750impl<'f, 'p> Drop for TextSection<'f, 'p> {
751 fn drop(&mut self) {
752 self.area.layer.end_text_section();
753 }
754}
755
756fn encode_win1252(s: &str) -> Result<Vec<u16>, Error> {
759 let bytes: Vec<_> = lopdf::Document::encode_text(Some("WinAnsiEncoding"), s)
760 .into_iter()
761 .map(u16::from)
762 .collect();
763
764 if bytes.len() != s.chars().count() {
766 Err(Error::new(
767 format!(
768 "Tried to print a string with characters that are not supported by the \
769 Windows-1252 encoding with a built-in font: {}",
770 s
771 ),
772 ErrorKind::UnsupportedEncoding,
773 ))
774 } else {
775 Ok(bytes)
776 }
777}