pub struct Footer {
pub height: f32,
pub content: Rc<dyn Fn(&PageContext) -> Element>,
}Fields§
§height: f32§content: Rc<dyn Fn(&PageContext) -> Element>Implementations§
Sourcepub fn new(
height: f32,
content: impl Fn(&PageContext) -> Element + 'static,
) -> Footer
pub fn new( height: f32, content: impl Fn(&PageContext) -> Element + 'static, ) -> Footer
Examples found in repository?
examples/report.rs (lines 50-55)
42fn main() {
43 let mut doc = Document::new(PageFormat::A4)
44 .margin(Margin::symmetric(56.0, 56.0))
45 .theme(brand_theme())
46 .header(Header::new(20.0, |_ctx| {
47 Text::new("Jahresbericht 2026 \u{2014} Muster GmbH").size(9.0).into()
48 }))
49 .header_visible_from(2)
50 .footer(Footer::new(20.0, |ctx| {
51 Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages))
52 .size(9.0)
53 .align(Align::Center)
54 .into()
55 }))
56 .watermark(Watermark::new("ENTWURF"));
57
58 // --- cover page -----------------------------------------------------
59 doc.add(Spacer::new(220.0));
60 doc.add(Text::new("Jahresbericht 2026").heading1().align(Align::Center));
61 doc.add(Spacer::new(8.0));
62 doc.add(Text::new("Muster GmbH").align(Align::Center));
63 doc.add(Text::new("vorgelegt am 20. August 2026").muted().align(Align::Center));
64 doc.add(Element::PageBreak);
65
66 // --- content ---------------------------------------------------------
67 doc.add(Text::new("1. Zusammenfassung").heading1());
68 doc.add(Text::new(
69 "Das Geschäftsjahr 2026 war geprägt von stabilem Wachstum in allen \
70 Kernbereichen. Die folgenden Abschnitte fassen die wichtigsten \
71 Kennzahlen und Entwicklungen zusammen.",
72 ));
73 doc.add(Spacer::new(12.0));
74
75 doc.add(Text::new("2. Wichtigste Ereignisse").heading2());
76 doc.add(
77 List::new()
78 .bullet(Text::new("Markteinführung des neuen Produkts im zweiten Quartal"))
79 .bullet(Text::new("Erweiterung des Teams um 12 neue Mitarbeitende"))
80 .bullet(Text::new("Eröffnung eines zweiten Standorts")),
81 );
82 doc.add(Spacer::new(12.0));
83
84 doc.add(Text::new("3. Zeitplan").heading2());
85 doc.add(
86 List::new()
87 .numbered(Text::new("Kickoff und Planung (Januar \u{2013} Februar)"))
88 .numbered(Text::new("Umsetzung Phase 1 (M\u{e4}rz \u{2013} Juni)"))
89 .numbered(Text::new("Umsetzung Phase 2 (Juli \u{2013} Oktober)"))
90 .numbered(Text::new("Abschluss und Auswertung (November \u{2013} Dezember)")),
91 );
92 doc.add(Spacer::new(12.0));
93
94 doc.add(Text::new("3.1 Details").heading3());
95 doc.add(Text::new(
96 "Weitere Details zu den einzelnen Phasen finden sich im Anhang. \
97 Diese Überschrift bleibt dank keep_with_next garantiert mit \
98 diesem Absatz auf derselben Seite zusammen.",
99 ));
100
101 common::write_pdf(&doc, "report.pdf");
102}More examples
examples/invoice.rs (lines 71-83)
35fn main() {
36 let mut items = vec![
37 LineItem {
38 description: "Beratungsleistung Projekt Alpha".to_string(),
39 qty: 8,
40 unit_price_cents: 12_000,
41 },
42 LineItem {
43 description: "Lizenz Software-Paket (jährlich)".to_string(),
44 qty: 1,
45 unit_price_cents: 49_900,
46 },
47 LineItem {
48 description: "Individuelle Anpassung / Customizing".to_string(),
49 qty: 3,
50 unit_price_cents: 15_000,
51 },
52 ];
53 // A few filler positions so the table is guaranteed to span more than
54 // one page, demonstrating the header-repeat-on-split behavior.
55 for i in 1..=25 {
56 items.push(LineItem {
57 description: format!("Zusatzposition {i:02}"),
58 qty: 1,
59 unit_price_cents: 990,
60 });
61 }
62
63 let net_total: i64 = items.iter().map(|i| i.qty as i64 * i.unit_price_cents).sum();
64 let vat_rate = 19;
65 let vat_total = net_total * vat_rate / 100;
66 let gross_total = net_total + vat_total;
67
68 let top_margin = 15.0 * MM;
69 let mut doc = Document::new(PageFormat::A4)
70 .margin(Margin::symmetric(20.0 * MM, top_margin))
71 .footer(Footer::new(30.0, |ctx| {
72 Column::new()
73 .gap(2.0)
74 .child(Line::new())
75 .child(
76 Row::new()
77 .gap(20.0)
78 .child(Text::new("Musterbank · IBAN DE12 3456 7890 1234 5678 90 · BIC MUSTDEFF").size(8.0))
79 .child(Text::new("USt-IdNr. DE123456789").size(8.0).flex(1.0)),
80 )
81 .child(Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages)).size(8.0))
82 .into()
83 }));
84
85 // --- DIN 5008 Form A window-envelope address block ----------------
86 // Window starts ~45mm from the top, ~20mm from the left
87 // (`plan/02-elementcatalog-and-features.md`); ~85x40mm matches a
88 // typical C6/5-long window envelope opening. Position/size are a
89 // documented convention for this recipe, not parsed from any norm
90 // document — a caller with different envelope stock adjusts these.
91 doc.add(Spacer::new(45.0 * MM - top_margin));
92 doc.add(
93 Column::new()
94 .gap(2.0)
95 .width(85.0 * MM)
96 .height(40.0 * MM)
97 .child(Text::new("Muster GmbH · Musterstraße 1 · 12345 Musterstadt").size(7.0))
98 .child(Spacer::new(8.0))
99 .child(Text::new("Empfänger GmbH"))
100 .child(Text::new("Frau Erika Mustermann"))
101 .child(Text::new("Beispielweg 42"))
102 .child(Text::new("54321 Beispielstadt")),
103 );
104 doc.add(Spacer::new(10.0 * MM));
105
106 doc.add(Text::new("Rechnung").heading1());
107 doc.add(Text::new(
108 "Rechnungsnummer: RE-2026-0142 Rechnungsdatum: 20.08.2026 Leistungsdatum: 20.08.2026",
109 ));
110 doc.add(Spacer::new(10.0));
111
112 doc.add(
113 Table::new()
114 .columns([
115 TableColumn::flex(1.0),
116 TableColumn::fixed(50.0).align(Align::End),
117 TableColumn::fixed(65.0).align(Align::End),
118 TableColumn::fixed(70.0).align(Align::End),
119 ])
120 .header(["Beschreibung", "Menge", "Einzelpreis", "Gesamt"])
121 .striped(Color::rgb(0xF5, 0xF5, 0xF5))
122 .from_rows(&items),
123 );
124
125 doc.add(Spacer::new(14.0));
126
127 // --- summary block (Netto/USt/Brutto), right-aligned --------------
128 // Recipe (`plan/02-elementcatalog-and-features.md`): an outer, full-
129 // width auto Column with `.align(Align::End)` positions the fixed-
130 // width (200pt) inner summary Column at the right edge; within it,
131 // each label gets `.flex(1.0)` to push its value to that block's own
132 // right edge. No special "summary block" element needed.
133 doc.add(
134 Column::new()
135 .align(Align::End)
136 .child(Column::new().gap(2.0).width(200.0).children(vec![
137 Element::from(
138 Row::new()
139 .child(Text::new("Nettosumme").flex(1.0))
140 .child(Text::new(format_currency_de(net_total))),
141 ),
142 Element::from(
143 Row::new()
144 .child(Text::new(format!("zzgl. {vat_rate}% USt.")).flex(1.0))
145 .child(Text::new(format_currency_de(vat_total))),
146 ),
147 Element::from(Line::new()),
148 Element::from(
149 Row::new()
150 .child(Text::new("Gesamtbetrag").bold().flex(1.0))
151 .child(Text::new(format_currency_de(gross_total)).bold()),
152 ),
153 ])),
154 );
155
156 common::write_pdf(&doc, "invoice.pdf");
157}Trait Implementations§
Auto Trait Implementations§
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Mutably borrows from an owned value. Read more