pdfium_render/pdf/document/page/
objects.rs

1//! Defines the [PdfPageObjects] struct, exposing functionality related to the
2//! page objects contained within a single `PdfPage`.
3
4pub mod common;
5pub(crate) mod private; // Keep private so that the PdfPageObjectsPrivate trait is not exposed.
6
7use crate::bindgen::{FPDF_DOCUMENT, FPDF_PAGE};
8use crate::bindings::PdfiumLibraryBindings;
9use crate::error::{PdfiumError, PdfiumInternalError};
10use crate::pdf::document::page::object::group::PdfPageGroupObject;
11use crate::pdf::document::page::object::ownership::PdfPageObjectOwnership;
12use crate::pdf::document::page::object::private::internal::PdfPageObjectPrivate;
13use crate::pdf::document::page::object::PdfPageObject;
14use crate::pdf::document::page::objects::common::{
15    PdfPageObjectIndex, PdfPageObjectsCommon, PdfPageObjectsIterator,
16};
17use crate::pdf::document::page::objects::private::internal::PdfPageObjectsPrivate;
18use std::os::raw::c_int;
19
20/// The page objects contained within a single `PdfPage`.
21///
22/// Content on a page is structured as a stream of [PdfPageObject] objects of different types:
23/// text objects, image objects, path objects, and so on.
24///
25/// Note that Pdfium does not support or recognize all PDF page object types. For instance,
26/// Pdfium does not currently support or recognize the External Object ("XObject") page object type
27/// supported by Adobe Acrobat and Foxit's commercial PDF SDK. In these cases, Pdfium will return
28/// `PdfPageObjectType::Unsupported`.
29pub struct PdfPageObjects<'a> {
30    document_handle: FPDF_DOCUMENT,
31    page_handle: FPDF_PAGE,
32    ownership: PdfPageObjectOwnership,
33    bindings: &'a dyn PdfiumLibraryBindings,
34}
35
36impl<'a> PdfPageObjects<'a> {
37    #[inline]
38    pub(crate) fn from_pdfium(
39        document_handle: FPDF_DOCUMENT,
40        page_handle: FPDF_PAGE,
41        bindings: &'a dyn PdfiumLibraryBindings,
42    ) -> Self {
43        Self {
44            document_handle,
45            page_handle,
46            ownership: PdfPageObjectOwnership::owned_by_page(document_handle, page_handle),
47            bindings,
48        }
49    }
50
51    /// Returns the internal `FPDF_DOCUMENT` handle for this page objects collection.
52    #[inline]
53    pub(crate) fn document_handle(&self) -> FPDF_DOCUMENT {
54        self.document_handle
55    }
56
57    /// Returns the internal `FPDF_PAGE` handle for this page objects collection.
58    #[inline]
59    pub(crate) fn page_handle(&self) -> FPDF_PAGE {
60        self.page_handle
61    }
62
63    /// Creates a new [PdfPageGroupObject] object group that includes any page objects in this
64    /// [PdfPageObjects] collection matching the given predicate function.
65    pub fn create_group<F>(&'a self, predicate: F) -> Result<PdfPageGroupObject<'a>, PdfiumError>
66    where
67        F: Fn(&PdfPageObject) -> bool,
68    {
69        let mut result = self.create_empty_group();
70
71        for mut object in self.iter().filter(predicate) {
72            result.push(&mut object)?;
73        }
74
75        Ok(result)
76    }
77
78    /// Creates a new [PdfPageGroupObject] object group that can accept any [PdfPageObject]
79    /// in this [PdfPageObjects] collection. The newly created group will be empty;
80    /// you will need to manually add to it the objects you want to manipulate.
81    #[inline]
82    pub fn create_empty_group(&self) -> PdfPageGroupObject<'a> {
83        PdfPageGroupObject::from_pdfium(self.document_handle(), self.page_handle(), self.bindings())
84    }
85}
86
87impl<'a> PdfPageObjectsPrivate<'a> for PdfPageObjects<'a> {
88    #[inline]
89    fn ownership(&self) -> &PdfPageObjectOwnership {
90        &self.ownership
91    }
92
93    #[inline]
94    fn bindings(&self) -> &'a dyn PdfiumLibraryBindings {
95        self.bindings
96    }
97
98    #[inline]
99    fn len_impl(&self) -> PdfPageObjectIndex {
100        self.bindings.FPDFPage_CountObjects(self.page_handle) as PdfPageObjectIndex
101    }
102
103    fn get_impl(&self, index: PdfPageObjectIndex) -> Result<PdfPageObject<'a>, PdfiumError> {
104        if index >= self.len() {
105            return Err(PdfiumError::PageObjectIndexOutOfBounds);
106        }
107
108        let object_handle = self
109            .bindings
110            .FPDFPage_GetObject(self.page_handle, index as c_int);
111
112        if object_handle.is_null() {
113            Err(PdfiumError::PdfiumLibraryInternalError(
114                PdfiumInternalError::Unknown,
115            ))
116        } else {
117            Ok(PdfPageObject::from_pdfium(
118                object_handle,
119                self.ownership().clone(),
120                self.bindings(),
121            ))
122        }
123    }
124
125    #[inline]
126    fn iter_impl(&'a self) -> PdfPageObjectsIterator<'a> {
127        PdfPageObjectsIterator::new(self)
128    }
129
130    #[inline]
131    fn add_object_impl(
132        &mut self,
133        mut object: PdfPageObject<'a>,
134    ) -> Result<PdfPageObject<'a>, PdfiumError> {
135        object.add_object_to_page(self).map(|_| object)
136    }
137
138    #[inline]
139    fn remove_object_impl(
140        &mut self,
141        mut object: PdfPageObject<'a>,
142    ) -> Result<PdfPageObject<'a>, PdfiumError> {
143        object.remove_object_from_page().map(|_| object)
144    }
145}