pdfium_render/pdf/document/page/
annotations.rs

1//! Defines the [PdfPageAnnotations] struct, exposing functionality related to the
2//! annotations that have been added to a single `PdfPage`.
3
4use crate::bindgen::{FPDF_ANNOTATION, FPDF_DOCUMENT, FPDF_FORMHANDLE, FPDF_PAGE};
5use crate::bindings::PdfiumLibraryBindings;
6use crate::error::{PdfiumError, PdfiumInternalError};
7use crate::pdf::color::PdfColor;
8use crate::pdf::document::page::annotation::free_text::PdfPageFreeTextAnnotation;
9use crate::pdf::document::page::annotation::highlight::PdfPageHighlightAnnotation;
10use crate::pdf::document::page::annotation::ink::PdfPageInkAnnotation;
11use crate::pdf::document::page::annotation::link::PdfPageLinkAnnotation;
12use crate::pdf::document::page::annotation::popup::PdfPagePopupAnnotation;
13use crate::pdf::document::page::annotation::private::internal::PdfPageAnnotationPrivate;
14use crate::pdf::document::page::annotation::square::PdfPageSquareAnnotation;
15use crate::pdf::document::page::annotation::squiggly::PdfPageSquigglyAnnotation;
16use crate::pdf::document::page::annotation::stamp::PdfPageStampAnnotation;
17use crate::pdf::document::page::annotation::strikeout::PdfPageStrikeoutAnnotation;
18use crate::pdf::document::page::annotation::text::PdfPageTextAnnotation;
19use crate::pdf::document::page::annotation::underline::PdfPageUnderlineAnnotation;
20use crate::pdf::document::page::annotation::{
21    PdfPageAnnotation, PdfPageAnnotationCommon, PdfPageAnnotationType,
22};
23use crate::pdf::document::page::object::{PdfPageObject, PdfPageObjectCommon};
24use crate::pdf::document::page::{PdfPage, PdfPageContentRegenerationStrategy, PdfPageIndexCache};
25use crate::pdf::quad_points::PdfQuadPoints;
26use chrono::prelude::*;
27use std::ops::Range;
28use std::os::raw::c_int;
29
30/// The zero-based index of a single [PdfPageAnnotation] inside its containing
31/// [PdfPageAnnotations] collection.
32pub type PdfPageAnnotationIndex = usize;
33
34/// The annotations that have been added to a single `PdfPage`.
35pub struct PdfPageAnnotations<'a> {
36    document_handle: FPDF_DOCUMENT,
37    page_handle: FPDF_PAGE,
38    form_handle: Option<FPDF_FORMHANDLE>,
39    bindings: &'a dyn PdfiumLibraryBindings,
40}
41
42impl<'a> PdfPageAnnotations<'a> {
43    #[inline]
44    pub(crate) fn from_pdfium(
45        document_handle: FPDF_DOCUMENT,
46        page_handle: FPDF_PAGE,
47        form_handle: Option<FPDF_FORMHANDLE>,
48        bindings: &'a dyn PdfiumLibraryBindings,
49    ) -> Self {
50        PdfPageAnnotations {
51            document_handle,
52            page_handle,
53            form_handle,
54            bindings,
55        }
56    }
57
58    /// Returns the internal `FPDF_DOCUMENT` handle of the [PdfDocument] containing this
59    /// [PdfPageAnnotations] collection.
60    #[inline]
61    pub(crate) fn document_handle(&self) -> FPDF_DOCUMENT {
62        self.document_handle
63    }
64
65    /// Returns the internal `FPDF_PAGE` handle of the [PdfPage] containing this
66    /// [PdfPageAnnotations] collection.
67    #[inline]
68    pub(crate) fn page_handle(&self) -> FPDF_PAGE {
69        self.page_handle
70    }
71
72    /// Returns the [PdfiumLibraryBindings] used by this [PdfPageAnnotations] collection.
73    #[inline]
74    pub fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
75        self.bindings
76    }
77
78    /// Returns the total number of annotations that have been added to the containing `PdfPage`.
79    #[inline]
80    pub fn len(&self) -> PdfPageAnnotationIndex {
81        self.bindings().FPDFPage_GetAnnotCount(self.page_handle) as PdfPageAnnotationIndex
82    }
83
84    /// Returns true if this [PdfPageAnnotations] collection is empty.
85    #[inline]
86    pub fn is_empty(&self) -> bool {
87        self.len() == 0
88    }
89
90    /// Returns a Range from 0..(number of annotations) for this [PdfPageAnnotations] collection.
91    #[inline]
92    pub fn as_range(&self) -> Range<PdfPageAnnotationIndex> {
93        0..self.len()
94    }
95
96    /// Returns a single [PdfPageAnnotation] from this [PdfPageAnnotations] collection.
97    pub fn get(&self, index: PdfPageAnnotationIndex) -> Result<PdfPageAnnotation<'a>, PdfiumError> {
98        if index >= self.len() {
99            return Err(PdfiumError::PageAnnotationIndexOutOfBounds);
100        }
101
102        let annotation_handle = self
103            .bindings()
104            .FPDFPage_GetAnnot(self.page_handle, index as c_int);
105
106        if annotation_handle.is_null() {
107            Err(PdfiumError::PdfiumLibraryInternalError(
108                PdfiumInternalError::Unknown,
109            ))
110        } else {
111            Ok(PdfPageAnnotation::from_pdfium(
112                self.document_handle,
113                self.page_handle,
114                annotation_handle,
115                self.form_handle,
116                self.bindings,
117            ))
118        }
119    }
120
121    /// Returns the first [PdfPageAnnotation] in this [PdfPageAnnotations] collection.
122    #[inline]
123    pub fn first(&self) -> Result<PdfPageAnnotation<'a>, PdfiumError> {
124        if !self.is_empty() {
125            self.get(0)
126        } else {
127            Err(PdfiumError::NoAnnotationsInCollection)
128        }
129    }
130
131    /// Returns the last [PdfPageAnnotation] in this [PdfPageAnnotations] collection.
132    #[inline]
133    pub fn last(&self) -> Result<PdfPageAnnotation<'a>, PdfiumError> {
134        if !self.is_empty() {
135            self.get(self.len() - 1)
136        } else {
137            Err(PdfiumError::NoAnnotationsInCollection)
138        }
139    }
140
141    /// Returns an iterator over all the annotations in this [PdfPageAnnotations] collection.
142    #[inline]
143    pub fn iter(&self) -> PdfPageAnnotationsIterator {
144        PdfPageAnnotationsIterator::new(self)
145    }
146
147    /// Creates a new annotation of the given [PdfPageAnnotationType] by passing the result of calling
148    /// `FPDFPage_CreateAnnot()` to an annotation constructor function.
149    ///
150    /// If the containing `PdfPage` has a content regeneration strategy of
151    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
152    /// will be triggered on the page.
153    pub(crate) fn create_annotation<T: PdfPageAnnotationCommon>(
154        &mut self,
155        annotation_type: PdfPageAnnotationType,
156        constructor: fn(
157            FPDF_DOCUMENT,
158            FPDF_PAGE,
159            FPDF_ANNOTATION,
160            &'a dyn PdfiumLibraryBindings,
161        ) -> T,
162    ) -> Result<T, PdfiumError> {
163        let handle = self
164            .bindings()
165            .FPDFPage_CreateAnnot(self.page_handle(), annotation_type.as_pdfium());
166
167        if handle.is_null() {
168            Err(PdfiumError::PdfiumLibraryInternalError(
169                PdfiumInternalError::Unknown,
170            ))
171        } else {
172            let mut annotation = constructor(
173                self.document_handle(),
174                self.page_handle(),
175                handle,
176                self.bindings(),
177            );
178
179            annotation
180                .set_creation_date(Utc::now())
181                .and_then(|()| {
182                    if let Some(content_regeneration_strategy) =
183                        PdfPageIndexCache::get_content_regeneration_strategy_for_page(
184                            self.document_handle(),
185                            self.page_handle(),
186                        )
187                    {
188                        if content_regeneration_strategy
189                            == PdfPageContentRegenerationStrategy::AutomaticOnEveryChange
190                        {
191                            PdfPage::regenerate_content_immut_for_handle(
192                                self.page_handle(),
193                                self.bindings(),
194                            )
195                        } else {
196                            Ok(())
197                        }
198                    } else {
199                        Err(PdfiumError::SourcePageIndexNotInCache)
200                    }
201                })
202                .map(|()| annotation)
203        }
204    }
205
206    /// Creates a new [PdfPageFreeTextAnnotation] containing the given text in this
207    /// [PdfPageAnnotations] collection, returning the newly created annotation.
208    ///
209    /// If the containing `PdfPage` has a content regeneration strategy of
210    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
211    /// will be triggered on the page.
212    #[inline]
213    pub fn create_free_text_annotation(
214        &mut self,
215        text: &str,
216    ) -> Result<PdfPageFreeTextAnnotation<'a>, PdfiumError> {
217        let mut annotation = self.create_annotation(
218            PdfPageAnnotationType::FreeText,
219            PdfPageFreeTextAnnotation::from_pdfium,
220        )?;
221
222        annotation.set_contents(text)?;
223
224        Ok(annotation)
225    }
226
227    /// Creates a new [PdfPageHighlightAnnotation] annotation in this [PdfPageAnnotations] collection,
228    /// returning the newly created annotation.
229    ///
230    /// If the containing `PdfPage` has a content regeneration strategy of
231    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
232    /// will be triggered on the page.
233    #[inline]
234    pub fn create_highlight_annotation(
235        &mut self,
236    ) -> Result<PdfPageHighlightAnnotation<'a>, PdfiumError> {
237        self.create_annotation(
238            PdfPageAnnotationType::Highlight,
239            PdfPageHighlightAnnotation::from_pdfium,
240        )
241    }
242
243    /// Creates a new [PdfPageInkAnnotation] in this [PdfPageAnnotations] collection,
244    /// returning the newly created annotation.
245    ///
246    /// If the containing `PdfPage` has a content regeneration strategy of
247    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
248    /// will be triggered on the page.
249    #[inline]
250    pub fn create_ink_annotation(&mut self) -> Result<PdfPageInkAnnotation<'a>, PdfiumError> {
251        self.create_annotation(
252            PdfPageAnnotationType::Ink,
253            PdfPageInkAnnotation::from_pdfium,
254        )
255    }
256
257    /// Creates a new [PdfPageLinkAnnotation] with the given URI in this [PdfPageAnnotations]
258    /// collection, returning the newly created annotation.
259    ///
260    /// If the containing `PdfPage` has a content regeneration strategy of
261    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
262    /// will be triggered on the page.
263    pub fn create_link_annotation(
264        &mut self,
265        uri: &str,
266    ) -> Result<PdfPageLinkAnnotation<'a>, PdfiumError> {
267        let mut annotation = self.create_annotation(
268            PdfPageAnnotationType::Link,
269            PdfPageLinkAnnotation::from_pdfium,
270        )?;
271
272        annotation.set_link(uri)?;
273
274        Ok(annotation)
275    }
276
277    /// Creates a new [PdfPagePopupAnnotation] annotation in this [PdfPageAnnotations] collection,
278    /// returning the newly created annotation.
279    ///
280    /// If the containing `PdfPage` has a content regeneration strategy of
281    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
282    /// will be triggered on the page.
283    #[inline]
284    pub fn create_popup_annotation(&mut self) -> Result<PdfPagePopupAnnotation<'a>, PdfiumError> {
285        self.create_annotation(
286            PdfPageAnnotationType::Popup,
287            PdfPagePopupAnnotation::from_pdfium,
288        )
289    }
290
291    /// Creates a new [PdfPageSquareAnnotation] annotation in this [PdfPageAnnotations] collection,
292    /// returning the newly created annotation.
293    ///
294    /// If the containing `PdfPage` has a content regeneration strategy of
295    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
296    /// will be triggered on the page.
297    #[inline]
298    pub fn create_square_annotation(&mut self) -> Result<PdfPageSquareAnnotation<'a>, PdfiumError> {
299        self.create_annotation(
300            PdfPageAnnotationType::Square,
301            PdfPageSquareAnnotation::from_pdfium,
302        )
303    }
304
305    /// Creates a new [PdfPageSquigglyAnnotation] annotation in this [PdfPageAnnotations] collection,
306    /// returning the newly created annotation.
307    ///
308    /// If the containing `PdfPage` has a content regeneration strategy of
309    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
310    /// will be triggered on the page.
311    #[inline]
312    pub fn create_squiggly_annotation(
313        &mut self,
314    ) -> Result<PdfPageSquigglyAnnotation<'a>, PdfiumError> {
315        self.create_annotation(
316            PdfPageAnnotationType::Squiggly,
317            PdfPageSquigglyAnnotation::from_pdfium,
318        )
319    }
320
321    /// Creates a new [PdfPageStampAnnotation] annotation in this [PdfPageAnnotations] collection,
322    /// returning the newly created annotation.
323    ///
324    /// If the containing `PdfPage` has a content regeneration strategy of
325    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
326    /// will be triggered on the page.
327    #[inline]
328    pub fn create_stamp_annotation(&mut self) -> Result<PdfPageStampAnnotation<'a>, PdfiumError> {
329        self.create_annotation(
330            PdfPageAnnotationType::Stamp,
331            PdfPageStampAnnotation::from_pdfium,
332        )
333    }
334
335    /// Creates a new [PdfPageStrikeoutAnnotation] annotation in this [PdfPageAnnotations] collection,
336    /// returning the newly created annotation.
337    ///
338    /// If the containing `PdfPage` has a content regeneration strategy of
339    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
340    /// will be triggered on the page.
341    #[inline]
342    pub fn create_strikeout_annotation(
343        &mut self,
344    ) -> Result<PdfPageStrikeoutAnnotation<'a>, PdfiumError> {
345        self.create_annotation(
346            PdfPageAnnotationType::Strikeout,
347            PdfPageStrikeoutAnnotation::from_pdfium,
348        )
349    }
350
351    /// Creates a new [PdfPageTextAnnotation] containing the given text in this [PdfPageAnnotations]
352    /// collection, returning the newly created annotation.
353    ///
354    /// If the containing `PdfPage` has a content regeneration strategy of
355    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
356    /// will be triggered on the page.
357    #[inline]
358    pub fn create_text_annotation(
359        &mut self,
360        text: &str,
361    ) -> Result<PdfPageTextAnnotation<'a>, PdfiumError> {
362        let mut annotation = self.create_annotation(
363            PdfPageAnnotationType::Text,
364            PdfPageTextAnnotation::from_pdfium,
365        )?;
366
367        annotation.set_contents(text)?;
368
369        Ok(annotation)
370    }
371
372    /// Creates a new [PdfPageUnderlineAnnotation] annotation in this [PdfPageAnnotations] collection,
373    /// returning the newly created annotation.
374    ///
375    /// If the containing `PdfPage` has a content regeneration strategy of
376    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
377    /// will be triggered on the page.
378    #[inline]
379    pub fn create_underline_annotation(
380        &mut self,
381    ) -> Result<PdfPageUnderlineAnnotation<'a>, PdfiumError> {
382        self.create_annotation(
383            PdfPageAnnotationType::Underline,
384            PdfPageUnderlineAnnotation::from_pdfium,
385        )
386    }
387
388    // Convenience functions for creating and positioning markup annotations
389    // in a single function call.
390
391    /// Creates a new [PdfPageSquigglyAnnotation] annotation and positions it underneath the given
392    /// [PdfPageObject], coloring it with the given [PdfColor].
393    ///
394    /// If the given contents string is supplied, the annotation will be additionally configured
395    /// so that when the given [PdfPageObject] is clicked in a conforming PDF viewer, the given
396    /// contents string will be displayed in a popup window.
397    ///
398    /// If the containing `PdfPage` has a content regeneration strategy of
399    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
400    /// will be triggered on the page.
401    #[inline]
402    pub fn create_squiggly_annotation_under_object(
403        &mut self,
404        object: &PdfPageObject,
405        color: PdfColor,
406        contents: Option<&str>,
407    ) -> Result<PdfPageSquigglyAnnotation<'a>, PdfiumError> {
408        let mut annotation = self.create_squiggly_annotation()?;
409
410        // The annotation will not display if it is not positioned.
411
412        let bounds = object.bounds()?;
413
414        annotation.set_position(bounds.left(), bounds.bottom())?;
415        annotation.set_stroke_color(color)?;
416
417        const SQUIGGLY_HEIGHT: f32 = 12.0;
418
419        let annotation_top = bounds.bottom().value - 5.0;
420        let annotation_bottom = annotation_top - SQUIGGLY_HEIGHT;
421
422        annotation
423            .attachment_points_mut()
424            .create_attachment_point_at_end(PdfQuadPoints::new_from_values(
425                bounds.left().value,
426                annotation_bottom,
427                bounds.right().value,
428                annotation_bottom,
429                bounds.right().value,
430                annotation_top,
431                bounds.left().value,
432                annotation_top,
433            ))?;
434
435        if let Some(contents) = contents {
436            annotation.set_width(bounds.width())?;
437            annotation.set_height(bounds.height())?;
438            annotation.set_contents(contents)?;
439        }
440
441        Ok(annotation)
442    }
443
444    /// Creates a new [PdfPageUnderlineAnnotation] annotation and positions it underneath the given
445    /// [PdfPageObject], coloring it with the given [PdfColor].
446    ///
447    /// If the given contents string is supplied, the annotation will be additionally configured
448    /// so that when the given [PdfPageObject] is clicked in a conforming PDF viewer, the given
449    /// contents string will be displayed in a popup window.
450    ///
451    /// If the containing `PdfPage` has a content regeneration strategy of
452    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
453    /// will be triggered on the page.
454    #[inline]
455    pub fn create_underline_annotation_under_object(
456        &mut self,
457        object: &PdfPageObject,
458        color: PdfColor,
459        contents: Option<&str>,
460    ) -> Result<PdfPageUnderlineAnnotation<'a>, PdfiumError> {
461        let mut annotation = self.create_underline_annotation()?;
462
463        // The annotation will not display if it is not positioned.
464
465        let bounds = object.bounds()?;
466
467        annotation.set_position(bounds.left(), bounds.bottom())?;
468        annotation.set_stroke_color(color)?;
469        annotation
470            .attachment_points_mut()
471            .create_attachment_point_at_end(bounds)?;
472
473        if let Some(contents) = contents {
474            annotation.set_width(bounds.width())?;
475            annotation.set_height(bounds.height())?;
476            annotation.set_contents(contents)?;
477        }
478
479        Ok(annotation)
480    }
481
482    /// Creates a new [PdfPageStrikeoutAnnotation] annotation and vertically positions it in the
483    /// center the given [PdfPageObject], coloring it with the given [PdfColor].
484    ///
485    /// If the given contents string is supplied, the annotation will be additionally configured
486    /// so that when the given [PdfPageObject] is clicked in a conforming PDF viewer, the given
487    /// contents string will be displayed in a popup window.
488    ///
489    /// If the containing `PdfPage` has a content regeneration strategy of
490    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
491    /// will be triggered on the page.
492    #[inline]
493    pub fn create_strikeout_annotation_through_object(
494        &mut self,
495        object: &PdfPageObject,
496        color: PdfColor,
497        contents: Option<&str>,
498    ) -> Result<PdfPageStrikeoutAnnotation<'a>, PdfiumError> {
499        let mut annotation = self.create_strikeout_annotation()?;
500
501        // The annotation will not display if it is not positioned.
502
503        let bounds = object.bounds()?;
504
505        annotation.set_position(bounds.left(), bounds.bottom())?;
506        annotation.set_stroke_color(color)?;
507        annotation
508            .attachment_points_mut()
509            .create_attachment_point_at_end(bounds)?;
510
511        if let Some(contents) = contents {
512            annotation.set_width(bounds.width())?;
513            annotation.set_height(bounds.height())?;
514            annotation.set_contents(contents)?;
515        }
516
517        Ok(annotation)
518    }
519
520    /// Creates a new [PdfPageHighlightAnnotation] annotation and positions it so as to cover
521    /// the given [PdfPageObject], coloring it with the given [PdfColor].
522    ///
523    /// If the given contents string is supplied, the annotation will be additionally configured
524    /// so that when the given [PdfPageObject] is clicked in a conforming PDF viewer, the given
525    /// contents string will be displayed in a popup window.
526    ///
527    /// If the containing `PdfPage` has a content regeneration strategy of
528    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
529    /// will be triggered on the page.
530    #[inline]
531    pub fn create_highlight_annotation_over_object(
532        &mut self,
533        object: &PdfPageObject,
534        color: PdfColor,
535        contents: Option<&str>,
536    ) -> Result<PdfPageHighlightAnnotation<'a>, PdfiumError> {
537        let mut annotation = self.create_highlight_annotation()?;
538
539        // The annotation will not display if it is not positioned.
540
541        let bounds = object.bounds()?;
542
543        annotation.set_position(bounds.left(), bounds.bottom())?;
544        annotation.set_stroke_color(color)?;
545        annotation
546            .attachment_points_mut()
547            .create_attachment_point_at_end(bounds)?;
548
549        if let Some(contents) = contents {
550            annotation.set_width(bounds.width())?;
551            annotation.set_height(bounds.height())?;
552            annotation.set_contents(contents)?;
553        }
554
555        Ok(annotation)
556    }
557
558    /// Removes the given [PdfPageAnnotation] from this [PdfPageAnnotations] collection,
559    /// consuming the [PdfPageAnnotation].
560    ///
561    /// If the containing `PdfPage` has a content regeneration strategy of
562    /// `PdfPageContentRegenerationStrategy::AutomaticOnEveryChange` then content regeneration
563    /// will be triggered on the page.
564    pub fn delete_annotation(
565        &mut self,
566        annotation: PdfPageAnnotation<'a>,
567    ) -> Result<(), PdfiumError> {
568        let index = self
569            .bindings()
570            .FPDFPage_GetAnnotIndex(self.page_handle(), annotation.handle());
571
572        if index == -1 {
573            return Err(PdfiumError::PageAnnotationIndexOutOfBounds);
574        }
575
576        if self.bindings().is_true(
577            self.bindings()
578                .FPDFPage_RemoveAnnot(self.page_handle(), index),
579        ) {
580            if let Some(content_regeneration_strategy) =
581                PdfPageIndexCache::get_content_regeneration_strategy_for_page(
582                    self.document_handle(),
583                    self.page_handle(),
584                )
585            {
586                if content_regeneration_strategy
587                    == PdfPageContentRegenerationStrategy::AutomaticOnEveryChange
588                {
589                    PdfPage::regenerate_content_immut_for_handle(
590                        self.page_handle(),
591                        self.bindings(),
592                    )
593                } else {
594                    Ok(())
595                }
596            } else {
597                Err(PdfiumError::SourcePageIndexNotInCache)
598            }
599        } else {
600            Err(PdfiumError::PdfiumLibraryInternalError(
601                PdfiumInternalError::Unknown,
602            ))
603        }
604    }
605}
606
607/// An iterator over all the [PdfPageAnnotation] objects in a [PdfPageAnnotations] collection.
608pub struct PdfPageAnnotationsIterator<'a> {
609    annotations: &'a PdfPageAnnotations<'a>,
610    next_index: PdfPageAnnotationIndex,
611}
612
613impl<'a> PdfPageAnnotationsIterator<'a> {
614    #[inline]
615    pub(crate) fn new(annotations: &'a PdfPageAnnotations<'a>) -> Self {
616        PdfPageAnnotationsIterator {
617            annotations,
618            next_index: 0,
619        }
620    }
621}
622
623impl<'a> Iterator for PdfPageAnnotationsIterator<'a> {
624    type Item = PdfPageAnnotation<'a>;
625
626    fn next(&mut self) -> Option<Self::Item> {
627        let next = self.annotations.get(self.next_index);
628
629        self.next_index += 1;
630
631        next.ok()
632    }
633}