rckive_genpdf/
render.rs

1//! Low-level PDF rendering utilities.
2//!
3//! This module provides low-level abstractions over [`printpdf`][]:  A [`Renderer`][] creates a
4//! document with one or more pages with different sizes.  A [`Page`][] has one or more layers, all
5//! of the same size.  A [`Layer`][] can be used to access its [`Area`][].
6//!
7//! An [`Area`][] is a view on a full layer or on a part of a layer.  It can be used to print
8//! lines and text.  For more advanced text formatting, you can create a [`TextSection`][] from an
9//! [`Area`][].
10//!
11//! [`printpdf`]: https://docs.rs/printpdf/latest/printpdf
12//! [`Renderer`]: struct.Renderer.html
13//! [`Page`]: struct.Page.html
14//! [`Layer`]: struct.Layer.html
15//! [`Area`]: struct.Area.html
16//! [`TextSection`]: struct.TextSection.html
17
18use 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
31/// A position relative to the top left corner of a layer.
32struct LayerPosition(Position);
33
34impl LayerPosition {
35    pub fn from_area(area: &Area<'_>, position: Position) -> Self {
36        Self(position + area.origin)
37    }
38}
39
40/// A position relative to the bottom left corner of a layer (“user space” in PDF terms).
41struct 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
66/// Renders a PDF document with one or more pages.
67///
68/// This is a wrapper around a [`printpdf::PdfDocumentReference`][].
69///
70/// [`printpdf::PdfDocumentReference`]: https://docs.rs/printpdf/0.3.2/printpdf/types/pdf_document/struct.PdfDocumentReference.html
71pub struct Renderer {
72    doc: printpdf::PdfDocumentReference,
73    // invariant: pages.len() >= 1
74    pages: Vec<Page>,
75}
76
77impl Renderer {
78    /// Creates a new PDF document renderer with one page of the given size and the given title.
79    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    /// Sets the PDF conformance for the generated PDF document.
98    pub fn with_conformance(mut self, conformance: printpdf::PdfConformance) -> Self {
99        self.doc = self.doc.with_conformance(conformance);
100        self
101    }
102
103    /// Sets the creation date for the generated PDF document.
104    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    /// Sets the modification date for the generated PDF document.
110    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    /// Adds a new page with the given size to the document.
116    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    /// Returns the number of pages in this document.
127    pub fn page_count(&self) -> usize {
128        self.pages.len()
129    }
130
131    /// Returns a page of this document.
132    pub fn get_page(&self, idx: usize) -> Option<&Page> {
133        self.pages.get(idx)
134    }
135
136    /// Returns a mutable reference to a page of this document.
137    pub fn get_page_mut(&mut self, idx: usize) -> Option<&mut Page> {
138        self.pages.get_mut(idx)
139    }
140
141    /// Returns a mutable reference to the first page of this document.
142    pub fn first_page(&self) -> &Page {
143        &self.pages[0]
144    }
145
146    /// Returns the first page of this document.
147    pub fn first_page_mut(&mut self) -> &mut Page {
148        &mut self.pages[0]
149    }
150
151    /// Returns the last page of this document.
152    pub fn last_page(&self) -> &Page {
153        &self.pages[self.pages.len() - 1]
154    }
155
156    /// Returns a mutable reference to the last page of this document.
157    pub fn last_page_mut(&mut self) -> &mut Page {
158        let idx = self.pages.len() - 1;
159        &mut self.pages[idx]
160    }
161
162    /// Loads the font from the given data, adds it to the generated document and returns a
163    /// reference to it.
164    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    /// Loads the font from the given data, adds it to the generated document and returns a
174    /// reference to it.
175    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    /// Writes this PDF document to a writer.
182    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
189/// A page of a PDF document.
190///
191/// This is a wrapper around a [`printpdf::PdfPageReference`][].
192///
193/// [`printpdf::PdfPageReference`]: https://docs.rs/printpdf/0.3.2/printpdf/types/pdf_page/struct.PdfPageReference.html
194pub 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    /// Adds a new layer with the given name to the page.
214    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    /// Returns the number of layers on this page.
220    pub fn layer_count(&self) -> usize {
221        self.layers.len()
222    }
223
224    /// Returns a layer of this page.
225    pub fn get_layer(&self, idx: usize) -> Option<Layer<'_>> {
226        self.layers.get(idx).map(|l| Layer::new(self, l))
227    }
228
229    /// Returns the first layer of this page.
230    pub fn first_layer(&self) -> Layer<'_> {
231        Layer::new(self, self.layers.first())
232    }
233
234    /// Returns the last layer of this page.
235    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/// A layer of a page of a PDF document.
291///
292/// This is a wrapper around a [`printpdf::PdfLayerReference`][].
293///
294/// [`printpdf::PdfLayerReference`]: https://docs.rs/printpdf/0.3.2/printpdf/types/pdf_layer/struct.PdfLayerReference.html
295#[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    /// Returns the next layer of this page.
307    ///
308    /// If this layer is not the last layer, the existing next layer is used.  If it is the last
309    /// layer, a new layer is created and added to the page.
310    pub fn next(&self) -> Layer<'p> {
311        self.page.next_layer(&self.data.layer)
312    }
313
314    /// Returns a drawable area for this layer.
315    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                    // rotation.degrees() is clockwise, but ImageRotation requires ccw
337                    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    /// Transforms the given position that is relative to the upper left corner of the layer to a
427    /// position that is relative to the lower left corner of the layer (as used by `printpdf`).
428    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/// A view on an area of a PDF layer that can be drawn on.
468///
469/// This struct provides access to the drawing methods of a [`printpdf::PdfLayerReference`][].  It
470/// is defined by the layer that is drawn on and the origin and the size of the area.
471///
472/// [`printpdf::PdfLayerReference`]: https://docs.rs/printpdf/0.3.2/printpdf/types/pdf_layer/struct.PdfLayerReference.html
473#[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    /// Returns a copy of this area on the next layer of the page.
490    ///
491    /// If this area is not on the last layer, the existing next layer is used.  If it is on the
492    /// last layer, a new layer is created and added to the page.
493    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    /// Reduces the size of the drawable area by the given margins.
503    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    /// Returns the size of this area.
512    pub fn size(&self) -> Size {
513        self.size
514    }
515
516    /// Adds the given offset to the area, reducing the drawable area.
517    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    /// Sets the size of this area.
526    pub fn set_size(&mut self, size: impl Into<Size>) {
527        self.size = size.into();
528    }
529
530    /// Sets the width of this area.
531    pub fn set_width(&mut self, width: Mm) {
532        self.size.width = width;
533    }
534
535    /// Sets the height of this area.
536    pub fn set_height(&mut self, height: Mm) {
537        self.size.height = height;
538    }
539
540    /// Splits this area horizontally using the given weights.
541    ///
542    /// The returned vector has the same number of elements as the provided slice.  The width of
543    /// the *i*-th area is *width \* weights[i] / total_weight*, where *width* is the width of this
544    /// area, and *total_weight* is the sum of all given weights.
545    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    /// Inserts an image into the document.
562    ///
563    /// *Only available if the `images` feature is enabled.*
564    ///
565    /// The position is assumed to be relative to the upper left hand corner of the area.
566    /// Your position will need to compensate for rotation/scale/dpi. Using [`Image`][]’s
567    /// render functionality will do this for you and is the recommended way to
568    /// insert an image into an Area.
569    ///
570    /// [`Image`]: ../elements/struct.Image.html
571    #[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    /// Draws a line with the given points and the given line style.
585    ///
586    /// The points are relative to the upper left corner of the area.
587    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    /// Tries to draw the given string at the given position and returns `true` if the area was
598    /// large enough to draw the string.
599    ///
600    /// The font cache must contain the PDF font for the font set in the style.  The position is
601    /// relative to the upper left corner of the area.
602    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    /// Creates a new text section at the given position if the text section fits in this area.
620    ///
621    /// The given style is only used to calculate the line height of the section.  The position is
622    /// relative to the upper left corner of the area.  The font cache must contain the PDF font
623    /// for all fonts printed with the text section.
624    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    /// Returns a position relative to the top left corner of this area.
636    fn position(&self, position: Position) -> LayerPosition {
637        LayerPosition::from_area(self, position)
638    }
639}
640
641/// A text section that is drawn on an area of a PDF layer.
642pub 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    /// Tries to add a new line and returns `true` if the area was large enough to fit the new
693    /// line.
694    #[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    /// Prints the given string with the given style.
706    ///
707    /// The font cache for this text section must contain the PDF font for the given style.
708    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        // Adjust cursor to remove left bearing of the first character of the first string
713        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            // Kerning is measured in 1/1000 em
727            .map(|pos| pos * -1000.0)
728            .map(|pos| pos as i64);
729        let codepoints = if font.is_builtin() {
730            // Built-in fonts always use the Windows-1252 encoding
731            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
756/// Encodes the given string using the Windows-1252 encoding for use with built-in PDF fonts,
757/// returning an error if it contains unsupported characters.
758fn 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    // Windows-1252 is a single-byte encoding, so one byte is one character.
765    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}