Skip to main content

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