oxidize_pdf/
document.rs

1use crate::error::Result;
2use crate::objects::{Object, ObjectId};
3use crate::page::Page;
4use crate::writer::PdfWriter;
5use std::collections::HashMap;
6
7/// A PDF document that can contain multiple pages and metadata.
8///
9/// # Example
10///
11/// ```rust
12/// use oxidize_pdf::{Document, Page};
13///
14/// let mut doc = Document::new();
15/// doc.set_title("My Document");
16/// doc.set_author("John Doe");
17///
18/// let page = Page::a4();
19/// doc.add_page(page);
20///
21/// doc.save("output.pdf").unwrap();
22/// ```
23pub struct Document {
24    pub(crate) pages: Vec<Page>,
25    #[allow(dead_code)]
26    pub(crate) objects: HashMap<ObjectId, Object>,
27    #[allow(dead_code)]
28    pub(crate) next_object_id: u32,
29    pub(crate) metadata: DocumentMetadata,
30}
31
32/// Metadata for a PDF document.
33#[derive(Debug, Clone)]
34pub struct DocumentMetadata {
35    /// Document title
36    pub title: Option<String>,
37    /// Document author
38    pub author: Option<String>,
39    /// Document subject
40    pub subject: Option<String>,
41    /// Document keywords
42    pub keywords: Option<String>,
43    /// Software that created the original document
44    pub creator: Option<String>,
45    /// Software that produced the PDF
46    pub producer: Option<String>,
47}
48
49impl Default for DocumentMetadata {
50    fn default() -> Self {
51        Self {
52            title: None,
53            author: None,
54            subject: None,
55            keywords: None,
56            creator: Some("oxidize_pdf".to_string()),
57            producer: Some("oxidize_pdf".to_string()),
58        }
59    }
60}
61
62impl Document {
63    /// Creates a new empty PDF document.
64    pub fn new() -> Self {
65        Self {
66            pages: Vec::new(),
67            objects: HashMap::new(),
68            next_object_id: 1,
69            metadata: DocumentMetadata::default(),
70        }
71    }
72
73    /// Adds a page to the document.
74    pub fn add_page(&mut self, page: Page) {
75        self.pages.push(page);
76    }
77
78    /// Sets the document title.
79    pub fn set_title(&mut self, title: impl Into<String>) {
80        self.metadata.title = Some(title.into());
81    }
82
83    /// Sets the document author.
84    pub fn set_author(&mut self, author: impl Into<String>) {
85        self.metadata.author = Some(author.into());
86    }
87
88    /// Sets the document subject.
89    pub fn set_subject(&mut self, subject: impl Into<String>) {
90        self.metadata.subject = Some(subject.into());
91    }
92
93    /// Sets the document keywords.
94    pub fn set_keywords(&mut self, keywords: impl Into<String>) {
95        self.metadata.keywords = Some(keywords.into());
96    }
97
98    /// Saves the document to a file.
99    ///
100    /// # Errors
101    ///
102    /// Returns an error if the file cannot be created or written.
103    pub fn save(&mut self, path: impl AsRef<std::path::Path>) -> Result<()> {
104        let mut writer = PdfWriter::new(path)?;
105        writer.write_document(self)?;
106        Ok(())
107    }
108
109    /// Writes the document to a buffer.
110    ///
111    /// # Errors
112    ///
113    /// Returns an error if the PDF cannot be generated.
114    pub fn write(&mut self, buffer: &mut Vec<u8>) -> Result<()> {
115        let mut writer = PdfWriter::new_with_writer(buffer);
116        writer.write_document(self)?;
117        Ok(())
118    }
119
120    #[allow(dead_code)]
121    pub(crate) fn allocate_object_id(&mut self) -> ObjectId {
122        let id = ObjectId::new(self.next_object_id, 0);
123        self.next_object_id += 1;
124        id
125    }
126
127    #[allow(dead_code)]
128    pub(crate) fn add_object(&mut self, obj: Object) -> ObjectId {
129        let id = self.allocate_object_id();
130        self.objects.insert(id, obj);
131        id
132    }
133}
134
135impl Default for Document {
136    fn default() -> Self {
137        Self::new()
138    }
139}