Skip to main content

pdfium_render/pdf/document/page/text/
segment.rs

1//! Defines the [PdfPageTextSegment] struct, exposing functionality related to a single rectangular
2//! text segment in a `PdfPageTextSegments` collection.
3
4use crate::error::PdfiumError;
5use crate::pdf::document::page::text::PdfPageText;
6use crate::pdf::document::page::text::chars::PdfPageTextChars;
7use crate::pdf::points::PdfPoints;
8use crate::pdf::rect::PdfRect;
9
10#[cfg(doc)]
11use {crate::pdf::document::page::PdfPage, crate::pdf::document::page::text::char::PdfPageTextChar};
12
13/// A single rectangular text segment in a `PdfPageTextSegments` collection.
14///
15/// Pdfium automatically merges smaller text boxes into larger text segments if all
16/// enclosed characters share the same baseline and the same font settings. The number of
17/// individual `PdfPageTextObject` objects on the page may be much larger than the number of
18/// text segments.
19pub struct PdfPageTextSegment<'a> {
20    text: &'a PdfPageText<'a>,
21    bounds: PdfRect,
22}
23
24impl<'a> PdfPageTextSegment<'a> {
25    pub(crate) fn from_pdfium(text: &'a PdfPageText<'a>, bounds: PdfRect) -> Self {
26        PdfPageTextSegment { text, bounds }
27    }
28
29    /// Returns the bounding box of this [PdfPageTextSegment].
30    #[inline]
31    pub fn bounds(&self) -> PdfRect {
32        self.bounds
33    }
34
35    /// Returns the width of this [PdfPageTextSegment].
36    #[inline]
37    pub fn width(&self) -> PdfPoints {
38        self.bounds.width()
39    }
40
41    /// Returns the height of this [PdfPageTextSegment].
42    #[inline]
43    pub fn height(&self) -> PdfPoints {
44        self.bounds.height()
45    }
46
47    /// Returns `true` if the bounds of this [PdfPageTextSegment] lie entirely within the given rectangle.
48    #[inline]
49    pub fn is_inside_rect(&self, rect: &PdfRect) -> bool {
50        self.bounds.is_inside(rect)
51    }
52
53    /// Returns `true` if the bounds of this [PdfPageTextSegment] lie at least partially within
54    /// the given rectangle.
55    #[inline]
56    pub fn does_overlap_rect(&self, rect: &PdfRect) -> bool {
57        self.bounds.does_overlap(rect)
58    }
59
60    /// Returns all characters that lie within the bounds of this [PdfPageTextSegment] in the
61    /// containing [PdfPage], in the order in which they are defined in the document.
62    ///
63    /// In complex custom layouts, the order in which characters are defined in the document
64    /// and the order in which they appear visually during rendering (and thus the order in
65    /// which they are read by a user) may not necessarily match.
66    #[inline]
67    pub fn text(&self) -> String {
68        self.text.inside_rect(self.bounds)
69    }
70
71    /// Returns text with corrected word spacing by filtering spurious generated spaces.
72    ///
73    /// Iterates characters within the segment and only inserts a space when the
74    /// horizontal gap between adjacent characters exceeds `font_size * space_ratio`.
75    /// This filters out spaces that pdfium inserts mid-word due to aggressive
76    /// inter-glyph spacing heuristics.
77    ///
78    /// Typical `space_ratio` values: 0.25 (MinerU's threshold), 0.3 (conservative).
79    pub fn text_respaced(&self, space_ratio: f32) -> String {
80        self.text.inside_rect_respaced(self.bounds, space_ratio)
81    }
82
83    /// Returns a collection of all the [PdfPageTextChar] characters that lie within the bounds of
84    /// this [PdfPageTextSegment] in the containing [PdfPage], in the order in which they are
85    /// defined in the document.
86    ///
87    /// In complex custom layouts, the order in which characters are defined in the document
88    /// and the order in which they appear visually during rendering (and thus the order in
89    /// which they are read by a user) may not necessarily match.
90    #[inline]
91    pub fn chars(&self) -> Result<PdfPageTextChars<'_>, PdfiumError> {
92        self.text.chars_inside_rect(self.bounds)
93    }
94}