justpdf_core/writer/
mod.rs1pub mod clean;
2pub mod compress;
3pub mod document;
4pub mod encode;
5pub mod linearize;
6pub mod modify;
7pub mod object_stream;
8pub mod page;
9pub mod serialize;
10
11pub use clean::{clean_objects, CleanStats};
12pub use compress::{compress_pdf, analyze_pdf, CompressOptions, CompressStats, AnalyzeResult};
13pub use document::{DocumentBuilder, embed_jpeg, embed_png};
14pub use encode::{encode_flate, make_stream};
15pub use linearize::linearize as linearize_pdf;
16pub use modify::{merge_documents, incremental_save, DocumentModifier};
17pub use object_stream::pack_object_streams;
18pub use page::PageBuilder;
19pub use serialize::{serialize_pdf, serialize_pdf_encrypted};
20
21use crate::error::Result;
22use crate::object::{IndirectRef, PdfObject};
23
24use std::path::Path;
25
26pub struct PdfWriter {
29 pub objects: Vec<(u32, PdfObject)>,
31 pub(crate) next_obj_num: u32,
33 pub version: (u8, u8),
35}
36
37impl PdfWriter {
38 pub fn new() -> Self {
40 Self {
41 objects: Vec::new(),
42 next_obj_num: 1,
43 version: (1, 7),
44 }
45 }
46
47 pub fn alloc_object_num(&mut self) -> u32 {
50 let num = self.next_obj_num;
51 self.next_obj_num += 1;
52 num
53 }
54
55 pub fn add_object(&mut self, obj: PdfObject) -> IndirectRef {
58 let num = self.alloc_object_num();
59 self.objects.push((num, obj));
60 IndirectRef {
61 obj_num: num,
62 gen_num: 0,
63 }
64 }
65
66 pub fn set_object(&mut self, obj_num: u32, obj: PdfObject) {
69 if let Some(entry) = self.objects.iter_mut().find(|(n, _)| *n == obj_num) {
70 entry.1 = obj;
71 } else {
72 self.objects.push((obj_num, obj));
73 }
74 }
75
76 pub fn write_to_bytes(&self, catalog_ref: &IndirectRef) -> Result<Vec<u8>> {
78 serialize_pdf(&self.objects, self.version, catalog_ref, None)
79 }
80
81 pub fn write_to_file(&self, path: &Path, catalog_ref: &IndirectRef) -> Result<()> {
83 let bytes = self.write_to_bytes(catalog_ref)?;
84 std::fs::write(path, bytes)?;
85 Ok(())
86 }
87}
88
89impl Default for PdfWriter {
90 fn default() -> Self {
91 Self::new()
92 }
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98 use crate::object::PdfObject;
99
100 #[test]
101 fn test_add_object_increments_refs() {
102 let mut writer = PdfWriter::new();
103
104 let ref1 = writer.add_object(PdfObject::Integer(1));
105 assert_eq!(ref1.obj_num, 1);
106 assert_eq!(ref1.gen_num, 0);
107
108 let ref2 = writer.add_object(PdfObject::Integer(2));
109 assert_eq!(ref2.obj_num, 2);
110 assert_eq!(ref2.gen_num, 0);
111
112 let ref3 = writer.add_object(PdfObject::Integer(3));
113 assert_eq!(ref3.obj_num, 3);
114 assert_eq!(ref3.gen_num, 0);
115
116 assert_eq!(writer.objects.len(), 3);
117 }
118
119 #[test]
120 fn test_alloc_object_num() {
121 let mut writer = PdfWriter::new();
122 let num = writer.alloc_object_num();
123 assert_eq!(num, 1);
124
125 let ref1 = writer.add_object(PdfObject::Null);
126 assert_eq!(ref1.obj_num, 2);
127 }
128
129 #[test]
130 fn test_set_object_replaces() {
131 let mut writer = PdfWriter::new();
132 let r = writer.add_object(PdfObject::Integer(10));
133 writer.set_object(r.obj_num, PdfObject::Integer(20));
134
135 assert_eq!(writer.objects.len(), 1);
136 assert_eq!(writer.objects[0].1, PdfObject::Integer(20));
137 }
138
139 #[test]
140 fn test_set_object_new() {
141 let mut writer = PdfWriter::new();
142 writer.set_object(5, PdfObject::Integer(50));
143 assert_eq!(writer.objects.len(), 1);
144 assert_eq!(writer.objects[0].0, 5);
145 }
146}