Skip to main content

pdfium_render/pdf/document/page/objects/
common.rs

1//! Defines the [PdfPageObjectsCommon] trait, providing functionality common to all
2//! containers of multiple [PdfPageObject] objects.
3
4use crate::error::{PdfiumError, PdfiumInternalError};
5use crate::pdf::color::PdfColor;
6use crate::pdf::document::fonts::ToPdfFontToken;
7use crate::pdf::document::page::PdfPageObjectOwnership;
8use crate::pdf::document::page::object::image::PdfPageImageObject;
9use crate::pdf::document::page::object::path::PdfPagePathObject;
10use crate::pdf::document::page::object::text::PdfPageTextObject;
11use crate::pdf::document::page::object::x_object_form::PdfPageXObjectFormObject;
12use crate::pdf::document::page::object::{PdfPageObject, PdfPageObjectCommon};
13use crate::pdf::document::page::objects::private::internal::PdfPageObjectsPrivate;
14use crate::pdf::points::PdfPoints;
15use crate::pdf::rect::PdfRect;
16use std::ops::{Range, RangeInclusive};
17
18#[cfg(feature = "image_025")]
19use image_025::DynamicImage;
20
21#[cfg(doc)]
22use {
23    crate::pdf::document::page::PdfPage, crate::pdf::document::page::PdfPageContentRegenerationStrategy,
24    crate::pdf::document::page::PdfPageObjects,
25};
26
27/// The zero-based index of a single [PdfPageObject] inside its containing [PdfPageObjects] collection.
28pub type PdfPageObjectIndex = usize;
29
30/// Functionality common to all containers of multiple [PdfPageObject] objects.
31/// Both pages and annotations can contain page objects.
32pub trait PdfPageObjectsCommon<'a> {
33    /// Returns the total number of page objects in the collection.
34    fn len(&self) -> PdfPageObjectIndex;
35
36    /// Returns true if this page objects collection is empty.
37    #[inline]
38    fn is_empty(&self) -> bool {
39        self.len() == 0
40    }
41
42    /// Returns a Range from `0..(number of objects)` for this page objects collection.
43    #[inline]
44    fn as_range(&self) -> Range<PdfPageObjectIndex> {
45        0..self.len()
46    }
47
48    /// Returns an inclusive Range from `0..=(number of objects - 1)` for this page objects collection.
49    #[inline]
50    fn as_range_inclusive(&self) -> RangeInclusive<PdfPageObjectIndex> {
51        if self.is_empty() { 0..=0 } else { 0..=(self.len() - 1) }
52    }
53
54    /// Returns a single [PdfPageObject] from this page objects collection.
55    fn get(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError>;
56
57    /// Returns the first [PdfPageObject] in this page objects collection.
58    #[inline]
59    fn first(&self) -> Result<PdfPageObject<'a>, PdfiumError> {
60        if !self.is_empty() {
61            self.get(0)
62        } else {
63            Err(PdfiumError::NoPageObjectsInCollection)
64        }
65    }
66
67    /// Returns the last [PdfPageObject] in this page objects collection.
68    #[inline]
69    fn last(&self) -> Result<PdfPageObject<'a>, PdfiumError> {
70        if !self.is_empty() {
71            self.get(self.len() - 1)
72        } else {
73            Err(PdfiumError::NoPageObjectsInCollection)
74        }
75    }
76
77    /// Returns an iterator over all the [PdfPageObject] objects in this page objects collection.
78    fn iter(&'a self) -> PdfPageObjectsIterator<'a>;
79
80    /// Returns the smallest bounding box that contains all the [PdfPageObject] objects in this
81    /// page objects collection.
82    fn bounds(&'a self) -> PdfRect {
83        let mut bottom: f32 = 0.0;
84        let mut top: f32 = 0.0;
85        let mut left: f32 = 0.0;
86        let mut right: f32 = 0.0;
87
88        for object in self.iter() {
89            if let Ok(bounds) = object.bounds() {
90                bottom = bottom.min(bounds.bottom().value);
91                top = top.max(bounds.top().value);
92                left = left.min(bounds.left().value);
93                right = right.max(bounds.right().value);
94            }
95        }
96
97        PdfRect::new_from_values(bottom, left, top, right)
98    }
99
100    /// Adds the given [PdfPageObject] to this page objects collection. The object's
101    /// memory ownership will be transferred to the [PdfPage] containing this page objects
102    /// collection, and the updated page object will be returned.
103    ///
104    /// If the containing [PdfPage] has a content regeneration strategy of
105    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
106    /// will be triggered on the page.
107    fn add_object(&mut self, object: PdfPageObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError>;
108
109    /// Adds the given [PdfPageTextObject] to this page objects collection,
110    /// returning the text object wrapped inside a generic [PdfPageObject] wrapper.
111    ///
112    /// If the containing [PdfPage] has a content regeneration strategy of
113    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
114    /// will be triggered on the page.
115    #[inline]
116    fn add_text_object(&mut self, object: PdfPageTextObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError> {
117        self.add_object(PdfPageObject::Text(object))
118    }
119
120    /// Creates a new [PdfPageTextObject] at the given x and y page co-ordinates
121    /// from the given arguments and adds it to this page objects collection,
122    /// returning the text object wrapped inside a generic [PdfPageObject] wrapper.
123    ///
124    /// If the containing [PdfPage] has a content regeneration strategy of
125    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
126    /// will be triggered on the page.
127    fn create_text_object(
128        &mut self,
129        x: PdfPoints,
130        y: PdfPoints,
131        text: impl ToString,
132        font: impl ToPdfFontToken,
133        font_size: PdfPoints,
134    ) -> Result<PdfPageObject<'a>, PdfiumError>;
135
136    /// Adds the given [PdfPagePathObject] to this page objects collection,
137    /// returning the path object wrapped inside a generic [PdfPageObject] wrapper.
138    ///
139    /// If the containing [PdfPage] has a content regeneration strategy of
140    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
141    /// will be triggered on the page.
142    #[inline]
143    fn add_path_object(&mut self, object: PdfPagePathObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError> {
144        self.add_object(PdfPageObject::Path(object))
145    }
146
147    /// Adds the given [PdfPageXObjectFormObject] to this page objects collection,
148    /// returning the XObject form object wrapped inside a generic [PdfPageObject] wrapper.
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    #[inline]
154    fn add_x_object_form_object(
155        &mut self,
156        object: PdfPageXObjectFormObject<'a>,
157    ) -> Result<PdfPageObject<'a>, PdfiumError> {
158        self.add_object(PdfPageObject::XObjectForm(object))
159    }
160
161    /// Creates a new [PdfPagePathObject] for the given line, with the given
162    /// stroke settings applied. The new path object will be added to this page objects collection
163    /// and then returned, wrapped inside a generic [PdfPageObject] wrapper.
164    ///
165    /// If the containing [PdfPage] has a content regeneration strategy of
166    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
167    /// will be triggered on the page.
168    fn create_path_object_line(
169        &mut self,
170        x1: PdfPoints,
171        y1: PdfPoints,
172        x2: PdfPoints,
173        y2: PdfPoints,
174        stroke_color: PdfColor,
175        stroke_width: PdfPoints,
176    ) -> Result<PdfPageObject<'a>, PdfiumError>;
177
178    /// Creates a new [PdfPagePathObject] for the given cubic Bézier curve, with the given
179    /// stroke settings applied. The new path object will be added to this page objects collection
180    /// and then returned, wrapped inside a generic [PdfPageObject] wrapper.
181    ///
182    /// If the containing [PdfPage] has a content regeneration strategy of
183    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
184    /// will be triggered on the page.
185    #[allow(clippy::too_many_arguments)]
186    fn create_path_object_bezier(
187        &mut self,
188        x1: PdfPoints,
189        y1: PdfPoints,
190        x2: PdfPoints,
191        y2: PdfPoints,
192        control1_x: PdfPoints,
193        control1_y: PdfPoints,
194        control2_x: PdfPoints,
195        control2_y: PdfPoints,
196        stroke_color: PdfColor,
197        stroke_width: PdfPoints,
198    ) -> Result<PdfPageObject<'a>, PdfiumError>;
199
200    /// Creates a new [PdfPagePathObject] for the given rectangle, with the given
201    /// fill and stroke settings applied. Both the stroke color and the stroke width must be
202    /// provided for the rectangle to be stroked. The new path object will be added to
203    /// this page objects collection and then returned, wrapped inside a generic
204    /// [PdfPageObject] wrapper.
205    ///
206    /// If the containing [PdfPage] has a content regeneration strategy of
207    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
208    /// will be triggered on the page.
209    fn create_path_object_rect(
210        &mut self,
211        rect: PdfRect,
212        stroke_color: Option<PdfColor>,
213        stroke_width: Option<PdfPoints>,
214        fill_color: Option<PdfColor>,
215    ) -> Result<PdfPageObject<'a>, PdfiumError>;
216
217    /// Creates a new [PdfPagePathObject]. The new path will be created with a circle that fills
218    /// the given rectangle, with the given fill and stroke settings applied. Both the stroke color
219    /// and the stroke width must be provided for the circle to be stroked. The new path object
220    /// will be added to this page objects collection and then returned, wrapped inside a generic
221    /// [PdfPageObject] wrapper.
222    ///
223    /// If the containing [PdfPage] has a content regeneration strategy of
224    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
225    /// will be triggered on the page.
226    fn create_path_object_circle(
227        &mut self,
228        rect: PdfRect,
229        stroke_color: Option<PdfColor>,
230        stroke_width: Option<PdfPoints>,
231        fill_color: Option<PdfColor>,
232    ) -> Result<PdfPageObject<'a>, PdfiumError>;
233
234    /// Creates a new [PdfPagePathObject]. The new path will be created with a circle centered
235    /// at the given coordinates, with the given radius, and with the given fill and stroke settings
236    /// applied. Both the stroke color and the stroke width must be provided for the circle to be
237    /// stroked. The new path object will be added to this page objects collection and then
238    /// returned, wrapped inside a generic [PdfPageObject] wrapper.
239    ///
240    /// If the containing [PdfPage] has a content regeneration strategy of
241    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
242    /// will be triggered on the page.
243    fn create_path_object_circle_at(
244        &mut self,
245        center_x: PdfPoints,
246        center_y: PdfPoints,
247        radius: PdfPoints,
248        stroke_color: Option<PdfColor>,
249        stroke_width: Option<PdfPoints>,
250        fill_color: Option<PdfColor>,
251    ) -> Result<PdfPageObject<'a>, PdfiumError>;
252
253    /// Creates a new [PdfPagePathObject]. The new path will be created with an ellipse that fills
254    /// the given rectangle, with the given fill and stroke settings applied. Both the stroke color
255    /// and the stroke width must be provided for the ellipse to be stroked. The new path object
256    /// will be added to this page objects collection and then returned, wrapped inside a generic
257    /// [PdfPageObject] wrapper.
258    ///
259    /// If the containing [PdfPage] has a content regeneration strategy of
260    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
261    /// will be triggered on the page.
262    fn create_path_object_ellipse(
263        &mut self,
264        rect: PdfRect,
265        stroke_color: Option<PdfColor>,
266        stroke_width: Option<PdfPoints>,
267        fill_color: Option<PdfColor>,
268    ) -> Result<PdfPageObject<'a>, PdfiumError>;
269
270    /// Creates a new [PdfPagePathObject]. The new path will be created with an ellipse centered
271    /// at the given coordinates, with the given radii, and with the given fill and stroke settings
272    /// applied. Both the stroke color and the stroke width must be provided for the ellipse to be
273    /// stroked. The new path object will be added to this page objects collection and then
274    /// returned, wrapped inside a generic [PdfPageObject] wrapper.
275    ///
276    /// If the containing [PdfPage] has a content regeneration strategy of
277    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
278    /// will be triggered on the page.
279    #[allow(clippy::too_many_arguments)]
280    fn create_path_object_ellipse_at(
281        &mut self,
282        center_x: PdfPoints,
283        center_y: PdfPoints,
284        x_radius: PdfPoints,
285        y_radius: PdfPoints,
286        stroke_color: Option<PdfColor>,
287        stroke_width: Option<PdfPoints>,
288        fill_color: Option<PdfColor>,
289    ) -> Result<PdfPageObject<'a>, PdfiumError>;
290
291    /// Adds the given [PdfPageImageObject] to this page objects collection,
292    /// returning the image object wrapped inside a generic [PdfPageObject] wrapper.
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    fn add_image_object(&mut self, object: PdfPageImageObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError> {
299        self.add_object(PdfPageObject::Image(object))
300    }
301
302    /// Creates a new [PdfPageImageObject] at the given x and y page co-ordinates
303    /// from the given arguments and adds it to this page objects collection,
304    /// returning the image object wrapped inside a generic [PdfPageObject] wrapper.
305    ///
306    /// By default, new image objects have their width and height both set to 1.0 points.
307    /// If provided, the given width and/or height will be applied to the newly created object to
308    /// scale its size.
309    ///
310    /// If the containing [PdfPage] has a content regeneration strategy of
311    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
312    /// will be triggered on the page.
313    ///
314    /// This function is only available when this crate's `image` feature is enabled.
315    #[cfg(feature = "image_025")]
316    fn create_image_object(
317        &mut self,
318        x: PdfPoints,
319        y: PdfPoints,
320        image: &DynamicImage,
321        width: Option<PdfPoints>,
322        height: Option<PdfPoints>,
323    ) -> Result<PdfPageObject<'a>, PdfiumError>;
324
325    /// Removes the given [PdfPageObject] from this page objects collection. The object's
326    /// memory ownership will be removed from the [PdfPage] containing this page objects
327    /// collection, and the updated page object will be returned. It can be added back to a
328    /// page objects collection or dropped, at which point the memory owned by the object will
329    /// be freed.
330    ///
331    /// If the containing [PdfPage] has a content regeneration strategy of
332    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
333    /// will be triggered on the page.
334    fn remove_object(&mut self, object: PdfPageObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError>;
335
336    /// Removes the [PdfPageObject] at the given index from this page objects collection.
337    /// The object's memory ownership will be removed from the [PdfPage] containing this page objects
338    /// collection, and the updated page object will be returned. It can be added back into a
339    /// page objects collection or discarded, at which point the memory owned by the object will
340    /// be freed.
341    ///
342    /// If the containing [PdfPage] has a content regeneration strategy of
343    /// [PdfPageContentRegenerationStrategy::AutomaticOnEveryChange] then content regeneration
344    /// will be triggered on the page.
345    fn remove_object_at_index(&mut self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError>;
346}
347
348impl<'a, T> PdfPageObjectsCommon<'a> for T
349where
350    T: PdfPageObjectsPrivate<'a>,
351{
352    #[inline]
353    fn len(&self) -> PdfPageObjectIndex {
354        self.len_impl()
355    }
356
357    #[inline]
358    fn get(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError> {
359        self.get_impl(index)
360    }
361
362    #[inline]
363    fn iter(&'a self) -> PdfPageObjectsIterator<'a> {
364        self.iter_impl()
365    }
366
367    #[inline]
368    fn add_object(&mut self, object: PdfPageObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError> {
369        self.add_object_impl(object)
370    }
371
372    #[inline]
373    fn create_text_object(
374        &mut self,
375        x: PdfPoints,
376        y: PdfPoints,
377        text: impl ToString,
378        font: impl ToPdfFontToken,
379        font_size: PdfPoints,
380    ) -> Result<PdfPageObject<'a>, PdfiumError> {
381        let document_handle = match self.ownership() {
382            PdfPageObjectOwnership::Page(ownership) => Some(ownership.document_handle()),
383            PdfPageObjectOwnership::AttachedAnnotation(ownership) => Some(ownership.document_handle()),
384            PdfPageObjectOwnership::UnattachedAnnotation(ownership) => Some(ownership.document_handle()),
385            _ => None,
386        };
387
388        if let Some(document_handle) = document_handle {
389            let mut object = PdfPageTextObject::new_from_handles(
390                document_handle,
391                text,
392                font.token().handle(),
393                font_size,
394                self.bindings(),
395            )?;
396
397            object.translate(x, y)?;
398
399            self.add_text_object(object)
400        } else {
401            Err(PdfiumError::OwnershipNotAttachedToPage)
402        }
403    }
404
405    #[inline]
406    fn create_path_object_line(
407        &mut self,
408        x1: PdfPoints,
409        y1: PdfPoints,
410        x2: PdfPoints,
411        y2: PdfPoints,
412        stroke_color: PdfColor,
413        stroke_width: PdfPoints,
414    ) -> Result<PdfPageObject<'a>, PdfiumError> {
415        let object =
416            PdfPagePathObject::new_line_from_bindings(self.bindings(), x1, y1, x2, y2, stroke_color, stroke_width)?;
417
418        self.add_path_object(object)
419    }
420
421    #[inline]
422    fn create_path_object_bezier(
423        &mut self,
424        x1: PdfPoints,
425        y1: PdfPoints,
426        x2: PdfPoints,
427        y2: PdfPoints,
428        control1_x: PdfPoints,
429        control1_y: PdfPoints,
430        control2_x: PdfPoints,
431        control2_y: PdfPoints,
432        stroke_color: PdfColor,
433        stroke_width: PdfPoints,
434    ) -> Result<PdfPageObject<'a>, PdfiumError> {
435        let object = PdfPagePathObject::new_bezier_from_bindings(
436            self.bindings(),
437            x1,
438            y1,
439            x2,
440            y2,
441            control1_x,
442            control1_y,
443            control2_x,
444            control2_y,
445            stroke_color,
446            stroke_width,
447        )?;
448
449        self.add_path_object(object)
450    }
451
452    #[inline]
453    fn create_path_object_rect(
454        &mut self,
455        rect: PdfRect,
456        stroke_color: Option<PdfColor>,
457        stroke_width: Option<PdfPoints>,
458        fill_color: Option<PdfColor>,
459    ) -> Result<PdfPageObject<'a>, PdfiumError> {
460        let object =
461            PdfPagePathObject::new_rect_from_bindings(self.bindings(), rect, stroke_color, stroke_width, fill_color)?;
462
463        self.add_path_object(object)
464    }
465
466    #[inline]
467    fn create_path_object_circle(
468        &mut self,
469        rect: PdfRect,
470        stroke_color: Option<PdfColor>,
471        stroke_width: Option<PdfPoints>,
472        fill_color: Option<PdfColor>,
473    ) -> Result<PdfPageObject<'a>, PdfiumError> {
474        let object =
475            PdfPagePathObject::new_circle_from_bindings(self.bindings(), rect, stroke_color, stroke_width, fill_color)?;
476
477        self.add_path_object(object)
478    }
479
480    #[inline]
481    fn create_path_object_circle_at(
482        &mut self,
483        center_x: PdfPoints,
484        center_y: PdfPoints,
485        radius: PdfPoints,
486        stroke_color: Option<PdfColor>,
487        stroke_width: Option<PdfPoints>,
488        fill_color: Option<PdfColor>,
489    ) -> Result<PdfPageObject<'a>, PdfiumError> {
490        let object = PdfPagePathObject::new_circle_at_from_bindings(
491            self.bindings(),
492            center_x,
493            center_y,
494            radius,
495            stroke_color,
496            stroke_width,
497            fill_color,
498        )?;
499
500        self.add_path_object(object)
501    }
502
503    #[inline]
504    fn create_path_object_ellipse(
505        &mut self,
506        rect: PdfRect,
507        stroke_color: Option<PdfColor>,
508        stroke_width: Option<PdfPoints>,
509        fill_color: Option<PdfColor>,
510    ) -> Result<PdfPageObject<'a>, PdfiumError> {
511        let object = PdfPagePathObject::new_ellipse_from_bindings(
512            self.bindings(),
513            rect,
514            stroke_color,
515            stroke_width,
516            fill_color,
517        )?;
518
519        self.add_path_object(object)
520    }
521
522    #[inline]
523    fn create_path_object_ellipse_at(
524        &mut self,
525        center_x: PdfPoints,
526        center_y: PdfPoints,
527        x_radius: PdfPoints,
528        y_radius: PdfPoints,
529        stroke_color: Option<PdfColor>,
530        stroke_width: Option<PdfPoints>,
531        fill_color: Option<PdfColor>,
532    ) -> Result<PdfPageObject<'a>, PdfiumError> {
533        let object = PdfPagePathObject::new_ellipse_at_from_bindings(
534            self.bindings(),
535            center_x,
536            center_y,
537            x_radius,
538            y_radius,
539            stroke_color,
540            stroke_width,
541            fill_color,
542        )?;
543
544        self.add_path_object(object)
545    }
546
547    #[cfg(feature = "image_025")]
548    fn create_image_object(
549        &mut self,
550        x: PdfPoints,
551        y: PdfPoints,
552        image: &DynamicImage,
553        width: Option<PdfPoints>,
554        height: Option<PdfPoints>,
555    ) -> Result<PdfPageObject<'a>, PdfiumError> {
556        let document_handle = match self.ownership() {
557            PdfPageObjectOwnership::Page(ownership) => Some(ownership.document_handle()),
558            PdfPageObjectOwnership::AttachedAnnotation(ownership) => Some(ownership.document_handle()),
559            PdfPageObjectOwnership::UnattachedAnnotation(ownership) => Some(ownership.document_handle()),
560            _ => None,
561        };
562
563        if let Some(document_handle) = document_handle {
564            let image_width = image.width();
565
566            let image_height = image.height();
567
568            let mut object = PdfPageImageObject::new_from_handle(document_handle, self.bindings())?;
569
570            object.set_image(image)?;
571
572            match (width, height) {
573                (Some(width), Some(height)) => {
574                    object.scale(width.value, height.value)?;
575                }
576                (Some(width), None) => {
577                    let aspect_ratio = image_height as f32 / image_width as f32;
578
579                    let height = width * aspect_ratio;
580
581                    object.scale(width.value, height.value)?;
582                }
583                (None, Some(height)) => {
584                    let aspect_ratio = image_height as f32 / image_width as f32;
585
586                    let width = height / aspect_ratio;
587
588                    object.scale(width.value, height.value)?;
589                }
590                (None, None) => {}
591            }
592
593            object.translate(x, y)?;
594
595            self.add_image_object(object)
596        } else {
597            Err(PdfiumError::OwnershipNotAttachedToPage)
598        }
599    }
600
601    #[inline]
602    fn remove_object(&mut self, object: PdfPageObject<'a>) -> Result<PdfPageObject<'a>, PdfiumError> {
603        self.remove_object_impl(object)
604    }
605
606    fn remove_object_at_index(&mut self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError> {
607        if index >= self.len() {
608            return Err(PdfiumError::PageObjectIndexOutOfBounds);
609        }
610
611        if let Ok(object) = self.get(index) {
612            self.remove_object(object)
613        } else {
614            Err(PdfiumError::PdfiumLibraryInternalError(PdfiumInternalError::Unknown))
615        }
616    }
617}
618
619/// An iterator over all the [PdfPageObject] objects in a page objects collection.
620pub struct PdfPageObjectsIterator<'a> {
621    objects: &'a dyn PdfPageObjectsPrivate<'a>,
622    next_index: PdfPageObjectIndex,
623}
624
625impl<'a> PdfPageObjectsIterator<'a> {
626    #[inline]
627    pub(crate) fn new(objects: &'a dyn PdfPageObjectsPrivate<'a>) -> Self {
628        PdfPageObjectsIterator { objects, next_index: 0 }
629    }
630}
631
632impl<'a> Iterator for PdfPageObjectsIterator<'a> {
633    type Item = PdfPageObject<'a>;
634
635    fn next(&mut self) -> Option<Self::Item> {
636        let next = self.objects.get_impl(self.next_index);
637
638        self.next_index += 1;
639
640        next.ok()
641    }
642}