use crate::bindgen::{FPDF_BOOL, FPDF_PAGE, FS_RECTF};
use crate::error::PdfiumError;
use crate::pdf::rect::PdfRect;
use crate::pdfium::PdfiumLibraryBindingsAccessor;
use std::marker::PhantomData;
use std::os::raw::c_float;
#[cfg(doc)]
use crate::pdf::document::page::PdfPage;
#[derive(Debug, Copy, Clone, PartialEq)]
pub enum PdfPageBoundaryBoxType {
Media,
Art,
Bleed,
Trim,
Crop,
Bounding,
}
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct PdfPageBoundaryBox {
pub box_type: PdfPageBoundaryBoxType,
pub bounds: PdfRect,
}
impl PdfPageBoundaryBox {
#[inline]
pub(crate) fn new(boundary: PdfPageBoundaryBoxType, bounds: PdfRect) -> Self {
Self {
box_type: boundary,
bounds,
}
}
}
pub struct PdfPageBoundaries<'a> {
page_handle: FPDF_PAGE,
lifetime: PhantomData<&'a FPDF_PAGE>,
}
impl<'a> PdfPageBoundaries<'a> {
#[inline]
pub(crate) fn from_pdfium(page_handle: FPDF_PAGE) -> Self {
Self {
page_handle,
lifetime: PhantomData,
}
}
#[inline]
pub fn get(&self, boundary: PdfPageBoundaryBoxType) -> Result<PdfPageBoundaryBox, PdfiumError> {
match boundary {
PdfPageBoundaryBoxType::Media => self.media(),
PdfPageBoundaryBoxType::Art => self.art(),
PdfPageBoundaryBoxType::Bleed => self.bleed(),
PdfPageBoundaryBoxType::Trim => self.trim(),
PdfPageBoundaryBoxType::Crop => self.crop(),
PdfPageBoundaryBoxType::Bounding => self.bounding(),
}
}
#[inline]
pub fn set(
&mut self,
box_type: PdfPageBoundaryBoxType,
rect: PdfRect,
) -> Result<(), PdfiumError> {
match box_type {
PdfPageBoundaryBoxType::Media => self.set_media(rect),
PdfPageBoundaryBoxType::Art => self.set_art(rect),
PdfPageBoundaryBoxType::Bleed => self.set_bleed(rect),
PdfPageBoundaryBoxType::Trim => self.set_trim(rect),
PdfPageBoundaryBoxType::Crop => self.set_crop(rect),
PdfPageBoundaryBoxType::Bounding => Ok(()), }
}
#[inline]
pub fn media(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
self.bindings()
.FPDFPage_GetMediaBox(page, left, bottom, right, top)
})
.map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Media, rect))
}
pub fn set_media(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
unsafe {
self.bindings().FPDFPage_SetMediaBox(
self.page_handle,
rect.left().value,
rect.bottom().value,
rect.right().value,
rect.top().value,
);
}
Ok(())
}
#[inline]
pub fn art(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
self.bindings()
.FPDFPage_GetArtBox(page, left, bottom, right, top)
})
.map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Art, rect))
}
pub fn set_art(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
unsafe {
self.bindings().FPDFPage_SetArtBox(
self.page_handle,
rect.left().value,
rect.bottom().value,
rect.right().value,
rect.top().value,
);
}
Ok(())
}
#[inline]
pub fn bleed(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
self.bindings()
.FPDFPage_GetBleedBox(page, left, bottom, right, top)
})
.map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Bleed, rect))
}
pub fn set_bleed(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
unsafe {
self.bindings().FPDFPage_SetBleedBox(
self.page_handle,
rect.left().value,
rect.bottom().value,
rect.right().value,
rect.top().value,
);
}
Ok(())
}
#[inline]
pub fn trim(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
self.bindings()
.FPDFPage_GetTrimBox(page, left, bottom, right, top)
})
.map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Trim, rect))
}
pub fn set_trim(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
unsafe {
self.bindings().FPDFPage_SetTrimBox(
self.page_handle,
rect.left().value,
rect.bottom().value,
rect.right().value,
rect.top().value,
);
}
Ok(())
}
#[inline]
pub fn crop(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
self.bindings()
.FPDFPage_GetCropBox(page, left, bottom, right, top)
})
.map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Crop, rect))
}
pub fn set_crop(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
unsafe {
self.bindings().FPDFPage_SetCropBox(
self.page_handle,
rect.left().value,
rect.bottom().value,
rect.right().value,
rect.top().value,
);
}
Ok(())
}
#[inline]
pub fn bounding(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
let mut rect = FS_RECTF {
left: 0.0,
top: 0.0,
right: 0.0,
bottom: 0.0,
};
let result = unsafe {
self.bindings()
.FPDF_GetPageBoundingBox(self.page_handle, &mut rect)
};
PdfRect::from_pdfium_as_result(result, rect, self.bindings())
.map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Bounding, rect))
}
#[inline]
fn get_bounding_box_rect<F>(&self, f: F) -> Result<PdfRect, PdfiumError>
where
F: FnOnce(FPDF_PAGE, *mut c_float, *mut c_float, *mut c_float, *mut c_float) -> FPDF_BOOL,
{
let mut left = 0_f32;
let mut bottom = 0_f32;
let mut right = 0_f32;
let mut top = 0_f32;
let result = f(
self.page_handle,
&mut left,
&mut bottom,
&mut right,
&mut top,
);
PdfRect::from_pdfium_as_result(
result,
FS_RECTF {
left,
top,
right,
bottom,
},
self.bindings(),
)
}
pub fn iter(&'a self) -> PageBoundaryIterator<'a> {
PageBoundaryIterator::new(self)
}
}
impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageBoundaries<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Send for PdfPageBoundaries<'a> {}
#[cfg(feature = "thread_safe")]
unsafe impl<'a> Sync for PdfPageBoundaries<'a> {}
pub struct PageBoundaryIterator<'a> {
boundaries: &'a PdfPageBoundaries<'a>,
next_index: usize,
}
impl<'a> PageBoundaryIterator<'a> {
#[inline]
pub(crate) fn new(boundaries: &'a PdfPageBoundaries<'a>) -> Self {
Self {
boundaries,
next_index: 0,
}
}
}
impl<'a> Iterator for PageBoundaryIterator<'a> {
type Item = PdfPageBoundaryBox;
fn next(&mut self) -> Option<Self::Item> {
let mut next = None;
while self.next_index < 5 && next.is_none() {
next = match self.next_index {
0 => self.boundaries.get(PdfPageBoundaryBoxType::Media).ok(),
1 => self.boundaries.get(PdfPageBoundaryBoxType::Art).ok(),
2 => self.boundaries.get(PdfPageBoundaryBoxType::Bleed).ok(),
3 => self.boundaries.get(PdfPageBoundaryBoxType::Trim).ok(),
4 => self.boundaries.get(PdfPageBoundaryBoxType::Crop).ok(),
5 => self.boundaries.get(PdfPageBoundaryBoxType::Bounding).ok(),
_ => None,
};
self.next_index += 1;
}
next
}
}