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}