Skip to main content

pdfkit/
page.rs

1use std::ptr;
2
3use crate::annotation::PdfAnnotation;
4use crate::error::Result;
5use crate::ffi;
6use crate::handle::ObjectHandle;
7use crate::selection::PdfSelection;
8use crate::types::{DisplayBox, PdfPoint, PdfRect};
9use crate::util::take_string;
10
11#[derive(Debug, Clone)]
12pub struct PdfPage {
13    handle: ObjectHandle,
14}
15
16impl PdfPage {
17    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
18        Self { handle }
19    }
20
21    pub fn new() -> Result<Self> {
22        let mut out_page = ptr::null_mut();
23        let mut out_error = ptr::null_mut();
24        let status = unsafe { ffi::pdf_page_new(&mut out_page, &mut out_error) };
25        crate::util::status_result(status, out_error)?;
26        Ok(Self::from_handle(crate::util::required_handle(
27            out_page,
28            "PDFPage",
29        )?))
30    }
31
32    #[must_use]
33    pub fn label(&self) -> Option<String> {
34        take_string(unsafe { ffi::pdf_page_label_string(self.handle.as_ptr()) })
35    }
36
37    #[must_use]
38    pub fn string(&self) -> Option<String> {
39        take_string(unsafe { ffi::pdf_page_string(self.handle.as_ptr()) })
40    }
41
42    #[must_use]
43    pub fn number_of_characters(&self) -> usize {
44        unsafe { ffi::pdf_page_number_of_characters(self.handle.as_ptr()) as usize }
45    }
46
47    #[must_use]
48    pub fn rotation(&self) -> i32 {
49        unsafe { ffi::pdf_page_rotation(self.handle.as_ptr()) }
50    }
51
52    pub fn set_rotation(&self, rotation: i32) -> Result<()> {
53        let mut out_error = ptr::null_mut();
54        let status = unsafe { ffi::pdf_page_set_rotation(self.handle.as_ptr(), rotation, &mut out_error) };
55        crate::util::status_result(status, out_error)
56    }
57
58    #[must_use]
59    pub fn bounds(&self, display_box: DisplayBox) -> PdfRect {
60        let mut x = 0.0_f64;
61        let mut y = 0.0_f64;
62        let mut width = 0.0_f64;
63        let mut height = 0.0_f64;
64        unsafe {
65            ffi::pdf_page_bounds(
66                self.handle.as_ptr(),
67                display_box.as_raw(),
68                &mut x,
69                &mut y,
70                &mut width,
71                &mut height,
72            );
73        }
74        PdfRect {
75            x,
76            y,
77            width,
78            height,
79        }
80    }
81
82    pub fn set_bounds(&self, display_box: DisplayBox, bounds: PdfRect) -> Result<()> {
83        let mut out_error = ptr::null_mut();
84        let status = unsafe {
85            ffi::pdf_page_set_bounds(
86                self.handle.as_ptr(),
87                display_box.as_raw(),
88                bounds.x,
89                bounds.y,
90                bounds.width,
91                bounds.height,
92                &mut out_error,
93            )
94        };
95        crate::util::status_result(status, out_error)
96    }
97
98    #[must_use]
99    pub fn document(&self) -> Option<crate::document::PdfDocument> {
100        let ptr = unsafe { ffi::pdf_page_document(self.handle.as_ptr()) };
101        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(crate::document::PdfDocument::from_handle)
102    }
103
104    #[must_use]
105    pub fn annotation_count(&self) -> usize {
106        unsafe { ffi::pdf_page_annotation_count(self.handle.as_ptr()) as usize }
107    }
108
109    #[must_use]
110    pub fn annotation(&self, index: usize) -> Option<PdfAnnotation> {
111        let ptr = unsafe { ffi::pdf_page_annotation_at(self.handle.as_ptr(), index as u64) };
112        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfAnnotation::from_handle)
113    }
114
115    #[must_use]
116    pub fn annotations(&self) -> Vec<PdfAnnotation> {
117        (0..self.annotation_count())
118            .filter_map(|index| self.annotation(index))
119            .collect()
120    }
121
122    pub fn add_annotation(&self, annotation: &PdfAnnotation) -> Result<()> {
123        let mut out_error = ptr::null_mut();
124        let status = unsafe {
125            ffi::pdf_page_add_annotation(
126                self.handle.as_ptr(),
127                annotation.as_handle_ptr(),
128                &mut out_error,
129            )
130        };
131        crate::util::status_result(status, out_error)
132    }
133
134    pub fn remove_annotation(&self, annotation: &PdfAnnotation) -> Result<()> {
135        let mut out_error = ptr::null_mut();
136        let status = unsafe {
137            ffi::pdf_page_remove_annotation(
138                self.handle.as_ptr(),
139                annotation.as_handle_ptr(),
140                &mut out_error,
141            )
142        };
143        crate::util::status_result(status, out_error)
144    }
145
146    #[must_use]
147    pub fn annotation_at_point(&self, point: PdfPoint) -> Option<PdfAnnotation> {
148        let ptr = unsafe { ffi::pdf_page_annotation_at_point(self.handle.as_ptr(), point.x, point.y) };
149        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfAnnotation::from_handle)
150    }
151
152    #[must_use]
153    pub fn selection_for_range(&self, location: usize, length: usize) -> Option<PdfSelection> {
154        let ptr = unsafe {
155            ffi::pdf_page_selection_for_range(self.handle.as_ptr(), location as u64, length as u64)
156        };
157        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfSelection::from_handle)
158    }
159
160    #[must_use]
161    pub fn selection_for_rect(&self, rect: PdfRect) -> Option<PdfSelection> {
162        let ptr = unsafe {
163            ffi::pdf_page_selection_for_rect(
164                self.handle.as_ptr(),
165                rect.x,
166                rect.y,
167                rect.width,
168                rect.height,
169            )
170        };
171        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfSelection::from_handle)
172    }
173
174    #[must_use]
175    pub fn selection_for_word_at_point(&self, point: PdfPoint) -> Option<PdfSelection> {
176        let ptr = unsafe {
177            ffi::pdf_page_selection_for_word_at_point(self.handle.as_ptr(), point.x, point.y)
178        };
179        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfSelection::from_handle)
180    }
181
182    #[must_use]
183    pub fn selection_for_line_at_point(&self, point: PdfPoint) -> Option<PdfSelection> {
184        let ptr = unsafe {
185            ffi::pdf_page_selection_for_line_at_point(self.handle.as_ptr(), point.x, point.y)
186        };
187        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfSelection::from_handle)
188    }
189
190    #[must_use]
191    pub fn selection_from_points(&self, start: PdfPoint, end: PdfPoint) -> Option<PdfSelection> {
192        let ptr = unsafe {
193            ffi::pdf_page_selection_from_points(
194                self.handle.as_ptr(),
195                start.x,
196                start.y,
197                end.x,
198                end.y,
199            )
200        };
201        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfSelection::from_handle)
202    }
203
204    #[must_use]
205    pub fn character_bounds_at(&self, index: usize) -> PdfRect {
206        let mut x = 0.0_f64;
207        let mut y = 0.0_f64;
208        let mut width = 0.0_f64;
209        let mut height = 0.0_f64;
210        unsafe {
211            ffi::pdf_page_character_bounds_at(
212                self.handle.as_ptr(),
213                index as u64,
214                &mut x,
215                &mut y,
216                &mut width,
217                &mut height,
218            );
219        }
220        PdfRect {
221            x,
222            y,
223            width,
224            height,
225        }
226    }
227
228    #[must_use]
229    pub fn character_index_at_point(&self, point: PdfPoint) -> Option<usize> {
230        let index = unsafe { ffi::pdf_page_character_index_at_point(self.handle.as_ptr(), point.x, point.y) };
231        (index != i64::MAX)
232            .then_some(index)
233            .and_then(|index| usize::try_from(index).ok())
234    }
235
236    #[must_use]
237    pub fn displays_annotations(&self) -> bool {
238        unsafe { ffi::pdf_page_displays_annotations(self.handle.as_ptr()) != 0 }
239    }
240
241    pub fn set_displays_annotations(&self, value: bool) {
242        unsafe { ffi::pdf_page_set_displays_annotations(self.handle.as_ptr(), i32::from(value)) };
243    }
244
245    pub(crate) fn as_handle_ptr(&self) -> *mut core::ffi::c_void {
246        self.handle.as_ptr()
247    }
248}