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}