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