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