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::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(annotation_handle: FPDF_ANNOTATION, bindings: &'a dyn PdfiumLibraryBindings) -> Self {
25        PdfPageAnnotationAttachmentPoints {
26            annotation_handle,
27            bindings,
28        }
29    }
30
31    /// Returns the number of attachment points in this [PdfPageAnnotationAttachmentPoints] collection.
32    pub fn len(&self) -> PdfPageAnnotationAttachmentPointIndex {
33        if self
34            .bindings
35            .is_true(self.bindings.FPDFAnnot_HasAttachmentPoints(self.annotation_handle))
36        {
37            self.bindings.FPDFAnnot_CountAttachmentPoints(self.annotation_handle)
38                as PdfPageAnnotationAttachmentPointIndex
39        } else {
40            0
41        }
42    }
43
44    /// Returns `true` if this [PdfPageAnnotationAttachmentPoints] collection is empty.
45    #[inline]
46    pub fn is_empty(&self) -> bool {
47        self.len() == 0
48    }
49
50    /// Returns a Range from `0..(number of attachment points)` for this
51    /// [PdfPageAnnotationAttachmentPoints] collection.
52    #[inline]
53    pub fn as_range(&self) -> Range<PdfPageAnnotationAttachmentPointIndex> {
54        0..self.len()
55    }
56
57    /// Returns an inclusive Range from `0..=(number of attachment points - 1)` for this
58    /// [PdfPageAnnotationAttachmentPoints] collection.
59    #[inline]
60    pub fn as_range_inclusive(&self) -> RangeInclusive<PdfPageAnnotationAttachmentPointIndex> {
61        if self.is_empty() { 0..=0 } else { 0..=(self.len() - 1) }
62    }
63
64    /// Returns a single attachment point, expressed as a set of [PdfQuadPoints], from this
65    /// [PdfPageAnnotationAttachmentPoints] collection.
66    pub fn get(&self, index: PdfPageAnnotationAttachmentPointIndex) -> Result<PdfQuadPoints, PdfiumError> {
67        if index >= self.len() {
68            return Err(PdfiumError::PageAnnotationAttachmentPointIndexOutOfBounds);
69        }
70
71        let mut result = PdfQuadPoints::ZERO.as_pdfium();
72
73        if self.bindings.is_true(self.bindings.FPDFAnnot_GetAttachmentPoints(
74            self.annotation_handle,
75            index,
76            &mut result,
77        )) {
78            Ok(PdfQuadPoints::from_pdfium(result))
79        } else {
80            Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
81        }
82    }
83
84    /// Returns the first attachment point, expressed as a set of [PdfQuadPoints],
85    /// in this [PdfPageAnnotationAttachmentPoints] collection.
86    #[inline]
87    pub fn first(&self) -> Result<PdfQuadPoints, PdfiumError> {
88        if !self.is_empty() {
89            self.get(0)
90        } else {
91            Err(PdfiumError::NoAttachmentPointsInPageAnnotation)
92        }
93    }
94
95    /// Returns the last attachment point, expressed as a set of [PdfQuadPoints],
96    /// in this [PdfPageAnnotationAttachmentPoints] collection.
97    #[inline]
98    pub fn last(&self) -> Result<PdfQuadPoints, PdfiumError> {
99        if !self.is_empty() {
100            self.get(self.len() - 1)
101        } else {
102            Err(PdfiumError::NoAttachmentPointsInPageAnnotation)
103        }
104    }
105
106    /// Creates a new attachment point from the given set of [PdfQuadPoints],
107    /// and appends it to the end of this [PdfPageAnnotationAttachmentPoints] collection.
108    #[inline]
109    pub fn create_attachment_point_at_end(&mut self, attachment_point: PdfQuadPoints) -> Result<(), PdfiumError> {
110        if self.bindings.is_true(
111            self.bindings
112                .FPDFAnnot_AppendAttachmentPoints(self.annotation_handle, &attachment_point.as_pdfium()),
113        ) {
114            Ok(())
115        } else {
116            Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
117        }
118    }
119
120    /// Replaces the attachment at the given index in this [PdfPageAnnotationAttachmentPoints]
121    /// collection with the given updated set of [PdfQuadPoints].
122    pub fn set_attachment_point_at_index(
123        &mut self,
124        index: PdfPageAnnotationAttachmentPointIndex,
125        attachment_point: PdfQuadPoints,
126    ) -> Result<(), PdfiumError> {
127        if self.bindings.is_true(self.bindings.FPDFAnnot_SetAttachmentPoints(
128            self.annotation_handle,
129            index,
130            &attachment_point.as_pdfium(),
131        )) {
132            Ok(())
133        } else {
134            Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
135        }
136    }
137
138    /// Returns an iterator over all the attachment points in this [PdfPageAnnotationAttachmentPoints] collection.
139    #[inline]
140    pub fn iter(&self) -> PdfPageAnnotationAttachmentPointsIterator<'_> {
141        PdfPageAnnotationAttachmentPointsIterator::new(self)
142    }
143}
144
145/// An iterator over all the attachment points in a [PdfPageAnnotationAttachmentPoints] collection.
146pub struct PdfPageAnnotationAttachmentPointsIterator<'a> {
147    attachment_points: &'a PdfPageAnnotationAttachmentPoints<'a>,
148    next_index: PdfPageAnnotationAttachmentPointIndex,
149}
150
151impl<'a> PdfPageAnnotationAttachmentPointsIterator<'a> {
152    #[inline]
153    pub(crate) fn new(attachment_points: &'a PdfPageAnnotationAttachmentPoints<'a>) -> Self {
154        PdfPageAnnotationAttachmentPointsIterator {
155            attachment_points,
156            next_index: 0,
157        }
158    }
159}
160
161impl<'a> Iterator for PdfPageAnnotationAttachmentPointsIterator<'a> {
162    type Item = PdfQuadPoints;
163
164    fn next(&mut self) -> Option<Self::Item> {
165        let next = self.attachment_points.get(self.next_index);
166
167        self.next_index += 1;
168
169        next.ok()
170    }
171}