Skip to main content

pdfkit/
selection.rs

1use std::ptr;
2
3use crate::document::PdfDocument;
4use crate::error::Result;
5use crate::ffi;
6use crate::handle::ObjectHandle;
7use crate::page::PdfPage;
8use crate::types::{PdfRect, PdfTextRange};
9use crate::util::take_string;
10
11/// Wraps `PDFSelection`.
12#[derive(Debug, Clone)]
13pub struct PdfSelection {
14    handle: ObjectHandle,
15}
16
17impl PdfSelection {
18    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
19        Self { handle }
20    }
21
22    /// Wraps `PDFSelection(document:)`.
23    pub fn new(document: &PdfDocument) -> Result<Self> {
24        let mut out_selection = ptr::null_mut();
25        let mut out_error = ptr::null_mut();
26        let status = unsafe {
27            ffi::pdf_selection_new(document.as_handle_ptr(), &mut out_selection, &mut out_error)
28        };
29        crate::util::status_result(status, out_error)?;
30        Ok(Self::from_handle(crate::util::required_handle(
31            out_selection,
32            "PDFSelection",
33        )?))
34    }
35
36    /// Wraps the corresponding `PDFSelection` API.
37    #[must_use]
38    pub fn string(&self) -> Option<String> {
39        take_string(unsafe { ffi::pdf_selection_string(self.handle.as_ptr()) })
40    }
41
42    /// Wraps the corresponding `PDFSelection` API.
43    #[must_use]
44    pub fn page_count(&self) -> usize {
45        unsafe { ffi::pdf_selection_page_count(self.handle.as_ptr()) as usize }
46    }
47
48    /// Wraps the corresponding `PDFSelection` API.
49    #[must_use]
50    pub fn page(&self, index: usize) -> Option<PdfPage> {
51        let ptr = unsafe { ffi::pdf_selection_page_at(self.handle.as_ptr(), index as u64) };
52        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfPage::from_handle)
53    }
54
55    /// Wraps the corresponding `PDFSelection` API.
56    #[must_use]
57    pub fn pages(&self) -> Vec<PdfPage> {
58        (0..self.page_count())
59            .filter_map(|index| self.page(index))
60            .collect()
61    }
62
63    /// Wraps the corresponding `PDFSelection` API.
64    #[must_use]
65    pub fn bounds_for_page(&self, page: &PdfPage) -> PdfRect {
66        let mut x = 0.0_f64;
67        let mut y = 0.0_f64;
68        let mut width = 0.0_f64;
69        let mut height = 0.0_f64;
70        unsafe {
71            ffi::pdf_selection_bounds_for_page(
72                self.handle.as_ptr(),
73                page.as_handle_ptr(),
74                &mut x,
75                &mut y,
76                &mut width,
77                &mut height,
78            );
79        }
80        PdfRect {
81            x,
82            y,
83            width,
84            height,
85        }
86    }
87
88    /// Wraps the corresponding `PDFSelection` API.
89    #[must_use]
90    pub fn number_of_text_ranges_on_page(&self, page: &PdfPage) -> usize {
91        unsafe {
92            ffi::pdf_selection_number_of_text_ranges_on_page(
93                self.handle.as_ptr(),
94                page.as_handle_ptr(),
95            ) as usize
96        }
97    }
98
99    /// Wraps the corresponding `PDFSelection` API.
100    #[must_use]
101    pub fn text_range(&self, index: usize, page: &PdfPage) -> Option<PdfTextRange> {
102        let mut location = 0_u64;
103        let mut length = 0_u64;
104        let ok = unsafe {
105            ffi::pdf_selection_range_at_index_on_page(
106                self.handle.as_ptr(),
107                index as u64,
108                page.as_handle_ptr(),
109                &mut location,
110                &mut length,
111            ) != 0
112        };
113        ok.then_some(PdfTextRange {
114            location: location as usize,
115            length: length as usize,
116        })
117    }
118
119    /// Wraps the corresponding `PDFSelection` API.
120    #[must_use]
121    pub fn selection_by_line_count(&self) -> usize {
122        unsafe { ffi::pdf_selection_selections_by_line_count(self.handle.as_ptr()) as usize }
123    }
124
125    /// Wraps the corresponding `PDFSelection` API.
126    #[must_use]
127    pub fn selection_by_line(&self, index: usize) -> Option<Self> {
128        let ptr =
129            unsafe { ffi::pdf_selection_selection_by_line_at(self.handle.as_ptr(), index as u64) };
130        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(Self::from_handle)
131    }
132
133    /// Wraps the corresponding `PDFSelection` API.
134    #[must_use]
135    pub fn selections_by_line(&self) -> Vec<Self> {
136        (0..self.selection_by_line_count())
137            .filter_map(|index| self.selection_by_line(index))
138            .collect()
139    }
140
141    /// Wraps the corresponding `PDFSelection` API.
142    pub fn add_selection(&self, other: &Self) -> Result<()> {
143        let mut out_error = ptr::null_mut();
144        let status = unsafe {
145            ffi::pdf_selection_add_selection(
146                self.handle.as_ptr(),
147                other.handle.as_ptr(),
148                &mut out_error,
149            )
150        };
151        crate::util::status_result(status, out_error)
152    }
153
154    /// Wraps the corresponding `PDFSelection` API.
155    pub fn extend_selection_at_end(&self, amount: isize) {
156        unsafe { ffi::pdf_selection_extend_at_end(self.handle.as_ptr(), amount as i64) };
157    }
158
159    /// Wraps the corresponding `PDFSelection` API.
160    pub fn extend_selection_at_start(&self, amount: isize) {
161        unsafe { ffi::pdf_selection_extend_at_start(self.handle.as_ptr(), amount as i64) };
162    }
163
164    /// Wraps the corresponding `PDFSelection` API.
165    pub fn extend_selection_for_line_boundaries(&self) {
166        unsafe { ffi::pdf_selection_extend_for_line_boundaries(self.handle.as_ptr()) };
167    }
168
169    pub(crate) fn as_handle_ptr(&self) -> *mut core::ffi::c_void {
170        self.handle.as_ptr()
171    }
172}