Skip to main content

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

1//! Defines the [PdfPageTextChars] struct, a collection of nominated [PdfPageTextChar]
2//! characters selected from a single [PdfPage].
3
4use crate::bindgen::{FPDF_DOCUMENT, FPDF_PAGE, FPDF_TEXTPAGE};
5use crate::bindings::PdfiumLibraryBindings;
6use crate::error::PdfiumError;
7use crate::pdf::document::page::PdfPageText;
8use crate::pdf::document::page::text::char::PdfPageTextChar;
9use crate::pdf::points::PdfPoints;
10
11#[cfg(doc)]
12use crate::pdf::document::page::PdfPage;
13
14/// The zero-based index of a single [PdfPageTextChar] inside its containing [PdfPageTextChars] collection.
15pub type PdfPageTextCharIndex = usize;
16
17/// A collection of nominated [PdfPageTextChar] characters selected from a single [PdfPage].
18pub struct PdfPageTextChars<'a> {
19    document_handle: FPDF_DOCUMENT,
20    page_handle: FPDF_PAGE,
21    text_page_handle: FPDF_TEXTPAGE,
22    char_indices: Vec<i32>,
23    bindings: &'a dyn PdfiumLibraryBindings,
24}
25
26impl<'a> PdfPageTextChars<'a> {
27    #[inline]
28    pub(crate) fn new(
29        document_handle: FPDF_DOCUMENT,
30        page_handle: FPDF_PAGE,
31        text_page_handle: FPDF_TEXTPAGE,
32        char_indices: Vec<i32>,
33        bindings: &'a dyn PdfiumLibraryBindings,
34    ) -> Self {
35        PdfPageTextChars {
36            document_handle,
37            page_handle,
38            text_page_handle,
39            char_indices,
40            bindings,
41        }
42    }
43
44    /// Returns the internal `FPDF_DOCUMENT` handle of the [PdfDocument] containing this
45    /// [PdfPageTextChars] collection.
46    #[inline]
47    pub(crate) fn document_handle(&self) -> FPDF_DOCUMENT {
48        self.document_handle
49    }
50
51    /// Returns the internal `FPDF_PAGE` handle of the [PdfPage] containing this
52    /// [PdfPageTextChars] collection.
53    #[inline]
54    pub(crate) fn page_handle(&self) -> FPDF_PAGE {
55        self.page_handle
56    }
57
58    /// Returns the internal `FPDF_TEXTPAGE` handle for this [PdfPageTextChars] collection.
59    #[inline]
60    pub(crate) fn text_page_handle(&self) -> FPDF_TEXTPAGE {
61        self.text_page_handle
62    }
63
64    /// Returns the [PdfiumLibraryBindings] used by this [PdfPageTextChars] collection.
65    #[inline]
66    pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
67        self.bindings
68    }
69
70    /// Returns the index in the containing [PdfPage] of the first character in this
71    /// [PdfPageTextChars] collection, if any.
72    #[inline]
73    pub fn first_char_index(&self) -> Option<PdfPageTextCharIndex> {
74        self.char_indices.first().map(|index| *index as PdfPageTextCharIndex)
75    }
76
77    /// Returns the number of individual characters in this [PdfPageTextChars] collection.
78    #[inline]
79    pub fn len(&self) -> PdfPageTextCharIndex {
80        self.char_indices.len()
81    }
82
83    /// Returns the index in the containing [PdfPage] of the last character in this
84    /// [PdfPageTextChars] collection, if any.
85    #[inline]
86    pub fn last_char_index(&self) -> Option<PdfPageTextCharIndex> {
87        self.char_indices.last().map(|index| *index as PdfPageTextCharIndex)
88    }
89
90    /// Returns `true` if this [PdfPageTextChars] collection is empty.
91    #[inline]
92    pub fn is_empty(&self) -> bool {
93        self.len() == 0
94    }
95
96    /// Returns a single [PdfPageTextChar] from this [PdfPageTextChars] collection.
97    #[inline]
98    pub fn get(&self, index: PdfPageTextCharIndex) -> Result<PdfPageTextChar<'_>, PdfiumError> {
99        match self.char_indices.get(index) {
100            Some(index) => Ok(PdfPageTextChar::from_pdfium(
101                self.document_handle(),
102                self.page_handle(),
103                self.text_page_handle(),
104                *index,
105                self.bindings(),
106            )),
107            None => Err(PdfiumError::CharIndexOutOfBounds),
108        }
109    }
110
111    /// Returns the character at the given x and y positions on the containing [PdfPage], if any.
112    #[inline]
113    pub fn get_char_at_point(&self, x: PdfPoints, y: PdfPoints) -> Option<PdfPageTextChar<'_>> {
114        self.get_char_near_point(x, PdfPoints::ZERO, y, PdfPoints::ZERO)
115    }
116
117    /// Returns the character near to the given x and y positions on the containing [PdfPage],
118    /// if any. The returned character will be no further from the given positions than the given
119    /// tolerance values.
120    #[inline]
121    pub fn get_char_near_point(
122        &self,
123        x: PdfPoints,
124        tolerance_x: PdfPoints,
125        y: PdfPoints,
126        tolerance_y: PdfPoints,
127    ) -> Option<PdfPageTextChar<'_>> {
128        PdfPageText::get_char_index_near_point(self.text_page_handle(), x, tolerance_x, y, tolerance_y, self.bindings())
129            .ok_or(PdfiumError::CharIndexOutOfBounds)
130            .and_then(|index| self.get(index))
131            .ok()
132    }
133
134    /// Returns an iterator over all the characters in this [PdfPageTextChars] collection.
135    #[inline]
136    pub fn iter(&self) -> PdfPageTextCharsIterator<'_> {
137        PdfPageTextCharsIterator::new(self)
138    }
139}
140
141/// An iterator over all the [PdfPageTextChar] objects in a [PdfPageTextChars] collection.
142pub struct PdfPageTextCharsIterator<'a> {
143    chars: &'a PdfPageTextChars<'a>,
144    next_index: PdfPageTextCharIndex,
145}
146
147impl<'a> PdfPageTextCharsIterator<'a> {
148    #[inline]
149    pub(crate) fn new(chars: &'a PdfPageTextChars) -> Self {
150        PdfPageTextCharsIterator { chars, next_index: 0 }
151    }
152}
153
154impl<'a> Iterator for PdfPageTextCharsIterator<'a> {
155    type Item = PdfPageTextChar<'a>;
156
157    fn next(&mut self) -> Option<Self::Item> {
158        let next = self.chars.get(self.next_index);
159
160        self.next_index += 1;
161
162        next.ok()
163    }
164}