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