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<'b>(
97        &'b self,
98        index: PdfPageTextCharIndex,
99    ) -> Result<PdfPageTextChar<'a>, PdfiumError> {
100        match self.char_indices.get(index) {
101            Some(index) => Ok(PdfPageTextChar::from_pdfium(
102                self.document_handle(),
103                self.page_handle(),
104                self.text_page_handle(),
105                *index,
106            )),
107            None => Err(PdfiumError::CharIndexOutOfBounds),
108        }
109    }
110
111    /// Returns the first [PdfPageTextChar] in this [PdfPageTextChars] collection.
112    #[inline]
113    pub fn first(&self) -> Result<PdfPageTextChar<'a>, PdfiumError> {
114        if !self.is_empty() {
115            self.get(0)
116        } else {
117            Err(PdfiumError::NoCharsInPageTextChars)
118        }
119    }
120
121    /// Returns the last [PdfPageTextSPdfPageTextCharegment] in this [PdfPageTextChars] collection.
122    #[inline]
123    pub fn last(&self) -> Result<PdfPageTextChar<'a>, PdfiumError> {
124        if !self.is_empty() {
125            self.get(self.len() - 1)
126        } else {
127            Err(PdfiumError::NoCharsInPageTextChars)
128        }
129    }
130
131    /// Returns the character at the given x and y positions on the containing [PdfPage], if any.
132    #[inline]
133    pub fn get_char_at_point(&self, x: PdfPoints, y: PdfPoints) -> Option<PdfPageTextChar<'_>> {
134        self.get_char_near_point(x, PdfPoints::ZERO, y, PdfPoints::ZERO)
135    }
136
137    /// Returns the character near to the given x and y positions on the containing [PdfPage],
138    /// if any. The returned character will be no further from the given positions than the given
139    /// tolerance values.
140    #[inline]
141    pub fn get_char_near_point(
142        &self,
143        x: PdfPoints,
144        tolerance_x: PdfPoints,
145        y: PdfPoints,
146        tolerance_y: PdfPoints,
147    ) -> Option<PdfPageTextChar<'_>> {
148        PdfPageText::get_char_index_near_point(
149            self.text_page_handle(),
150            x,
151            tolerance_x,
152            y,
153            tolerance_y,
154            self.bindings(),
155        )
156        .ok_or(PdfiumError::CharIndexOutOfBounds)
157        .and_then(|index| self.get(index))
158        .ok()
159    }
160
161    /// Returns an iterator over all the characters in this [PdfPageTextChars] collection.
162    #[inline]
163    pub fn iter(&self) -> PdfPageTextCharsIterator<'_> {
164        PdfPageTextCharsIterator::new(self)
165    }
166}
167
168impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageTextChars<'a> {}
169
170#[cfg(feature = "thread_safe")]
171unsafe impl<'a> Send for PdfPageTextChars<'a> {}
172
173#[cfg(feature = "thread_safe")]
174unsafe impl<'a> Sync for PdfPageTextChars<'a> {}
175
176/// An iterator over all the [PdfPageTextChar] objects in a [PdfPageTextChars] collection.
177pub struct PdfPageTextCharsIterator<'a> {
178    chars: &'a PdfPageTextChars<'a>,
179    next_index: PdfPageTextCharIndex,
180}
181
182impl<'a> PdfPageTextCharsIterator<'a> {
183    #[inline]
184    pub(crate) fn new(chars: &'a PdfPageTextChars) -> Self {
185        PdfPageTextCharsIterator {
186            chars,
187            next_index: 0,
188        }
189    }
190}
191
192impl<'a> Iterator for PdfPageTextCharsIterator<'a> {
193    type Item = PdfPageTextChar<'a>;
194
195    fn next(&mut self) -> Option<Self::Item> {
196        let next = self.chars.get(self.next_index);
197
198        self.next_index += 1;
199
200        next.ok()
201    }
202}