1use crate::bindgen::{FPDF_BOOL, FPDF_PAGE, FS_RECTF};
5use crate::error::PdfiumError;
6use crate::pdf::rect::PdfRect;
7use crate::pdfium::PdfiumLibraryBindingsAccessor;
8use std::marker::PhantomData;
9use std::os::raw::c_float;
10
11#[cfg(doc)]
12use crate::pdf::document::page::PdfPage;
13
14#[derive(Debug, Copy, Clone, PartialEq)]
16pub enum PdfPageBoundaryBoxType {
17 Media,
18 Art,
19 Bleed,
20 Trim,
21 Crop,
22 Bounding,
23}
24
25#[derive(Debug, Copy, Clone, PartialEq)]
27pub struct PdfPageBoundaryBox {
28 pub box_type: PdfPageBoundaryBoxType,
29 pub bounds: PdfRect,
30}
31
32impl PdfPageBoundaryBox {
33 #[inline]
34 pub(crate) fn new(boundary: PdfPageBoundaryBoxType, bounds: PdfRect) -> Self {
35 Self {
36 box_type: boundary,
37 bounds,
38 }
39 }
40}
41
42pub struct PdfPageBoundaries<'a> {
64 page_handle: FPDF_PAGE,
65 lifetime: PhantomData<&'a FPDF_PAGE>,
66}
67
68impl<'a> PdfPageBoundaries<'a> {
69 #[inline]
70 pub(crate) fn from_pdfium(page_handle: FPDF_PAGE) -> Self {
71 Self {
72 page_handle,
73 lifetime: PhantomData,
74 }
75 }
76
77 #[inline]
80 pub fn get(&self, boundary: PdfPageBoundaryBoxType) -> Result<PdfPageBoundaryBox, PdfiumError> {
81 match boundary {
82 PdfPageBoundaryBoxType::Media => self.media(),
83 PdfPageBoundaryBoxType::Art => self.art(),
84 PdfPageBoundaryBoxType::Bleed => self.bleed(),
85 PdfPageBoundaryBoxType::Trim => self.trim(),
86 PdfPageBoundaryBoxType::Crop => self.crop(),
87 PdfPageBoundaryBoxType::Bounding => self.bounding(),
88 }
89 }
90
91 #[inline]
94 pub fn set(
95 &mut self,
96 box_type: PdfPageBoundaryBoxType,
97 rect: PdfRect,
98 ) -> Result<(), PdfiumError> {
99 match box_type {
100 PdfPageBoundaryBoxType::Media => self.set_media(rect),
101 PdfPageBoundaryBoxType::Art => self.set_art(rect),
102 PdfPageBoundaryBoxType::Bleed => self.set_bleed(rect),
103 PdfPageBoundaryBoxType::Trim => self.set_trim(rect),
104 PdfPageBoundaryBoxType::Crop => self.set_crop(rect),
105 PdfPageBoundaryBoxType::Bounding => Ok(()), }
107 }
108
109 #[inline]
113 pub fn media(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
114 self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
115 self.bindings()
116 .FPDFPage_GetMediaBox(page, left, bottom, right, top)
117 })
118 .map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Media, rect))
119 }
120
121 pub fn set_media(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
123 unsafe {
124 self.bindings().FPDFPage_SetMediaBox(
125 self.page_handle,
126 rect.left().value,
127 rect.bottom().value,
128 rect.right().value,
129 rect.top().value,
130 );
131 }
132
133 Ok(())
134 }
135
136 #[inline]
140 pub fn art(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
141 self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
142 self.bindings()
143 .FPDFPage_GetArtBox(page, left, bottom, right, top)
144 })
145 .map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Art, rect))
146 }
147
148 pub fn set_art(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
150 unsafe {
151 self.bindings().FPDFPage_SetArtBox(
152 self.page_handle,
153 rect.left().value,
154 rect.bottom().value,
155 rect.right().value,
156 rect.top().value,
157 );
158 }
159
160 Ok(())
161 }
162
163 #[inline]
167 pub fn bleed(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
168 self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
169 self.bindings()
170 .FPDFPage_GetBleedBox(page, left, bottom, right, top)
171 })
172 .map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Bleed, rect))
173 }
174
175 pub fn set_bleed(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
177 unsafe {
178 self.bindings().FPDFPage_SetBleedBox(
179 self.page_handle,
180 rect.left().value,
181 rect.bottom().value,
182 rect.right().value,
183 rect.top().value,
184 );
185 }
186
187 Ok(())
188 }
189
190 #[inline]
194 pub fn trim(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
195 self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
196 self.bindings()
197 .FPDFPage_GetTrimBox(page, left, bottom, right, top)
198 })
199 .map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Trim, rect))
200 }
201
202 pub fn set_trim(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
204 unsafe {
205 self.bindings().FPDFPage_SetTrimBox(
206 self.page_handle,
207 rect.left().value,
208 rect.bottom().value,
209 rect.right().value,
210 rect.top().value,
211 );
212 }
213
214 Ok(())
215 }
216
217 #[inline]
220 pub fn crop(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
221 self.get_bounding_box_rect(|page, left, bottom, right, top| unsafe {
222 self.bindings()
223 .FPDFPage_GetCropBox(page, left, bottom, right, top)
224 })
225 .map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Crop, rect))
226 }
227
228 pub fn set_crop(&mut self, rect: PdfRect) -> Result<(), PdfiumError> {
230 unsafe {
231 self.bindings().FPDFPage_SetCropBox(
232 self.page_handle,
233 rect.left().value,
234 rect.bottom().value,
235 rect.right().value,
236 rect.top().value,
237 );
238 }
239
240 Ok(())
241 }
242
243 #[inline]
248 pub fn bounding(&self) -> Result<PdfPageBoundaryBox, PdfiumError> {
249 let mut rect = FS_RECTF {
250 left: 0.0,
251 top: 0.0,
252 right: 0.0,
253 bottom: 0.0,
254 };
255
256 let result = unsafe {
257 self.bindings()
258 .FPDF_GetPageBoundingBox(self.page_handle, &mut rect)
259 };
260
261 PdfRect::from_pdfium_as_result(result, rect, self.bindings())
262 .map(|rect| PdfPageBoundaryBox::new(PdfPageBoundaryBoxType::Bounding, rect))
263 }
264
265 #[inline]
267 fn get_bounding_box_rect<F>(&self, f: F) -> Result<PdfRect, PdfiumError>
268 where
269 F: FnOnce(FPDF_PAGE, *mut c_float, *mut c_float, *mut c_float, *mut c_float) -> FPDF_BOOL,
270 {
271 let mut left = 0_f32;
272 let mut bottom = 0_f32;
273 let mut right = 0_f32;
274 let mut top = 0_f32;
275
276 let result = f(
277 self.page_handle,
278 &mut left,
279 &mut bottom,
280 &mut right,
281 &mut top,
282 );
283
284 PdfRect::from_pdfium_as_result(
285 result,
286 FS_RECTF {
287 left,
288 top,
289 right,
290 bottom,
291 },
292 self.bindings(),
293 )
294 }
295
296 pub fn iter(&'a self) -> PageBoundaryIterator<'a> {
301 PageBoundaryIterator::new(self)
302 }
303}
304
305impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageBoundaries<'a> {}
306
307#[cfg(feature = "thread_safe")]
308unsafe impl<'a> Send for PdfPageBoundaries<'a> {}
309
310#[cfg(feature = "thread_safe")]
311unsafe impl<'a> Sync for PdfPageBoundaries<'a> {}
312
313pub struct PageBoundaryIterator<'a> {
318 boundaries: &'a PdfPageBoundaries<'a>,
319 next_index: usize,
320}
321
322impl<'a> PageBoundaryIterator<'a> {
323 #[inline]
324 pub(crate) fn new(boundaries: &'a PdfPageBoundaries<'a>) -> Self {
325 Self {
326 boundaries,
327 next_index: 0,
328 }
329 }
330}
331
332impl<'a> Iterator for PageBoundaryIterator<'a> {
333 type Item = PdfPageBoundaryBox;
334
335 fn next(&mut self) -> Option<Self::Item> {
336 let mut next = None;
337
338 while self.next_index < 5 && next.is_none() {
339 next = match self.next_index {
340 0 => self.boundaries.get(PdfPageBoundaryBoxType::Media).ok(),
341 1 => self.boundaries.get(PdfPageBoundaryBoxType::Art).ok(),
342 2 => self.boundaries.get(PdfPageBoundaryBoxType::Bleed).ok(),
343 3 => self.boundaries.get(PdfPageBoundaryBoxType::Trim).ok(),
344 4 => self.boundaries.get(PdfPageBoundaryBoxType::Crop).ok(),
345 5 => self.boundaries.get(PdfPageBoundaryBoxType::Bounding).ok(),
346 _ => None,
347 };
348
349 self.next_index += 1;
350 }
351
352 next
353 }
354}