1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
//! This example shows how to use pdf-writer in a bit more realisitic
//! circumstances.
//!
//! It demonstrates how to allocate IDs on the fly using [`Ref::bump`] and
//! shows how to write multiple things at once using [`Chunk`]s.
use pdf_writer::{Chunk, Content, Name, Pdf, Rect, Ref};
fn main() -> std::io::Result<()> {
// Define an ID allocator. Every time we need a new object, we just call
// `alloc.bump()`, which increases `alloc` by one and returns its previous
// value.
let mut alloc = Ref::new(1);
// Start writing.
let mut pdf = Pdf::new();
// Create a secondary chunk for parallel writing. This will allows us to
// write stuff while we're also holding a mutable reference to the main
// writer.
let mut secondary = Chunk::new();
// We'll collect the page IDs here.
let page_tree_id = alloc.bump();
let mut page_ids = vec![];
// Write a few pages with different colors.
for p in 0..10 {
// We'll create five shapes with varying transparency.
let count = 5;
// Write the page.
let page_id = alloc.bump();
page_ids.push(page_id);
let mut page = pdf.page(page_id);
let width = 90.0 + 60.0 * count as f32;
page.media_box(Rect::new(0.0, 0.0, width, 200.0));
page.parent(page_tree_id);
// Create the page's content.
let mut content = Content::new();
let mut extg_states = vec![];
for i in 1..=count {
// Define a unique name for the ExtG state.
let state_name = format!("G_{p}_{i}");
// Write the content that references the state.
let x = 60.0 * i as f32 - 10.0;
content.set_parameters(Name(state_name.as_bytes()));
content.set_fill_rgb(1.0, 0.1 * p as f32, 0.0);
content.rect(x, 50.0, 50.0, 100.0);
content.fill_even_odd();
// Write the ExtG state into the secondary chunk. Note how we can
// write into it even though the main `pdf` writer is currently
// borrowed.
//
// In a real application, we could also try to deduplicate ExtG
// states here to save precious file size.
let state_id = alloc.bump();
let alpha = i as f32 / count as f32;
secondary.ext_graphics(state_id).non_stroking_alpha(alpha);
extg_states.push((state_name, state_id));
}
// Write the content, add it to the secondary chunk (the main chunk is
// still borrowed) and register it with the page.
let content_id = alloc.bump();
secondary.stream(content_id, &content.finish());
page.contents(content_id);
// Reference the ExtG states that we wrote in the page's resources
// dictionary.
page.resources()
.ext_g_states()
.pairs(extg_states.iter().map(|(n, id)| (Name(n.as_bytes()), id)));
}
// Add the ExtG states to the PDF.
pdf.extend(&secondary);
// Write the root of the page tree.
pdf.pages(page_tree_id)
.kids(page_ids.iter().copied())
.count(page_ids.len() as i32);
// Write the document catalog.
pdf.catalog(alloc.bump()).pages(page_tree_id);
// Finish and write the thing to a file.
std::fs::write("target/chunks.pdf", pdf.finish())
}