pdfium_render/pdf/document/page/text/
chars.rs1use 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
15pub type PdfPageTextCharIndex = usize;
17
18pub 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 #[inline]
47 pub(crate) fn document_handle(&self) -> FPDF_DOCUMENT {
48 self.document_handle
49 }
50
51 #[inline]
54 pub(crate) fn page_handle(&self) -> FPDF_PAGE {
55 self.page_handle
56 }
57
58 #[inline]
60 pub(crate) fn text_page_handle(&self) -> FPDF_TEXTPAGE {
61 self.text_page_handle
62 }
63
64 #[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 #[inline]
75 pub fn len(&self) -> PdfPageTextCharIndex {
76 self.char_indices.len()
77 }
78
79 #[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 #[inline]
90 pub fn is_empty(&self) -> bool {
91 self.len() == 0
92 }
93
94 #[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 #[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 #[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 #[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 #[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 #[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
176pub 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}