Skip to main content

pdfkit/
annotation.rs

1use std::ptr;
2
3use crate::action::{PdfAction, PdfActionLike};
4use crate::action_goto::PdfActionGoTo;
5use crate::action_url::PdfActionUrl;
6use crate::annotation_constants::PdfAnnotationSubtype;
7use crate::border::PdfBorder;
8use crate::error::Result;
9use crate::ffi;
10use crate::handle::ObjectHandle;
11use crate::types::{PdfAnnotationInfo, PdfRect};
12use crate::util::{c_string, option_c_string, parse_json};
13
14/// Wraps `PDFAnnotation`.
15#[derive(Debug, Clone)]
16pub struct PdfAnnotation {
17    handle: ObjectHandle,
18}
19
20impl PdfAnnotation {
21    pub(crate) fn from_handle(handle: ObjectHandle) -> Self {
22        Self { handle }
23    }
24
25    /// Wraps `PDFAnnotation(bounds:forType:withProperties:)`.
26    pub fn new(bounds: PdfRect, annotation_type: &str) -> Result<Self> {
27        let annotation_type = c_string(annotation_type)?;
28        let mut out_annotation = ptr::null_mut();
29        let mut out_error = ptr::null_mut();
30        let status = unsafe {
31            ffi::pdf_annotation_new(
32                bounds.x,
33                bounds.y,
34                bounds.width,
35                bounds.height,
36                annotation_type.as_ptr(),
37                &mut out_annotation,
38                &mut out_error,
39            )
40        };
41        crate::util::status_result(status, out_error)?;
42        Ok(Self::from_handle(crate::util::required_handle(
43            out_annotation,
44            "PDFAnnotation",
45        )?))
46    }
47
48    /// Wraps `PDFAnnotation(bounds:forType:withProperties:)` using a typed subtype.
49    pub fn new_with_subtype(
50        bounds: PdfRect,
51        annotation_subtype: PdfAnnotationSubtype,
52    ) -> Result<Self> {
53        let annotation_type = c_string(annotation_subtype.name())?;
54        let mut out_annotation = ptr::null_mut();
55        let mut out_error = ptr::null_mut();
56        let status = unsafe {
57            ffi::pdf_annotation_new(
58                bounds.x,
59                bounds.y,
60                bounds.width,
61                bounds.height,
62                annotation_type.as_ptr(),
63                &mut out_annotation,
64                &mut out_error,
65            )
66        };
67        crate::util::status_result(status, out_error)?;
68        Ok(Self::from_handle(crate::util::required_handle(
69            out_annotation,
70            "PDFAnnotation",
71        )?))
72    }
73
74    /// Wraps the corresponding `PDFAnnotation` API.
75    pub fn info(&self) -> Result<PdfAnnotationInfo> {
76        parse_json(
77            unsafe { ffi::pdf_annotation_info_json(self.handle.as_ptr()) },
78            "PDFAnnotation",
79        )
80    }
81
82    /// Wraps the corresponding `PDFAnnotation` API.
83    pub fn set_contents(&self, value: Option<&str>) -> Result<()> {
84        let value = option_c_string(value)?;
85        let mut out_error = ptr::null_mut();
86        let status = unsafe {
87            ffi::pdf_annotation_set_contents(
88                self.handle.as_ptr(),
89                value.as_ref().map_or(ptr::null(), |value| value.as_ptr()),
90                &mut out_error,
91            )
92        };
93        crate::util::status_result(status, out_error)
94    }
95
96    /// Wraps the corresponding `PDFAnnotation` API.
97    pub fn set_highlighted(&self, value: bool) {
98        unsafe { ffi::pdf_annotation_set_highlighted(self.handle.as_ptr(), i32::from(value)) };
99    }
100
101    /// Wraps the corresponding `PDFAnnotation` API.
102    #[must_use]
103    pub fn border(&self) -> Option<PdfBorder> {
104        let ptr = unsafe { ffi::pdf_annotation_border(self.handle.as_ptr()) };
105        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfBorder::from_handle)
106    }
107
108    /// Wraps the corresponding `PDFAnnotation` API.
109    pub fn set_border(&self, border: Option<&PdfBorder>) -> Result<()> {
110        let mut out_error = ptr::null_mut();
111        let status = unsafe {
112            ffi::pdf_annotation_set_border(
113                self.handle.as_ptr(),
114                border.map_or(ptr::null_mut(), PdfBorder::as_handle_ptr),
115                &mut out_error,
116            )
117        };
118        crate::util::status_result(status, out_error)
119    }
120
121    /// Wraps the corresponding `PDFAnnotation` API.
122    #[must_use]
123    pub fn action(&self) -> Option<PdfAction> {
124        let ptr = unsafe { ffi::pdf_annotation_action(self.handle.as_ptr()) };
125        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfAction::from_handle)
126    }
127
128    /// Wraps the corresponding `PDFAnnotation` API.
129    pub fn set_action<A: PdfActionLike>(&self, action: Option<&A>) -> Result<()> {
130        let mut out_error = ptr::null_mut();
131        let status = unsafe {
132            ffi::pdf_annotation_set_action(
133                self.handle.as_ptr(),
134                action.map_or(ptr::null_mut(), PdfActionLike::as_action_handle_ptr),
135                &mut out_error,
136            )
137        };
138        crate::util::status_result(status, out_error)
139    }
140
141    /// Wraps the corresponding `PDFAnnotation` API.
142    pub fn clear_action(&self) -> Result<()> {
143        self.set_action::<PdfAction>(None)
144    }
145
146    /// Wraps the corresponding `PDFAnnotation` API.
147    #[must_use]
148    pub fn action_url(&self) -> Option<PdfActionUrl> {
149        let ptr = unsafe { ffi::pdf_annotation_action_url(self.handle.as_ptr()) };
150        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfActionUrl::from_handle)
151    }
152
153    /// Wraps the corresponding `PDFAnnotation` API.
154    pub fn set_action_url(&self, action: Option<&PdfActionUrl>) -> Result<()> {
155        self.set_action(action)
156    }
157
158    /// Wraps the corresponding `PDFAnnotation` API.
159    #[must_use]
160    pub fn action_goto(&self) -> Option<PdfActionGoTo> {
161        let ptr = unsafe { ffi::pdf_annotation_action_goto(self.handle.as_ptr()) };
162        unsafe { ObjectHandle::from_retained_ptr(ptr) }.map(PdfActionGoTo::from_handle)
163    }
164
165    /// Wraps the corresponding `PDFAnnotation` API.
166    pub fn set_action_goto(&self, action: Option<&PdfActionGoTo>) -> Result<()> {
167        self.set_action(action)
168    }
169
170    pub(crate) fn as_handle_ptr(&self) -> *mut core::ffi::c_void {
171        self.handle.as_ptr()
172    }
173}