Skip to main content

pdfium_render/pdf/document/page/annotation/
attachment_points.rs

1//! Defines the [PdfPageAnnotationAttachmentPoints] struct, a collection of all the
2//! attachment points that visually associate a `PdfPageAnnotation` object with one or more
3//! `PdfPageObject` objects on a `PdfPage`.
4
5use crate::bindgen::FPDF_ANNOTATION;
6use crate::error::{PdfiumError, PdfiumInternalError};
7use crate::pdf::quad_points::PdfQuadPoints;
8use crate::pdfium::PdfiumLibraryBindingsAccessor;
9use std::marker::PhantomData;
10use std::ops::{Range, RangeInclusive};
11
12/// The zero-based index of a single attachment point inside its containing
13/// [PdfPageAnnotationAttachmentPoints] collection.
14pub type PdfPageAnnotationAttachmentPointIndex = usize;
15
16/// A set of all the attachment points that visually connect a `PdfPageAnnotation` object
17/// to one or more `PdfPageObject` objects on a `PdfPage`.
18pub struct PdfPageAnnotationAttachmentPoints<'a> {
19    annotation_handle: FPDF_ANNOTATION,
20    lifetime: PhantomData<&'a FPDF_ANNOTATION>,
21}
22
23impl<'a> PdfPageAnnotationAttachmentPoints<'a> {
24    #[inline]
25    pub(crate) fn from_pdfium(annotation_handle: FPDF_ANNOTATION) -> Self {
26        PdfPageAnnotationAttachmentPoints {
27            annotation_handle,
28            lifetime: PhantomData,
29        }
30    }
31
32    /// Returns the number of attachment points in this [PdfPageAnnotationAttachmentPoints] collection.
33    pub fn len(&self) -> PdfPageAnnotationAttachmentPointIndex {
34        if self.bindings().is_true(unsafe {
35            self.bindings()
36                .FPDFAnnot_HasAttachmentPoints(self.annotation_handle)
37        }) {
38            (unsafe {
39                self.bindings()
40                    .FPDFAnnot_CountAttachmentPoints(self.annotation_handle)
41            }) as PdfPageAnnotationAttachmentPointIndex
42        } else {
43            // Attachment points are not supported for this annotation type.
44
45            0
46        }
47    }
48
49    /// Returns `true` if this [PdfPageAnnotationAttachmentPoints] collection is empty.
50    #[inline]
51    pub fn is_empty(&self) -> bool {
52        self.len() == 0
53    }
54
55    /// Returns a Range from `0..(number of attachment points)` for this
56    /// [PdfPageAnnotationAttachmentPoints] collection.
57    #[inline]
58    pub fn as_range(&self) -> Range<PdfPageAnnotationAttachmentPointIndex> {
59        0..self.len()
60    }
61
62    /// Returns an inclusive Range from `0..=(number of attachment points - 1)` for this
63    /// [PdfPageAnnotationAttachmentPoints] collection.
64    #[inline]
65    pub fn as_range_inclusive(&self) -> RangeInclusive<PdfPageAnnotationAttachmentPointIndex> {
66        if self.is_empty() {
67            0..=0
68        } else {
69            0..=(self.len() - 1)
70        }
71    }
72
73    /// Returns a single attachment point, expressed as a set of [PdfQuadPoints], from this
74    /// [PdfPageAnnotationAttachmentPoints] collection.
75    pub fn get(
76        &self,
77        index: PdfPageAnnotationAttachmentPointIndex,
78    ) -> Result<PdfQuadPoints, PdfiumError> {
79        if index >= self.len() {
80            return Err(PdfiumError::PageAnnotationAttachmentPointIndexOutOfBounds);
81        }
82
83        let mut result = PdfQuadPoints::ZERO.as_pdfium();
84
85        if self.bindings().is_true(unsafe {
86            self.bindings().FPDFAnnot_GetAttachmentPoints(
87                self.annotation_handle,
88                index,
89                &mut result,
90            )
91        }) {
92            Ok(PdfQuadPoints::from_pdfium(result))
93        } else {
94            Err(PdfiumError::PdfiumLibraryInternalError(
95                PdfiumInternalError::Unknown,
96            ))
97        }
98    }
99
100    /// Returns the first attachment point, expressed as a set of [PdfQuadPoints],
101    /// in this [PdfPageAnnotationAttachmentPoints] collection.
102    #[inline]
103    pub fn first(&self) -> Result<PdfQuadPoints, PdfiumError> {
104        if !self.is_empty() {
105            self.get(0)
106        } else {
107            Err(PdfiumError::NoAttachmentPointsInPageAnnotation)
108        }
109    }
110
111    /// Returns the last attachment point, expressed as a set of [PdfQuadPoints],
112    /// in this [PdfPageAnnotationAttachmentPoints] collection.
113    #[inline]
114    pub fn last(&self) -> Result<PdfQuadPoints, PdfiumError> {
115        if !self.is_empty() {
116            self.get(self.len() - 1)
117        } else {
118            Err(PdfiumError::NoAttachmentPointsInPageAnnotation)
119        }
120    }
121
122    /// Creates a new attachment point from the given set of [PdfQuadPoints],
123    /// and appends it to the end of this [PdfPageAnnotationAttachmentPoints] collection.
124    #[inline]
125    pub fn create_attachment_point_at_end(
126        &mut self,
127        attachment_point: PdfQuadPoints,
128    ) -> Result<(), PdfiumError> {
129        if self.bindings().is_true(unsafe {
130            self.bindings().FPDFAnnot_AppendAttachmentPoints(
131                self.annotation_handle,
132                &attachment_point.as_pdfium(),
133            )
134        }) {
135            Ok(())
136        } else {
137            Err(PdfiumError::PdfiumLibraryInternalError(
138                PdfiumInternalError::Unknown,
139            ))
140        }
141    }
142
143    /// Replaces the attachment at the given index in this [PdfPageAnnotationAttachmentPoints]
144    /// collection with the given updated set of [PdfQuadPoints].
145    pub fn set_attachment_point_at_index(
146        &mut self,
147        index: PdfPageAnnotationAttachmentPointIndex,
148        attachment_point: PdfQuadPoints,
149    ) -> Result<(), PdfiumError> {
150        if self.bindings().is_true(unsafe {
151            self.bindings().FPDFAnnot_SetAttachmentPoints(
152                self.annotation_handle,
153                index,
154                &attachment_point.as_pdfium(),
155            )
156        }) {
157            Ok(())
158        } else {
159            Err(PdfiumError::PdfiumLibraryInternalError(
160                PdfiumInternalError::Unknown,
161            ))
162        }
163    }
164
165    /// Returns an iterator over all the attachment points in this [PdfPageAnnotationAttachmentPoints] collection.
166    #[inline]
167    pub fn iter(&self) -> PdfPageAnnotationAttachmentPointsIterator<'_> {
168        PdfPageAnnotationAttachmentPointsIterator::new(self)
169    }
170}
171
172impl<'a> PdfiumLibraryBindingsAccessor<'a> for PdfPageAnnotationAttachmentPoints<'a> {}
173
174#[cfg(feature = "thread_safe")]
175unsafe impl<'a> Send for PdfPageAnnotationAttachmentPoints<'a> {}
176
177#[cfg(feature = "thread_safe")]
178unsafe impl<'a> Sync for PdfPageAnnotationAttachmentPoints<'a> {}
179
180/// An iterator over all the attachment points in a [PdfPageAnnotationAttachmentPoints] collection.
181pub struct PdfPageAnnotationAttachmentPointsIterator<'a> {
182    attachment_points: &'a PdfPageAnnotationAttachmentPoints<'a>,
183    next_index: PdfPageAnnotationAttachmentPointIndex,
184}
185
186impl<'a> PdfPageAnnotationAttachmentPointsIterator<'a> {
187    #[inline]
188    pub(crate) fn new(attachment_points: &'a PdfPageAnnotationAttachmentPoints<'a>) -> Self {
189        PdfPageAnnotationAttachmentPointsIterator {
190            attachment_points,
191            next_index: 0,
192        }
193    }
194}
195
196impl<'a> Iterator for PdfPageAnnotationAttachmentPointsIterator<'a> {
197    type Item = PdfQuadPoints;
198
199    fn next(&mut self) -> Option<Self::Item> {
200        let next = self.attachment_points.get(self.next_index);
201
202        self.next_index += 1;
203
204        next.ok()
205    }
206}