Skip to main content

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

1//! Defines the [PdfPageTextSegments] struct, a collection of all the distinct rectangular
2//! areas of a single [PdfPage] occupied by spans of text that share a common text style.
3
4use crate::bindgen::FS_RECTF;
5use crate::bindings::PdfiumLibraryBindings;
6use crate::error::PdfiumError;
7use crate::pdf::document::page::text::PdfPageText;
8use crate::pdf::document::page::text::segment::PdfPageTextSegment;
9use crate::pdf::rect::PdfRect;
10use std::ops::{Range, RangeInclusive};
11use std::os::raw::c_int;
12
13#[cfg(doc)]
14use {crate::pdf::document::page::PdfPage, crate::pdf::document::page::object::text::PdfPageTextObject};
15
16/// The zero-based index of a single [PdfPageTextSegment] inside its containing
17/// [PdfPageTextSegments] collection.
18pub type PdfPageTextSegmentIndex = usize;
19
20/// A collection of all the distinct rectangular areas of a single [PdfPage] occupied by
21/// spans of text that share a common text style.
22///
23/// Pdfium automatically merges smaller text boxes into larger ones if all enclosed characters
24/// are on the same line and share the same font settings.
25pub struct PdfPageTextSegments<'a> {
26    text: &'a PdfPageText<'a>,
27    start: i32,
28    characters: i32,
29    bindings: &'a dyn PdfiumLibraryBindings,
30}
31
32impl<'a> PdfPageTextSegments<'a> {
33    #[inline]
34    pub(crate) fn new(
35        text: &'a PdfPageText<'a>,
36        start: i32,
37        characters: i32,
38        bindings: &'a dyn PdfiumLibraryBindings,
39    ) -> Self {
40        PdfPageTextSegments {
41            text,
42            start,
43            characters,
44            bindings,
45        }
46    }
47
48    /// Returns the number of distinct rectangular areas occupied by text in the containing [PdfPage].
49    ///
50    /// Pdfium automatically merges smaller text boxes into larger ones if all enclosed characters
51    /// are on the same line and share the same font settings. The number of rectangular text segments
52    /// returned by this function therefore indicates the minimum number of spans of text that
53    /// share text styles on the page. The number of individual [PdfPageTextObject] objects on
54    /// the page may be much larger than the number of text segments.
55    #[inline]
56    pub fn len(&self) -> PdfPageTextSegmentIndex {
57        self.bindings
58            .FPDFText_CountRects(self.text.text_page_handle(), self.start, self.characters)
59            as PdfPageTextSegmentIndex
60    }
61
62    /// Returns `true` if this [PdfPageTextSegments] collection is empty.
63    #[inline]
64    pub fn is_empty(&self) -> bool {
65        self.len() == 0
66    }
67
68    /// Returns a Range from `0..(number of segments)` for this [PdfPageTextSegments] collection.
69    #[inline]
70    pub fn as_range(&self) -> Range<PdfPageTextSegmentIndex> {
71        0..self.len()
72    }
73
74    /// Returns an inclusive Range from `0..=(number of segments - 1)` for this
75    /// [PdfPageTextSegments] collection.
76    #[inline]
77    pub fn as_range_inclusive(&self) -> RangeInclusive<PdfPageTextSegmentIndex> {
78        if self.is_empty() { 0..=0 } else { 0..=(self.len() - 1) }
79    }
80
81    /// Returns a single [PdfPageTextSegment] from this [PdfPageTextSegments] collection.
82    #[inline]
83    pub fn get(&self, index: PdfPageTextSegmentIndex) -> Result<PdfPageTextSegment<'_>, PdfiumError> {
84        if index >= self.len() {
85            return Err(PdfiumError::TextSegmentIndexOutOfBounds);
86        }
87
88        let mut left = 0.0;
89
90        let mut bottom = 0.0;
91
92        let mut right = 0.0;
93
94        let mut top = 0.0;
95
96        let result = self.bindings.FPDFText_GetRect(
97            self.text.text_page_handle(),
98            index as c_int,
99            &mut left,
100            &mut top,
101            &mut right,
102            &mut bottom,
103        );
104
105        PdfRect::from_pdfium_as_result(
106            result,
107            FS_RECTF {
108                left: left as f32,
109                top: top as f32,
110                right: right as f32,
111                bottom: bottom as f32,
112            },
113            self.bindings,
114        )
115        .map(|rect| PdfPageTextSegment::from_pdfium(self.text, rect))
116    }
117
118    /// Returns an iterator over all the text segments in this [PdfPageTextSegments] collection.
119    ///
120    /// Pdfium automatically merges smaller text boxes into larger text segments if all
121    /// enclosed characters are on the same line and share the same font settings. The number of
122    /// individual [PdfPageTextObject] objects on the page may be much larger than the number of
123    /// text segments.
124    #[inline]
125    pub fn iter(&self) -> PdfPageTextSegmentsIterator<'_> {
126        PdfPageTextSegmentsIterator::new(self)
127    }
128}
129
130/// An iterator over all the [PdfPageTextSegment] objects in a [PdfPageTextSegments] collection.
131pub struct PdfPageTextSegmentsIterator<'a> {
132    segments: &'a PdfPageTextSegments<'a>,
133    next_index: PdfPageTextSegmentIndex,
134}
135
136impl<'a> PdfPageTextSegmentsIterator<'a> {
137    #[inline]
138    pub(crate) fn new(segments: &'a PdfPageTextSegments<'a>) -> Self {
139        PdfPageTextSegmentsIterator {
140            segments,
141            next_index: 0,
142        }
143    }
144}
145
146impl<'a> Iterator for PdfPageTextSegmentsIterator<'a> {
147    type Item = PdfPageTextSegment<'a>;
148
149    fn next(&mut self) -> Option<Self::Item> {
150        let next = self.segments.get(self.next_index);
151
152        self.next_index += 1;
153
154        next.ok()
155    }
156}