pub struct Text {
pub content: String,
pub style: TextStyle,
pub common: Common,
}Fields§
§content: String§style: TextStyle§common: CommonImplementations§
Source§impl Text
impl Text
Sourcepub fn new(content: impl Into<String>) -> Text
pub fn new(content: impl Into<String>) -> Text
Examples found in repository?
examples/report.rs (line 14)
10fn main() {
11 let mut doc = Document::new(PageFormat::A4)
12 .margin(Margin::symmetric(56.0, 56.0))
13 .header(Header::new(20.0, |_ctx| {
14 Text::new("Jahresbericht 2026 \u{2014} Muster GmbH").size(9.0).into()
15 }))
16 .header_visible_from(2)
17 .footer(Footer::new(20.0, |ctx| {
18 Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages))
19 .size(9.0)
20 .align(Align::Center)
21 .into()
22 }))
23 .watermark(Watermark::new("ENTWURF"));
24
25 // --- cover page -----------------------------------------------------
26 doc.add(Spacer::new(220.0));
27 doc.add(Text::new("Jahresbericht 2026").heading1().align(Align::Center));
28 doc.add(Spacer::new(8.0));
29 doc.add(Text::new("Muster GmbH").align(Align::Center));
30 doc.add(Text::new("vorgelegt am 20. August 2026").align(Align::Center));
31 doc.add(Element::PageBreak);
32
33 // --- content ---------------------------------------------------------
34 doc.add(Text::new("1. Zusammenfassung").heading1());
35 doc.add(Text::new(
36 "Das Geschäftsjahr 2026 war geprägt von stabilem Wachstum in allen \
37 Kernbereichen. Die folgenden Abschnitte fassen die wichtigsten \
38 Kennzahlen und Entwicklungen zusammen.",
39 ));
40 doc.add(Spacer::new(12.0));
41
42 doc.add(Text::new("2. Wichtigste Ereignisse").heading2());
43 doc.add(
44 List::new()
45 .bullet(Text::new("Markteinführung des neuen Produkts im zweiten Quartal"))
46 .bullet(Text::new("Erweiterung des Teams um 12 neue Mitarbeitende"))
47 .bullet(Text::new("Eröffnung eines zweiten Standorts")),
48 );
49 doc.add(Spacer::new(12.0));
50
51 doc.add(Text::new("3. Zeitplan").heading2());
52 doc.add(
53 List::new()
54 .numbered(Text::new("Kickoff und Planung (Januar \u{2013} Februar)"))
55 .numbered(Text::new("Umsetzung Phase 1 (M\u{e4}rz \u{2013} Juni)"))
56 .numbered(Text::new("Umsetzung Phase 2 (Juli \u{2013} Oktober)"))
57 .numbered(Text::new("Abschluss und Auswertung (November \u{2013} Dezember)")),
58 );
59 doc.add(Spacer::new(12.0));
60
61 doc.add(Text::new("3.1 Details").heading3());
62 doc.add(Text::new(
63 "Weitere Details zu den einzelnen Phasen finden sich im Anhang. \
64 Diese Überschrift bleibt dank keep_with_next garantiert mit \
65 diesem Absatz auf derselben Seite zusammen.",
66 ));
67
68 let bytes = doc.render().expect("render should succeed");
69 std::fs::write("report.pdf", &bytes).expect("write report.pdf");
70 println!("wrote report.pdf ({} bytes)", bytes.len());
71}More examples
examples/invoice.rs (line 63)
20fn main() {
21 let mut items = vec![
22 LineItem {
23 description: "Beratungsleistung Projekt Alpha".to_string(),
24 qty: 8,
25 unit_price_cents: 12_000,
26 },
27 LineItem {
28 description: "Lizenz Software-Paket (jährlich)".to_string(),
29 qty: 1,
30 unit_price_cents: 49_900,
31 },
32 LineItem {
33 description: "Individuelle Anpassung / Customizing".to_string(),
34 qty: 3,
35 unit_price_cents: 15_000,
36 },
37 ];
38 // A few filler positions so the table is guaranteed to span more than
39 // one page, demonstrating the header-repeat-on-split behavior.
40 for i in 1..=25 {
41 items.push(LineItem {
42 description: format!("Zusatzposition {i:02}"),
43 qty: 1,
44 unit_price_cents: 990,
45 });
46 }
47
48 let net_total: i64 = items.iter().map(|i| i.qty as i64 * i.unit_price_cents).sum();
49 let vat_rate = 19;
50 let vat_total = net_total * vat_rate / 100;
51 let gross_total = net_total + vat_total;
52
53 let top_margin = 15.0 * MM;
54 let mut doc = Document::new(PageFormat::A4)
55 .margin(Margin::symmetric(20.0 * MM, top_margin))
56 .footer(Footer::new(30.0, |ctx| {
57 Column::new()
58 .gap(2.0)
59 .child(Line::new())
60 .child(
61 Row::new()
62 .gap(20.0)
63 .child(Text::new("Musterbank · IBAN DE12 3456 7890 1234 5678 90 · BIC MUSTDEFF").size(8.0))
64 .child(Text::new("USt-IdNr. DE123456789").size(8.0).flex(1.0)),
65 )
66 .child(Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages)).size(8.0))
67 .into()
68 }));
69
70 // --- DIN 5008 Form A window-envelope address block ----------------
71 // Window starts ~45mm from the top, ~20mm from the left
72 // (`plan/02-elementcatalog-and-features.md`); ~85x40mm matches a
73 // typical C6/5-long window envelope opening. Position/size are a
74 // documented convention for this recipe, not parsed from any norm
75 // document — a caller with different envelope stock adjusts these.
76 doc.add(Spacer::new(45.0 * MM - top_margin));
77 doc.add(
78 Column::new()
79 .gap(2.0)
80 .width(85.0 * MM)
81 .height(40.0 * MM)
82 .child(Text::new("Muster GmbH · Musterstraße 1 · 12345 Musterstadt").size(7.0))
83 .child(Spacer::new(8.0))
84 .child(Text::new("Empfänger GmbH"))
85 .child(Text::new("Frau Erika Mustermann"))
86 .child(Text::new("Beispielweg 42"))
87 .child(Text::new("54321 Beispielstadt")),
88 );
89 doc.add(Spacer::new(10.0 * MM));
90
91 doc.add(Text::new("Rechnung").heading1());
92 doc.add(Text::new(
93 "Rechnungsnummer: RE-2026-0142 Rechnungsdatum: 20.08.2026 Leistungsdatum: 20.08.2026",
94 ));
95 doc.add(Spacer::new(10.0));
96
97 doc.add(
98 Table::new()
99 .columns([
100 TableColumn::flex(1.0),
101 TableColumn::fixed(50.0).align(Align::End),
102 TableColumn::fixed(65.0).align(Align::End),
103 TableColumn::fixed(70.0).align(Align::End),
104 ])
105 .header(["Beschreibung", "Menge", "Einzelpreis", "Gesamt"])
106 .striped(Color::rgb(0xF5, 0xF5, 0xF5))
107 .rows(items.iter().map(|item| {
108 let total = item.qty as i64 * item.unit_price_cents;
109 vec![
110 Element::from(item.description.as_str()),
111 Element::from(item.qty.to_string()),
112 Element::from(format_currency_de(item.unit_price_cents)),
113 Element::from(format_currency_de(total)),
114 ]
115 })),
116 );
117
118 doc.add(Spacer::new(14.0));
119
120 // --- summary block (Netto/USt/Brutto), right-aligned --------------
121 // Recipe (`plan/02-elementcatalog-and-features.md`): an outer, full-
122 // width auto Column with `.align(Align::End)` positions the fixed-
123 // width (200pt) inner summary Column at the right edge; within it,
124 // each label gets `.flex(1.0)` to push its value to that block's own
125 // right edge. No special "summary block" element needed.
126 doc.add(
127 Column::new()
128 .align(Align::End)
129 .child(Column::new().gap(2.0).width(200.0).children(vec![
130 Element::from(
131 Row::new()
132 .child(Text::new("Nettosumme").flex(1.0))
133 .child(Text::new(format_currency_de(net_total))),
134 ),
135 Element::from(
136 Row::new()
137 .child(Text::new(format!("zzgl. {vat_rate}% USt.")).flex(1.0))
138 .child(Text::new(format_currency_de(vat_total))),
139 ),
140 Element::from(Line::new()),
141 Element::from(
142 Row::new()
143 .child(Text::new("Gesamtbetrag").bold().flex(1.0))
144 .child(Text::new(format_currency_de(gross_total)).bold()),
145 ),
146 ])),
147 );
148
149 let bytes = doc.render().expect("render should succeed");
150 std::fs::write("invoice.pdf", &bytes).expect("write invoice.pdf");
151 println!("wrote invoice.pdf ({} bytes)", bytes.len());
152}Sourcepub fn size(self, size: f32) -> Text
pub fn size(self, size: f32) -> Text
Examples found in repository?
examples/report.rs (line 14)
10fn main() {
11 let mut doc = Document::new(PageFormat::A4)
12 .margin(Margin::symmetric(56.0, 56.0))
13 .header(Header::new(20.0, |_ctx| {
14 Text::new("Jahresbericht 2026 \u{2014} Muster GmbH").size(9.0).into()
15 }))
16 .header_visible_from(2)
17 .footer(Footer::new(20.0, |ctx| {
18 Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages))
19 .size(9.0)
20 .align(Align::Center)
21 .into()
22 }))
23 .watermark(Watermark::new("ENTWURF"));
24
25 // --- cover page -----------------------------------------------------
26 doc.add(Spacer::new(220.0));
27 doc.add(Text::new("Jahresbericht 2026").heading1().align(Align::Center));
28 doc.add(Spacer::new(8.0));
29 doc.add(Text::new("Muster GmbH").align(Align::Center));
30 doc.add(Text::new("vorgelegt am 20. August 2026").align(Align::Center));
31 doc.add(Element::PageBreak);
32
33 // --- content ---------------------------------------------------------
34 doc.add(Text::new("1. Zusammenfassung").heading1());
35 doc.add(Text::new(
36 "Das Geschäftsjahr 2026 war geprägt von stabilem Wachstum in allen \
37 Kernbereichen. Die folgenden Abschnitte fassen die wichtigsten \
38 Kennzahlen und Entwicklungen zusammen.",
39 ));
40 doc.add(Spacer::new(12.0));
41
42 doc.add(Text::new("2. Wichtigste Ereignisse").heading2());
43 doc.add(
44 List::new()
45 .bullet(Text::new("Markteinführung des neuen Produkts im zweiten Quartal"))
46 .bullet(Text::new("Erweiterung des Teams um 12 neue Mitarbeitende"))
47 .bullet(Text::new("Eröffnung eines zweiten Standorts")),
48 );
49 doc.add(Spacer::new(12.0));
50
51 doc.add(Text::new("3. Zeitplan").heading2());
52 doc.add(
53 List::new()
54 .numbered(Text::new("Kickoff und Planung (Januar \u{2013} Februar)"))
55 .numbered(Text::new("Umsetzung Phase 1 (M\u{e4}rz \u{2013} Juni)"))
56 .numbered(Text::new("Umsetzung Phase 2 (Juli \u{2013} Oktober)"))
57 .numbered(Text::new("Abschluss und Auswertung (November \u{2013} Dezember)")),
58 );
59 doc.add(Spacer::new(12.0));
60
61 doc.add(Text::new("3.1 Details").heading3());
62 doc.add(Text::new(
63 "Weitere Details zu den einzelnen Phasen finden sich im Anhang. \
64 Diese Überschrift bleibt dank keep_with_next garantiert mit \
65 diesem Absatz auf derselben Seite zusammen.",
66 ));
67
68 let bytes = doc.render().expect("render should succeed");
69 std::fs::write("report.pdf", &bytes).expect("write report.pdf");
70 println!("wrote report.pdf ({} bytes)", bytes.len());
71}More examples
examples/invoice.rs (line 63)
20fn main() {
21 let mut items = vec![
22 LineItem {
23 description: "Beratungsleistung Projekt Alpha".to_string(),
24 qty: 8,
25 unit_price_cents: 12_000,
26 },
27 LineItem {
28 description: "Lizenz Software-Paket (jährlich)".to_string(),
29 qty: 1,
30 unit_price_cents: 49_900,
31 },
32 LineItem {
33 description: "Individuelle Anpassung / Customizing".to_string(),
34 qty: 3,
35 unit_price_cents: 15_000,
36 },
37 ];
38 // A few filler positions so the table is guaranteed to span more than
39 // one page, demonstrating the header-repeat-on-split behavior.
40 for i in 1..=25 {
41 items.push(LineItem {
42 description: format!("Zusatzposition {i:02}"),
43 qty: 1,
44 unit_price_cents: 990,
45 });
46 }
47
48 let net_total: i64 = items.iter().map(|i| i.qty as i64 * i.unit_price_cents).sum();
49 let vat_rate = 19;
50 let vat_total = net_total * vat_rate / 100;
51 let gross_total = net_total + vat_total;
52
53 let top_margin = 15.0 * MM;
54 let mut doc = Document::new(PageFormat::A4)
55 .margin(Margin::symmetric(20.0 * MM, top_margin))
56 .footer(Footer::new(30.0, |ctx| {
57 Column::new()
58 .gap(2.0)
59 .child(Line::new())
60 .child(
61 Row::new()
62 .gap(20.0)
63 .child(Text::new("Musterbank · IBAN DE12 3456 7890 1234 5678 90 · BIC MUSTDEFF").size(8.0))
64 .child(Text::new("USt-IdNr. DE123456789").size(8.0).flex(1.0)),
65 )
66 .child(Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages)).size(8.0))
67 .into()
68 }));
69
70 // --- DIN 5008 Form A window-envelope address block ----------------
71 // Window starts ~45mm from the top, ~20mm from the left
72 // (`plan/02-elementcatalog-and-features.md`); ~85x40mm matches a
73 // typical C6/5-long window envelope opening. Position/size are a
74 // documented convention for this recipe, not parsed from any norm
75 // document — a caller with different envelope stock adjusts these.
76 doc.add(Spacer::new(45.0 * MM - top_margin));
77 doc.add(
78 Column::new()
79 .gap(2.0)
80 .width(85.0 * MM)
81 .height(40.0 * MM)
82 .child(Text::new("Muster GmbH · Musterstraße 1 · 12345 Musterstadt").size(7.0))
83 .child(Spacer::new(8.0))
84 .child(Text::new("Empfänger GmbH"))
85 .child(Text::new("Frau Erika Mustermann"))
86 .child(Text::new("Beispielweg 42"))
87 .child(Text::new("54321 Beispielstadt")),
88 );
89 doc.add(Spacer::new(10.0 * MM));
90
91 doc.add(Text::new("Rechnung").heading1());
92 doc.add(Text::new(
93 "Rechnungsnummer: RE-2026-0142 Rechnungsdatum: 20.08.2026 Leistungsdatum: 20.08.2026",
94 ));
95 doc.add(Spacer::new(10.0));
96
97 doc.add(
98 Table::new()
99 .columns([
100 TableColumn::flex(1.0),
101 TableColumn::fixed(50.0).align(Align::End),
102 TableColumn::fixed(65.0).align(Align::End),
103 TableColumn::fixed(70.0).align(Align::End),
104 ])
105 .header(["Beschreibung", "Menge", "Einzelpreis", "Gesamt"])
106 .striped(Color::rgb(0xF5, 0xF5, 0xF5))
107 .rows(items.iter().map(|item| {
108 let total = item.qty as i64 * item.unit_price_cents;
109 vec![
110 Element::from(item.description.as_str()),
111 Element::from(item.qty.to_string()),
112 Element::from(format_currency_de(item.unit_price_cents)),
113 Element::from(format_currency_de(total)),
114 ]
115 })),
116 );
117
118 doc.add(Spacer::new(14.0));
119
120 // --- summary block (Netto/USt/Brutto), right-aligned --------------
121 // Recipe (`plan/02-elementcatalog-and-features.md`): an outer, full-
122 // width auto Column with `.align(Align::End)` positions the fixed-
123 // width (200pt) inner summary Column at the right edge; within it,
124 // each label gets `.flex(1.0)` to push its value to that block's own
125 // right edge. No special "summary block" element needed.
126 doc.add(
127 Column::new()
128 .align(Align::End)
129 .child(Column::new().gap(2.0).width(200.0).children(vec![
130 Element::from(
131 Row::new()
132 .child(Text::new("Nettosumme").flex(1.0))
133 .child(Text::new(format_currency_de(net_total))),
134 ),
135 Element::from(
136 Row::new()
137 .child(Text::new(format!("zzgl. {vat_rate}% USt.")).flex(1.0))
138 .child(Text::new(format_currency_de(vat_total))),
139 ),
140 Element::from(Line::new()),
141 Element::from(
142 Row::new()
143 .child(Text::new("Gesamtbetrag").bold().flex(1.0))
144 .child(Text::new(format_currency_de(gross_total)).bold()),
145 ),
146 ])),
147 );
148
149 let bytes = doc.render().expect("render should succeed");
150 std::fs::write("invoice.pdf", &bytes).expect("write invoice.pdf");
151 println!("wrote invoice.pdf ({} bytes)", bytes.len());
152}Sourcepub fn bold(self) -> Text
pub fn bold(self) -> Text
Examples found in repository?
examples/invoice.rs (line 143)
20fn main() {
21 let mut items = vec![
22 LineItem {
23 description: "Beratungsleistung Projekt Alpha".to_string(),
24 qty: 8,
25 unit_price_cents: 12_000,
26 },
27 LineItem {
28 description: "Lizenz Software-Paket (jährlich)".to_string(),
29 qty: 1,
30 unit_price_cents: 49_900,
31 },
32 LineItem {
33 description: "Individuelle Anpassung / Customizing".to_string(),
34 qty: 3,
35 unit_price_cents: 15_000,
36 },
37 ];
38 // A few filler positions so the table is guaranteed to span more than
39 // one page, demonstrating the header-repeat-on-split behavior.
40 for i in 1..=25 {
41 items.push(LineItem {
42 description: format!("Zusatzposition {i:02}"),
43 qty: 1,
44 unit_price_cents: 990,
45 });
46 }
47
48 let net_total: i64 = items.iter().map(|i| i.qty as i64 * i.unit_price_cents).sum();
49 let vat_rate = 19;
50 let vat_total = net_total * vat_rate / 100;
51 let gross_total = net_total + vat_total;
52
53 let top_margin = 15.0 * MM;
54 let mut doc = Document::new(PageFormat::A4)
55 .margin(Margin::symmetric(20.0 * MM, top_margin))
56 .footer(Footer::new(30.0, |ctx| {
57 Column::new()
58 .gap(2.0)
59 .child(Line::new())
60 .child(
61 Row::new()
62 .gap(20.0)
63 .child(Text::new("Musterbank · IBAN DE12 3456 7890 1234 5678 90 · BIC MUSTDEFF").size(8.0))
64 .child(Text::new("USt-IdNr. DE123456789").size(8.0).flex(1.0)),
65 )
66 .child(Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages)).size(8.0))
67 .into()
68 }));
69
70 // --- DIN 5008 Form A window-envelope address block ----------------
71 // Window starts ~45mm from the top, ~20mm from the left
72 // (`plan/02-elementcatalog-and-features.md`); ~85x40mm matches a
73 // typical C6/5-long window envelope opening. Position/size are a
74 // documented convention for this recipe, not parsed from any norm
75 // document — a caller with different envelope stock adjusts these.
76 doc.add(Spacer::new(45.0 * MM - top_margin));
77 doc.add(
78 Column::new()
79 .gap(2.0)
80 .width(85.0 * MM)
81 .height(40.0 * MM)
82 .child(Text::new("Muster GmbH · Musterstraße 1 · 12345 Musterstadt").size(7.0))
83 .child(Spacer::new(8.0))
84 .child(Text::new("Empfänger GmbH"))
85 .child(Text::new("Frau Erika Mustermann"))
86 .child(Text::new("Beispielweg 42"))
87 .child(Text::new("54321 Beispielstadt")),
88 );
89 doc.add(Spacer::new(10.0 * MM));
90
91 doc.add(Text::new("Rechnung").heading1());
92 doc.add(Text::new(
93 "Rechnungsnummer: RE-2026-0142 Rechnungsdatum: 20.08.2026 Leistungsdatum: 20.08.2026",
94 ));
95 doc.add(Spacer::new(10.0));
96
97 doc.add(
98 Table::new()
99 .columns([
100 TableColumn::flex(1.0),
101 TableColumn::fixed(50.0).align(Align::End),
102 TableColumn::fixed(65.0).align(Align::End),
103 TableColumn::fixed(70.0).align(Align::End),
104 ])
105 .header(["Beschreibung", "Menge", "Einzelpreis", "Gesamt"])
106 .striped(Color::rgb(0xF5, 0xF5, 0xF5))
107 .rows(items.iter().map(|item| {
108 let total = item.qty as i64 * item.unit_price_cents;
109 vec![
110 Element::from(item.description.as_str()),
111 Element::from(item.qty.to_string()),
112 Element::from(format_currency_de(item.unit_price_cents)),
113 Element::from(format_currency_de(total)),
114 ]
115 })),
116 );
117
118 doc.add(Spacer::new(14.0));
119
120 // --- summary block (Netto/USt/Brutto), right-aligned --------------
121 // Recipe (`plan/02-elementcatalog-and-features.md`): an outer, full-
122 // width auto Column with `.align(Align::End)` positions the fixed-
123 // width (200pt) inner summary Column at the right edge; within it,
124 // each label gets `.flex(1.0)` to push its value to that block's own
125 // right edge. No special "summary block" element needed.
126 doc.add(
127 Column::new()
128 .align(Align::End)
129 .child(Column::new().gap(2.0).width(200.0).children(vec![
130 Element::from(
131 Row::new()
132 .child(Text::new("Nettosumme").flex(1.0))
133 .child(Text::new(format_currency_de(net_total))),
134 ),
135 Element::from(
136 Row::new()
137 .child(Text::new(format!("zzgl. {vat_rate}% USt.")).flex(1.0))
138 .child(Text::new(format_currency_de(vat_total))),
139 ),
140 Element::from(Line::new()),
141 Element::from(
142 Row::new()
143 .child(Text::new("Gesamtbetrag").bold().flex(1.0))
144 .child(Text::new(format_currency_de(gross_total)).bold()),
145 ),
146 ])),
147 );
148
149 let bytes = doc.render().expect("render should succeed");
150 std::fs::write("invoice.pdf", &bytes).expect("write invoice.pdf");
151 println!("wrote invoice.pdf ({} bytes)", bytes.len());
152}pub fn font(self, font: FontKey) -> Text
pub fn color(self, color: Color) -> Text
Sourcepub fn align(self, align: Align) -> Text
pub fn align(self, align: Align) -> Text
Examples found in repository?
examples/report.rs (line 20)
10fn main() {
11 let mut doc = Document::new(PageFormat::A4)
12 .margin(Margin::symmetric(56.0, 56.0))
13 .header(Header::new(20.0, |_ctx| {
14 Text::new("Jahresbericht 2026 \u{2014} Muster GmbH").size(9.0).into()
15 }))
16 .header_visible_from(2)
17 .footer(Footer::new(20.0, |ctx| {
18 Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages))
19 .size(9.0)
20 .align(Align::Center)
21 .into()
22 }))
23 .watermark(Watermark::new("ENTWURF"));
24
25 // --- cover page -----------------------------------------------------
26 doc.add(Spacer::new(220.0));
27 doc.add(Text::new("Jahresbericht 2026").heading1().align(Align::Center));
28 doc.add(Spacer::new(8.0));
29 doc.add(Text::new("Muster GmbH").align(Align::Center));
30 doc.add(Text::new("vorgelegt am 20. August 2026").align(Align::Center));
31 doc.add(Element::PageBreak);
32
33 // --- content ---------------------------------------------------------
34 doc.add(Text::new("1. Zusammenfassung").heading1());
35 doc.add(Text::new(
36 "Das Geschäftsjahr 2026 war geprägt von stabilem Wachstum in allen \
37 Kernbereichen. Die folgenden Abschnitte fassen die wichtigsten \
38 Kennzahlen und Entwicklungen zusammen.",
39 ));
40 doc.add(Spacer::new(12.0));
41
42 doc.add(Text::new("2. Wichtigste Ereignisse").heading2());
43 doc.add(
44 List::new()
45 .bullet(Text::new("Markteinführung des neuen Produkts im zweiten Quartal"))
46 .bullet(Text::new("Erweiterung des Teams um 12 neue Mitarbeitende"))
47 .bullet(Text::new("Eröffnung eines zweiten Standorts")),
48 );
49 doc.add(Spacer::new(12.0));
50
51 doc.add(Text::new("3. Zeitplan").heading2());
52 doc.add(
53 List::new()
54 .numbered(Text::new("Kickoff und Planung (Januar \u{2013} Februar)"))
55 .numbered(Text::new("Umsetzung Phase 1 (M\u{e4}rz \u{2013} Juni)"))
56 .numbered(Text::new("Umsetzung Phase 2 (Juli \u{2013} Oktober)"))
57 .numbered(Text::new("Abschluss und Auswertung (November \u{2013} Dezember)")),
58 );
59 doc.add(Spacer::new(12.0));
60
61 doc.add(Text::new("3.1 Details").heading3());
62 doc.add(Text::new(
63 "Weitere Details zu den einzelnen Phasen finden sich im Anhang. \
64 Diese Überschrift bleibt dank keep_with_next garantiert mit \
65 diesem Absatz auf derselben Seite zusammen.",
66 ));
67
68 let bytes = doc.render().expect("render should succeed");
69 std::fs::write("report.pdf", &bytes).expect("write report.pdf");
70 println!("wrote report.pdf ({} bytes)", bytes.len());
71}pub fn line_height(self, line_height: f32) -> Text
Sourcepub fn heading1(self) -> Text
pub fn heading1(self) -> Text
Heading presets (Phase 6, plan/02-elementcatalog-and-features.md):
thin wrappers over .size()/.bold(), additionally setting
keep_with_next so a heading never ends up alone at the bottom of
a page without its following content
(plan/05-overflow-and-robustness.md Grundprinzip 9).
Examples found in repository?
examples/report.rs (line 27)
10fn main() {
11 let mut doc = Document::new(PageFormat::A4)
12 .margin(Margin::symmetric(56.0, 56.0))
13 .header(Header::new(20.0, |_ctx| {
14 Text::new("Jahresbericht 2026 \u{2014} Muster GmbH").size(9.0).into()
15 }))
16 .header_visible_from(2)
17 .footer(Footer::new(20.0, |ctx| {
18 Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages))
19 .size(9.0)
20 .align(Align::Center)
21 .into()
22 }))
23 .watermark(Watermark::new("ENTWURF"));
24
25 // --- cover page -----------------------------------------------------
26 doc.add(Spacer::new(220.0));
27 doc.add(Text::new("Jahresbericht 2026").heading1().align(Align::Center));
28 doc.add(Spacer::new(8.0));
29 doc.add(Text::new("Muster GmbH").align(Align::Center));
30 doc.add(Text::new("vorgelegt am 20. August 2026").align(Align::Center));
31 doc.add(Element::PageBreak);
32
33 // --- content ---------------------------------------------------------
34 doc.add(Text::new("1. Zusammenfassung").heading1());
35 doc.add(Text::new(
36 "Das Geschäftsjahr 2026 war geprägt von stabilem Wachstum in allen \
37 Kernbereichen. Die folgenden Abschnitte fassen die wichtigsten \
38 Kennzahlen und Entwicklungen zusammen.",
39 ));
40 doc.add(Spacer::new(12.0));
41
42 doc.add(Text::new("2. Wichtigste Ereignisse").heading2());
43 doc.add(
44 List::new()
45 .bullet(Text::new("Markteinführung des neuen Produkts im zweiten Quartal"))
46 .bullet(Text::new("Erweiterung des Teams um 12 neue Mitarbeitende"))
47 .bullet(Text::new("Eröffnung eines zweiten Standorts")),
48 );
49 doc.add(Spacer::new(12.0));
50
51 doc.add(Text::new("3. Zeitplan").heading2());
52 doc.add(
53 List::new()
54 .numbered(Text::new("Kickoff und Planung (Januar \u{2013} Februar)"))
55 .numbered(Text::new("Umsetzung Phase 1 (M\u{e4}rz \u{2013} Juni)"))
56 .numbered(Text::new("Umsetzung Phase 2 (Juli \u{2013} Oktober)"))
57 .numbered(Text::new("Abschluss und Auswertung (November \u{2013} Dezember)")),
58 );
59 doc.add(Spacer::new(12.0));
60
61 doc.add(Text::new("3.1 Details").heading3());
62 doc.add(Text::new(
63 "Weitere Details zu den einzelnen Phasen finden sich im Anhang. \
64 Diese Überschrift bleibt dank keep_with_next garantiert mit \
65 diesem Absatz auf derselben Seite zusammen.",
66 ));
67
68 let bytes = doc.render().expect("render should succeed");
69 std::fs::write("report.pdf", &bytes).expect("write report.pdf");
70 println!("wrote report.pdf ({} bytes)", bytes.len());
71}More examples
examples/invoice.rs (line 91)
20fn main() {
21 let mut items = vec![
22 LineItem {
23 description: "Beratungsleistung Projekt Alpha".to_string(),
24 qty: 8,
25 unit_price_cents: 12_000,
26 },
27 LineItem {
28 description: "Lizenz Software-Paket (jährlich)".to_string(),
29 qty: 1,
30 unit_price_cents: 49_900,
31 },
32 LineItem {
33 description: "Individuelle Anpassung / Customizing".to_string(),
34 qty: 3,
35 unit_price_cents: 15_000,
36 },
37 ];
38 // A few filler positions so the table is guaranteed to span more than
39 // one page, demonstrating the header-repeat-on-split behavior.
40 for i in 1..=25 {
41 items.push(LineItem {
42 description: format!("Zusatzposition {i:02}"),
43 qty: 1,
44 unit_price_cents: 990,
45 });
46 }
47
48 let net_total: i64 = items.iter().map(|i| i.qty as i64 * i.unit_price_cents).sum();
49 let vat_rate = 19;
50 let vat_total = net_total * vat_rate / 100;
51 let gross_total = net_total + vat_total;
52
53 let top_margin = 15.0 * MM;
54 let mut doc = Document::new(PageFormat::A4)
55 .margin(Margin::symmetric(20.0 * MM, top_margin))
56 .footer(Footer::new(30.0, |ctx| {
57 Column::new()
58 .gap(2.0)
59 .child(Line::new())
60 .child(
61 Row::new()
62 .gap(20.0)
63 .child(Text::new("Musterbank · IBAN DE12 3456 7890 1234 5678 90 · BIC MUSTDEFF").size(8.0))
64 .child(Text::new("USt-IdNr. DE123456789").size(8.0).flex(1.0)),
65 )
66 .child(Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages)).size(8.0))
67 .into()
68 }));
69
70 // --- DIN 5008 Form A window-envelope address block ----------------
71 // Window starts ~45mm from the top, ~20mm from the left
72 // (`plan/02-elementcatalog-and-features.md`); ~85x40mm matches a
73 // typical C6/5-long window envelope opening. Position/size are a
74 // documented convention for this recipe, not parsed from any norm
75 // document — a caller with different envelope stock adjusts these.
76 doc.add(Spacer::new(45.0 * MM - top_margin));
77 doc.add(
78 Column::new()
79 .gap(2.0)
80 .width(85.0 * MM)
81 .height(40.0 * MM)
82 .child(Text::new("Muster GmbH · Musterstraße 1 · 12345 Musterstadt").size(7.0))
83 .child(Spacer::new(8.0))
84 .child(Text::new("Empfänger GmbH"))
85 .child(Text::new("Frau Erika Mustermann"))
86 .child(Text::new("Beispielweg 42"))
87 .child(Text::new("54321 Beispielstadt")),
88 );
89 doc.add(Spacer::new(10.0 * MM));
90
91 doc.add(Text::new("Rechnung").heading1());
92 doc.add(Text::new(
93 "Rechnungsnummer: RE-2026-0142 Rechnungsdatum: 20.08.2026 Leistungsdatum: 20.08.2026",
94 ));
95 doc.add(Spacer::new(10.0));
96
97 doc.add(
98 Table::new()
99 .columns([
100 TableColumn::flex(1.0),
101 TableColumn::fixed(50.0).align(Align::End),
102 TableColumn::fixed(65.0).align(Align::End),
103 TableColumn::fixed(70.0).align(Align::End),
104 ])
105 .header(["Beschreibung", "Menge", "Einzelpreis", "Gesamt"])
106 .striped(Color::rgb(0xF5, 0xF5, 0xF5))
107 .rows(items.iter().map(|item| {
108 let total = item.qty as i64 * item.unit_price_cents;
109 vec![
110 Element::from(item.description.as_str()),
111 Element::from(item.qty.to_string()),
112 Element::from(format_currency_de(item.unit_price_cents)),
113 Element::from(format_currency_de(total)),
114 ]
115 })),
116 );
117
118 doc.add(Spacer::new(14.0));
119
120 // --- summary block (Netto/USt/Brutto), right-aligned --------------
121 // Recipe (`plan/02-elementcatalog-and-features.md`): an outer, full-
122 // width auto Column with `.align(Align::End)` positions the fixed-
123 // width (200pt) inner summary Column at the right edge; within it,
124 // each label gets `.flex(1.0)` to push its value to that block's own
125 // right edge. No special "summary block" element needed.
126 doc.add(
127 Column::new()
128 .align(Align::End)
129 .child(Column::new().gap(2.0).width(200.0).children(vec![
130 Element::from(
131 Row::new()
132 .child(Text::new("Nettosumme").flex(1.0))
133 .child(Text::new(format_currency_de(net_total))),
134 ),
135 Element::from(
136 Row::new()
137 .child(Text::new(format!("zzgl. {vat_rate}% USt.")).flex(1.0))
138 .child(Text::new(format_currency_de(vat_total))),
139 ),
140 Element::from(Line::new()),
141 Element::from(
142 Row::new()
143 .child(Text::new("Gesamtbetrag").bold().flex(1.0))
144 .child(Text::new(format_currency_de(gross_total)).bold()),
145 ),
146 ])),
147 );
148
149 let bytes = doc.render().expect("render should succeed");
150 std::fs::write("invoice.pdf", &bytes).expect("write invoice.pdf");
151 println!("wrote invoice.pdf ({} bytes)", bytes.len());
152}Sourcepub fn heading2(self) -> Text
pub fn heading2(self) -> Text
Examples found in repository?
examples/report.rs (line 42)
10fn main() {
11 let mut doc = Document::new(PageFormat::A4)
12 .margin(Margin::symmetric(56.0, 56.0))
13 .header(Header::new(20.0, |_ctx| {
14 Text::new("Jahresbericht 2026 \u{2014} Muster GmbH").size(9.0).into()
15 }))
16 .header_visible_from(2)
17 .footer(Footer::new(20.0, |ctx| {
18 Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages))
19 .size(9.0)
20 .align(Align::Center)
21 .into()
22 }))
23 .watermark(Watermark::new("ENTWURF"));
24
25 // --- cover page -----------------------------------------------------
26 doc.add(Spacer::new(220.0));
27 doc.add(Text::new("Jahresbericht 2026").heading1().align(Align::Center));
28 doc.add(Spacer::new(8.0));
29 doc.add(Text::new("Muster GmbH").align(Align::Center));
30 doc.add(Text::new("vorgelegt am 20. August 2026").align(Align::Center));
31 doc.add(Element::PageBreak);
32
33 // --- content ---------------------------------------------------------
34 doc.add(Text::new("1. Zusammenfassung").heading1());
35 doc.add(Text::new(
36 "Das Geschäftsjahr 2026 war geprägt von stabilem Wachstum in allen \
37 Kernbereichen. Die folgenden Abschnitte fassen die wichtigsten \
38 Kennzahlen und Entwicklungen zusammen.",
39 ));
40 doc.add(Spacer::new(12.0));
41
42 doc.add(Text::new("2. Wichtigste Ereignisse").heading2());
43 doc.add(
44 List::new()
45 .bullet(Text::new("Markteinführung des neuen Produkts im zweiten Quartal"))
46 .bullet(Text::new("Erweiterung des Teams um 12 neue Mitarbeitende"))
47 .bullet(Text::new("Eröffnung eines zweiten Standorts")),
48 );
49 doc.add(Spacer::new(12.0));
50
51 doc.add(Text::new("3. Zeitplan").heading2());
52 doc.add(
53 List::new()
54 .numbered(Text::new("Kickoff und Planung (Januar \u{2013} Februar)"))
55 .numbered(Text::new("Umsetzung Phase 1 (M\u{e4}rz \u{2013} Juni)"))
56 .numbered(Text::new("Umsetzung Phase 2 (Juli \u{2013} Oktober)"))
57 .numbered(Text::new("Abschluss und Auswertung (November \u{2013} Dezember)")),
58 );
59 doc.add(Spacer::new(12.0));
60
61 doc.add(Text::new("3.1 Details").heading3());
62 doc.add(Text::new(
63 "Weitere Details zu den einzelnen Phasen finden sich im Anhang. \
64 Diese Überschrift bleibt dank keep_with_next garantiert mit \
65 diesem Absatz auf derselben Seite zusammen.",
66 ));
67
68 let bytes = doc.render().expect("render should succeed");
69 std::fs::write("report.pdf", &bytes).expect("write report.pdf");
70 println!("wrote report.pdf ({} bytes)", bytes.len());
71}Sourcepub fn heading3(self) -> Text
pub fn heading3(self) -> Text
Examples found in repository?
examples/report.rs (line 61)
10fn main() {
11 let mut doc = Document::new(PageFormat::A4)
12 .margin(Margin::symmetric(56.0, 56.0))
13 .header(Header::new(20.0, |_ctx| {
14 Text::new("Jahresbericht 2026 \u{2014} Muster GmbH").size(9.0).into()
15 }))
16 .header_visible_from(2)
17 .footer(Footer::new(20.0, |ctx| {
18 Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages))
19 .size(9.0)
20 .align(Align::Center)
21 .into()
22 }))
23 .watermark(Watermark::new("ENTWURF"));
24
25 // --- cover page -----------------------------------------------------
26 doc.add(Spacer::new(220.0));
27 doc.add(Text::new("Jahresbericht 2026").heading1().align(Align::Center));
28 doc.add(Spacer::new(8.0));
29 doc.add(Text::new("Muster GmbH").align(Align::Center));
30 doc.add(Text::new("vorgelegt am 20. August 2026").align(Align::Center));
31 doc.add(Element::PageBreak);
32
33 // --- content ---------------------------------------------------------
34 doc.add(Text::new("1. Zusammenfassung").heading1());
35 doc.add(Text::new(
36 "Das Geschäftsjahr 2026 war geprägt von stabilem Wachstum in allen \
37 Kernbereichen. Die folgenden Abschnitte fassen die wichtigsten \
38 Kennzahlen und Entwicklungen zusammen.",
39 ));
40 doc.add(Spacer::new(12.0));
41
42 doc.add(Text::new("2. Wichtigste Ereignisse").heading2());
43 doc.add(
44 List::new()
45 .bullet(Text::new("Markteinführung des neuen Produkts im zweiten Quartal"))
46 .bullet(Text::new("Erweiterung des Teams um 12 neue Mitarbeitende"))
47 .bullet(Text::new("Eröffnung eines zweiten Standorts")),
48 );
49 doc.add(Spacer::new(12.0));
50
51 doc.add(Text::new("3. Zeitplan").heading2());
52 doc.add(
53 List::new()
54 .numbered(Text::new("Kickoff und Planung (Januar \u{2013} Februar)"))
55 .numbered(Text::new("Umsetzung Phase 1 (M\u{e4}rz \u{2013} Juni)"))
56 .numbered(Text::new("Umsetzung Phase 2 (Juli \u{2013} Oktober)"))
57 .numbered(Text::new("Abschluss und Auswertung (November \u{2013} Dezember)")),
58 );
59 doc.add(Spacer::new(12.0));
60
61 doc.add(Text::new("3.1 Details").heading3());
62 doc.add(Text::new(
63 "Weitere Details zu den einzelnen Phasen finden sich im Anhang. \
64 Diese Überschrift bleibt dank keep_with_next garantiert mit \
65 diesem Absatz auf derselben Seite zusammen.",
66 ));
67
68 let bytes = doc.render().expect("render should succeed");
69 std::fs::write("report.pdf", &bytes).expect("write report.pdf");
70 println!("wrote report.pdf ({} bytes)", bytes.len());
71}pub fn width(self, width: f32) -> Text
pub fn height(self, height: f32) -> Text
Sourcepub fn flex(self, factor: f32) -> Text
pub fn flex(self, factor: f32) -> Text
Examples found in repository?
examples/invoice.rs (line 64)
20fn main() {
21 let mut items = vec![
22 LineItem {
23 description: "Beratungsleistung Projekt Alpha".to_string(),
24 qty: 8,
25 unit_price_cents: 12_000,
26 },
27 LineItem {
28 description: "Lizenz Software-Paket (jährlich)".to_string(),
29 qty: 1,
30 unit_price_cents: 49_900,
31 },
32 LineItem {
33 description: "Individuelle Anpassung / Customizing".to_string(),
34 qty: 3,
35 unit_price_cents: 15_000,
36 },
37 ];
38 // A few filler positions so the table is guaranteed to span more than
39 // one page, demonstrating the header-repeat-on-split behavior.
40 for i in 1..=25 {
41 items.push(LineItem {
42 description: format!("Zusatzposition {i:02}"),
43 qty: 1,
44 unit_price_cents: 990,
45 });
46 }
47
48 let net_total: i64 = items.iter().map(|i| i.qty as i64 * i.unit_price_cents).sum();
49 let vat_rate = 19;
50 let vat_total = net_total * vat_rate / 100;
51 let gross_total = net_total + vat_total;
52
53 let top_margin = 15.0 * MM;
54 let mut doc = Document::new(PageFormat::A4)
55 .margin(Margin::symmetric(20.0 * MM, top_margin))
56 .footer(Footer::new(30.0, |ctx| {
57 Column::new()
58 .gap(2.0)
59 .child(Line::new())
60 .child(
61 Row::new()
62 .gap(20.0)
63 .child(Text::new("Musterbank · IBAN DE12 3456 7890 1234 5678 90 · BIC MUSTDEFF").size(8.0))
64 .child(Text::new("USt-IdNr. DE123456789").size(8.0).flex(1.0)),
65 )
66 .child(Text::new(format!("Seite {} von {}", ctx.page, ctx.total_pages)).size(8.0))
67 .into()
68 }));
69
70 // --- DIN 5008 Form A window-envelope address block ----------------
71 // Window starts ~45mm from the top, ~20mm from the left
72 // (`plan/02-elementcatalog-and-features.md`); ~85x40mm matches a
73 // typical C6/5-long window envelope opening. Position/size are a
74 // documented convention for this recipe, not parsed from any norm
75 // document — a caller with different envelope stock adjusts these.
76 doc.add(Spacer::new(45.0 * MM - top_margin));
77 doc.add(
78 Column::new()
79 .gap(2.0)
80 .width(85.0 * MM)
81 .height(40.0 * MM)
82 .child(Text::new("Muster GmbH · Musterstraße 1 · 12345 Musterstadt").size(7.0))
83 .child(Spacer::new(8.0))
84 .child(Text::new("Empfänger GmbH"))
85 .child(Text::new("Frau Erika Mustermann"))
86 .child(Text::new("Beispielweg 42"))
87 .child(Text::new("54321 Beispielstadt")),
88 );
89 doc.add(Spacer::new(10.0 * MM));
90
91 doc.add(Text::new("Rechnung").heading1());
92 doc.add(Text::new(
93 "Rechnungsnummer: RE-2026-0142 Rechnungsdatum: 20.08.2026 Leistungsdatum: 20.08.2026",
94 ));
95 doc.add(Spacer::new(10.0));
96
97 doc.add(
98 Table::new()
99 .columns([
100 TableColumn::flex(1.0),
101 TableColumn::fixed(50.0).align(Align::End),
102 TableColumn::fixed(65.0).align(Align::End),
103 TableColumn::fixed(70.0).align(Align::End),
104 ])
105 .header(["Beschreibung", "Menge", "Einzelpreis", "Gesamt"])
106 .striped(Color::rgb(0xF5, 0xF5, 0xF5))
107 .rows(items.iter().map(|item| {
108 let total = item.qty as i64 * item.unit_price_cents;
109 vec![
110 Element::from(item.description.as_str()),
111 Element::from(item.qty.to_string()),
112 Element::from(format_currency_de(item.unit_price_cents)),
113 Element::from(format_currency_de(total)),
114 ]
115 })),
116 );
117
118 doc.add(Spacer::new(14.0));
119
120 // --- summary block (Netto/USt/Brutto), right-aligned --------------
121 // Recipe (`plan/02-elementcatalog-and-features.md`): an outer, full-
122 // width auto Column with `.align(Align::End)` positions the fixed-
123 // width (200pt) inner summary Column at the right edge; within it,
124 // each label gets `.flex(1.0)` to push its value to that block's own
125 // right edge. No special "summary block" element needed.
126 doc.add(
127 Column::new()
128 .align(Align::End)
129 .child(Column::new().gap(2.0).width(200.0).children(vec![
130 Element::from(
131 Row::new()
132 .child(Text::new("Nettosumme").flex(1.0))
133 .child(Text::new(format_currency_de(net_total))),
134 ),
135 Element::from(
136 Row::new()
137 .child(Text::new(format!("zzgl. {vat_rate}% USt.")).flex(1.0))
138 .child(Text::new(format_currency_de(vat_total))),
139 ),
140 Element::from(Line::new()),
141 Element::from(
142 Row::new()
143 .child(Text::new("Gesamtbetrag").bold().flex(1.0))
144 .child(Text::new(format_currency_de(gross_total)).bold()),
145 ),
146 ])),
147 );
148
149 let bytes = doc.render().expect("render should succeed");
150 std::fs::write("invoice.pdf", &bytes).expect("write invoice.pdf");
151 println!("wrote invoice.pdf ({} bytes)", bytes.len());
152}pub fn padding(self, padding: f32) -> Text
pub fn overflow(self, overflow: Overflow) -> Text
pub fn background(self, color: Color) -> Text
pub fn border(self, border: Border) -> Text
Sourcepub fn keep_with_next(self) -> Text
pub fn keep_with_next(self) -> Text
See plan/05-overflow-and-robustness.md Grundprinzip 9: only
placed on a page if the following sibling also still fits.
Trait Implementations§
Source§impl Layoutable for Text
impl Layoutable for Text
fn measure(&self, ctx: &LayoutCtx<'_>, constraints: Constraints) -> Size
fn layout( &self, ctx: &LayoutCtx<'_>, area: Rect, warnings: &mut Vec<LayoutWarning>, page: usize, ) -> LayoutResult
Auto Trait Implementations§
impl Freeze for Text
impl RefUnwindSafe for Text
impl Send for Text
impl Sync for Text
impl Unpin for Text
impl UnsafeUnpin for Text
impl UnwindSafe for Text
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