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