use crate::bindgen::{FPDF_DOCUMENT, FPDF_PAGE, FPDF_TEXTPAGE};
use crate::error::PdfiumError;
use crate::pdf::document::page::text::char::PdfPageTextChar;
use crate::pdf::document::page::PdfPageText;
use crate::pdf::points::PdfPoints;
use crate::pdfium::PdfiumLibraryBindingsAccessor;
use std::marker::PhantomData;
#[cfg(doc)]
use crate::pdf::document::page::PdfPage;
pub type PdfPageTextCharIndex = usize;
pub struct PdfPageTextChars<'a> {
document_handle: FPDF_DOCUMENT,
page_handle: FPDF_PAGE,
text_page_handle: FPDF_TEXTPAGE,
char_indices: Vec<i32>,
lifetime: PhantomData<&'a FPDF_TEXTPAGE>,
}
impl<'a> PdfPageTextChars<'a> {
#[inline]
pub(crate) fn new(
document_handle: FPDF_DOCUMENT,
page_handle: FPDF_PAGE,
text_page_handle: FPDF_TEXTPAGE,
char_indices: Vec<i32>,
) -> Self {
PdfPageTextChars {
document_handle,
page_handle,
text_page_handle,
char_indices,
lifetime: PhantomData,
}
}
#[inline]
pub(crate) fn document_handle(&self) -> FPDF_DOCUMENT {
self.document_handle
}
#[inline]
pub(crate) fn page_handle(&self) -> FPDF_PAGE {
self.page_handle
}
#[inline]
pub(crate) fn text_page_handle(&self) -> FPDF_TEXTPAGE {
self.text_page_handle
}
#[inline]
pub fn first_char_index(&self) -> Option<PdfPageTextCharIndex> {
self.char_indices
.first()
.map(|index| *index as PdfPageTextCharIndex)
}
#[inline]
pub fn len(&self) -> PdfPageTextCharIndex {
self.char_indices.len()
}
#[inline]
pub fn last_char_index(&self) -> Option<PdfPageTextCharIndex> {
self.char_indices
.last()
.map(|index| *index as PdfPageTextCharIndex)
}
#[inline]
pub fn is_empty(&self) -> bool {
self.len() == 0
}
#[inline]
pub fn get(&self, index: PdfPageTextCharIndex) -> Result<PdfPageTextChar<'_>, PdfiumError> {
match self.char_indices.get(index) {
Some(index) => Ok(PdfPageTextChar::from_pdfium(
self.document_handle(),
self.page_handle(),
self.text_page_handle(),
*index,
)),
None => Err(PdfiumError::CharIndexOutOfBounds),
}
}
#[inline]
pub fn get_char_at_point(&self, x: PdfPoints, y: PdfPoints) -> Option<PdfPageTextChar<'_>> {
self.get_char_near_point(x, PdfPoints::ZERO, y, PdfPoints::ZERO)
}
#[inline]
pub fn get_char_near_point(
&self,
x: PdfPoints,
tolerance_x: PdfPoints,
y: PdfPoints,
tolerance_y: PdfPoints,
) -> Option<PdfPageTextChar<'_>> {
PdfPageText::get_char_index_near_point(
self.text_page_handle(),
x,
tolerance_x,
y,
tolerance_y,
self.bindings(),
)
.ok_or(PdfiumError::CharIndexOutOfBounds)
.and_then(|index| self.get(index))
.ok()
}
#[inline]
pub fn iter(&self) -> PdfPageTextCharsIterator<'_> {
PdfPageTextCharsIterator::new(self)
}
}
impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageTextChars<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Send for PdfPageTextChars<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Sync for PdfPageTextChars<'a> {}
pub struct PdfPageTextCharsIterator<'a> {
chars: &'a PdfPageTextChars<'a>,
next_index: PdfPageTextCharIndex,
}
impl<'a> PdfPageTextCharsIterator<'a> {
#[inline]
pub(crate) fn new(chars: &'a PdfPageTextChars) -> Self {
PdfPageTextCharsIterator {
chars,
next_index: 0,
}
}
}
impl<'a> Iterator for PdfPageTextCharsIterator<'a> {
type Item = PdfPageTextChar<'a>;
fn next(&mut self) -> Option<Self::Item> {
let next = self.chars.get(self.next_index);
self.next_index += 1;
next.ok()
}
}