pub struct Slide {
pub shapes: Vec<Shape>,
pub notes: Option<TextBody>,
pub comments: Vec<SlideComment>,
pub background: Option<Fill>,
pub hidden: bool,
pub name: Option<String>,
pub hide_master_graphics: bool,
}Expand description
A single slide: an ordered list of shapes (<p:spTree>’s children), plus optional speaker
notes.
Fields§
§shapes: Vec<Shape>§notes: Option<TextBody>This slide’s speaker notes (ppt/notesSlides/notesSlideN.xml’s own “body” placeholder
text), if any. None (the default) means no notes part is written for this slide at all —
real PowerPoint packages commonly have no notes for most slides, so this stays a genuinely
optional, per-slide part rather than always-present boilerplate (mirrors word-ooxml’s
header/footer, styles.xml, etc. — every optional part in this workspace follows the same
“only written when actually set” convention). See Presentation’s writer for the fixed
notes-master/notes-slide boilerplate this produces around the text itself.
comments: Vec<SlideComment>This slide’s comments (ppt/comments/commentN.xml), if any — a genuinely optional part,
only written when non-empty, same “only written when actually set” convention as notes.
See SlideComment’s own doc comment for the caveat that this feature isn’t grounded on a
real fixture.
background: Option<Fill><p:cSld>/<p:bg>/<p:bgPr> — this slide’s own background fill, overriding whatever the slide
layout/master would otherwise show through. None (the default) omits <p:bg> entirely —
the slide simply inherits its background from the layout/master chain, same “no override”
default every other optional field in this crate uses. Only the direct fill choice
(<p:bgPr>, EG_FillProperties) is modeled — <p:bgRef> (a reference into the theme’s own
background style list) is not. Grounded against a real fixture (ppt/slides/slide2.xml),
which confirmed <p:bg> as <p:cSld>’s very first child, directly wrapping <p:bgPr>
before any fill.
<p:sld show="0"> (CT_Slide’s own show attribute) — hides this slide from the normal
slide-show sequence (it’s still present in the deck, just skipped when presenting;
PowerPoint’s own “Hide Slide” toggle). false (the default) omits the attribute, matching
the schema’s own default of a shown slide. Grounded against a real fixture.
name: Option<String><p:sld name="."> — an optional display name for this slide (distinct from its title
placeholder’s own text), shown e.g. in PowerPoint’s Slide Navigator/Outline view. None
omits the attribute entirely. Not grounded on a fixture — no corpus .pptx file
examined actually sets it — modeled directly from CT_Slide’s schema anyway, the same
posture already used for e.g. crate::model::SlideComment/crate::model::Connector.
hide_master_graphics: bool<p:sld showMasterSp="0"> (CT_Slide’s own showMasterSp attribute, inverted here) —
hides this slide’s inherited slide- master placeholder graphics/decorations (e.g. a logo or
footer bar drawn directly on the master, not through a placeholder this slide overrides).
The schema’s own default is showMasterSp="1" (shown) when the attribute is omitted — this
field is named/stored inverted (false = shown, matching every other boolean “override”
field in this crate, e.g. hidden) so that Slide::new’s all-false default already
matches real PowerPoint’s own default behavior, and the attribute is only ever written (as
"0") when explicitly hidden. Grounded against real fixtures.
Implementations§
Source§impl Slide
impl Slide
Sourcepub fn new() -> Slide
pub fn new() -> Slide
Creates an empty slide (no shapes, no notes, no comments, no background override, shown, unnamed, showing inherited master graphics).
Examples found in repository?
14fn main() -> office_toolkit::Result<()> {
15 let path = output_path("hello_world.pptx");
16
17 let text_box = AutoShape::new(2, "Hello box")
18 .with_properties(
19 ShapeProperties::new().with_transform(
20 Transform2D::new()
21 .with_offset(838_200, 1_365_250)
22 .with_extent(7_772_400, 1_200_150),
23 ),
24 )
25 .with_text_body(
26 TextBody::new()
27 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Hello, world!"))),
28 );
29
30 // `Presentation` and `Slide` both come from `office_toolkit::prelude`.
31 let presentation =
32 Presentation::new().with_slide(Slide::new().with_shape(Shape::AutoShape(text_box)));
33 presentation.save_to_file(&path)?;
34 println!("Wrote {}", path.display());
35
36 // Read the file back to confirm it is a valid .pptx.
37 let reopened = Presentation::open_file(&path)?;
38 println!("Slide count: {}", reopened.slides.len());
39
40 Ok(())
41}More examples
12fn main() -> office_toolkit::Result<()> {
13 let path = output_path("pptx_notes_and_comments.pptx");
14
15 let title = |text: &str| {
16 AutoShape::new(2, "Title")
17 .with_properties(
18 ShapeProperties::new().with_transform(
19 Transform2D::new()
20 .with_offset(838_200, 838_200)
21 .with_extent(8_000_000, 1_000_000),
22 ),
23 )
24 .with_text_body(
25 TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(text))),
26 )
27 };
28
29 let notes_slide = Slide::new()
30 .with_shape(Shape::AutoShape(title("A slide with speaker notes")))
31 .with_notes(
32 TextBody::new().with_paragraph(
33 TextParagraph::new()
34 .with_run(TextRun::text("Remember to mention the Q3 numbers here.")),
35 ),
36 );
37
38 let commented_slide = Slide::new()
39 .with_shape(Shape::AutoShape(title("A slide with reviewer comments")))
40 .with_comment(
41 SlideComment::new(
42 "Reviewer",
43 "RV",
44 "2026-07-21T10:00:00",
45 "This claim needs a source.",
46 )
47 .with_position(1_000_000, 2_000_000),
48 )
49 .with_comment(
50 SlideComment::new(
51 "Editor",
52 "ED",
53 "2026-07-21T11:30:00",
54 "Looks good otherwise.",
55 )
56 .with_position(3_000_000, 2_000_000),
57 );
58
59 let presentation = Presentation::new()
60 .with_slide(notes_slide)
61 .with_slide(commented_slide);
62
63 presentation.save_to_file(&path)?;
64 println!("Wrote {}", path.display());
65 Ok(())
66}20fn main() -> office_toolkit::Result<()> {
21 let path = output_path("pptx_media.pptx");
22 let image_bytes = std::fs::read(image_fixture_path())?;
23
24 let embedded_picture = Picture::new(
25 2,
26 "Embedded picture",
27 image_bytes.clone(),
28 PictureFormat::Png,
29 3_000_000,
30 2_000_000,
31 )
32 .with_offset(838_200, 838_200)
33 .with_description("Project test image");
34
35 let linked_picture = Picture::new(
36 2,
37 "Externally linked picture",
38 image_bytes,
39 PictureFormat::Png,
40 3_000_000,
41 2_000_000,
42 )
43 .with_offset(838_200, 838_200)
44 .with_external_link("https://example.com/original-image.png");
45
46 // Placeholder bytes — a real .pptx would carry a genuine video file
47 // here. This example only demonstrates the model/writer plumbing.
48 let poster_image = vec![0x89, 0x50, 0x4E, 0x47]; // fake, just enough bytes to have *some* data
49 let media = SlideMedia::new(
50 2,
51 "Video clip",
52 vec![0u8; 16],
53 MediaFormat::Mp4,
54 4_000_000,
55 2_250_000,
56 )
57 .with_offset(838_200, 838_200)
58 .with_poster_image(poster_image, PictureFormat::Png);
59
60 let chart = SlideChart::new(
61 2,
62 "Quarterly revenue",
63 sample_chart_space(),
64 6_000_000,
65 3_500_000,
66 )
67 .with_offset(838_200, 838_200);
68
69 let presentation = Presentation::new()
70 .with_slide(Slide::new().with_shape(Shape::Picture(embedded_picture)))
71 .with_slide(Slide::new().with_shape(Shape::Picture(linked_picture)))
72 .with_slide(Slide::new().with_shape(Shape::Media(media)))
73 .with_slide(Slide::new().with_shape(Shape::Chart(Box::new(chart))));
74
75 presentation.save_to_file(&path)?;
76 println!("Wrote {}", path.display());
77 Ok(())
78}16fn main() -> office_toolkit::Result<()> {
17 let path = output_path("pptx_tables.pptx");
18
19 let plain_table = SlideTable::new(2, "Plain table", 5_000_000, 1_500_000)
20 .with_offset(838_200, 838_200)
21 .with_column_widths(vec![2_500_000, 2_500_000])
22 .with_row(
23 TableRow::new(500_000)
24 .with_cell(cell("Name"))
25 .with_cell(cell("Score")),
26 )
27 .with_row(
28 TableRow::new(500_000)
29 .with_cell(cell("Alice"))
30 .with_cell(cell("92")),
31 )
32 .with_row(
33 TableRow::new(500_000)
34 .with_cell(cell("Bob"))
35 .with_cell(cell("87")),
36 );
37
38 let merged_table = SlideTable::new(2, "Merged cells", 5_000_000, 1_000_000)
39 .with_offset(838_200, 838_200)
40 .with_column_widths(vec![1_667_000, 1_667_000, 1_666_000])
41 .with_row(
42 TableRow::new(500_000)
43 .with_cell(cell("Spanning header").with_horizontal_span(3))
44 .with_cell(TableCell::horizontally_merged())
45 .with_cell(TableCell::horizontally_merged()),
46 )
47 .with_row(
48 TableRow::new(500_000)
49 .with_cell(cell("A"))
50 .with_cell(cell("B"))
51 .with_cell(cell("C")),
52 );
53
54 let styled_table = SlideTable::new(2, "Styled table", 5_000_000, 1_500_000)
55 .with_offset(838_200, 838_200)
56 .with_style_id("{66BB4812-77A1-49B3-BDF9-0CCEB564D7B5}")
57 .with_style_first_row(true)
58 .with_style_band_rows(true)
59 .with_column_widths(vec![2_500_000, 2_500_000])
60 .with_row(
61 TableRow::new(500_000)
62 .with_cell(cell("Header A"))
63 .with_cell(cell("Header B")),
64 )
65 .with_row(
66 TableRow::new(500_000)
67 .with_cell(cell("1"))
68 .with_cell(cell("2")),
69 )
70 .with_row(
71 TableRow::new(500_000)
72 .with_cell(cell("3"))
73 .with_cell(cell("4")),
74 );
75
76 let presentation = Presentation::new()
77 .with_table_style(
78 SlideTableStyle::new(
79 "{66BB4812-77A1-49B3-BDF9-0CCEB564D7B5}",
80 "Custom Table Style",
81 )
82 .with_first_row(
83 TableStylePart::new()
84 .with_fill(Fill::Solid(Color::Rgb("2E74B5".to_string())))
85 .with_bold(true)
86 .with_text_color(Color::Rgb("FFFFFF".to_string())),
87 )
88 .with_band1_horizontal(
89 TableStylePart::new().with_fill(Fill::Solid(Color::Rgb("F2F2F2".to_string()))),
90 ),
91 )
92 .with_slide(Slide::new().with_shape(Shape::Table(plain_table)))
93 .with_slide(Slide::new().with_shape(Shape::Table(merged_table)))
94 .with_slide(Slide::new().with_shape(Shape::Table(styled_table)));
95
96 presentation.save_to_file(&path)?;
97 println!("Wrote {}", path.display());
98 Ok(())
99}14fn main() -> office_toolkit::Result<()> {
15 let path = output_path("pptx_shapes_and_placeholders.pptx");
16
17 let plain_shape = AutoShape::new(2, "Plain autoshape")
18 .with_properties(
19 ShapeProperties::new().with_transform(
20 Transform2D::new()
21 .with_offset(838_200, 838_200)
22 .with_extent(5_000_000, 1_000_000),
23 ),
24 )
25 .with_text_body(
26 TextBody::new()
27 .with_paragraph(TextParagraph::new().with_run(TextRun::text("A plain autoshape."))),
28 );
29
30 let text_box = AutoShape::new(2, "Text box")
31 .with_text_box(true)
32 .with_properties(
33 ShapeProperties::new().with_transform(
34 Transform2D::new()
35 .with_offset(838_200, 838_200)
36 .with_extent(5_000_000, 1_000_000),
37 ),
38 )
39 .with_text_body(TextBody::new().with_paragraph(
40 TextParagraph::new().with_run(TextRun::text("A genuine text box (txBox=\"1\").")),
41 ));
42
43 let title = AutoShape::new(2, "Title placeholder")
44 .with_placeholder(Placeholder::new(PlaceholderKind::CenterTitle))
45 .with_properties(
46 ShapeProperties::new().with_transform(
47 Transform2D::new()
48 .with_offset(838_200, 838_200)
49 .with_extent(10_515_600, 1_325_563),
50 ),
51 )
52 .with_text_body(
53 TextBody::new()
54 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Title placeholder"))),
55 );
56 let subtitle =
57 AutoShape::new(3, "Subtitle placeholder")
58 .with_placeholder(Placeholder::new(PlaceholderKind::SubTitle).with_index(1))
59 .with_properties(
60 ShapeProperties::new().with_transform(
61 Transform2D::new()
62 .with_offset(838_200, 2_400_000)
63 .with_extent(10_515_600, 800_000),
64 ),
65 )
66 .with_text_body(TextBody::new().with_paragraph(
67 TextParagraph::new().with_run(TextRun::text("Subtitle placeholder")),
68 ));
69
70 let hyperlinked_shape = AutoShape::new(2, "Hyperlinked shape")
71 .with_hyperlink("https://www.rust-lang.org")
72 .with_properties(
73 ShapeProperties::new().with_transform(
74 Transform2D::new()
75 .with_offset(838_200, 838_200)
76 .with_extent(5_000_000, 1_000_000),
77 ),
78 )
79 .with_text_body(TextBody::new().with_paragraph(
80 TextParagraph::new().with_run(TextRun::text("Click this shape to open a link.")),
81 ));
82
83 let presentation = Presentation::new()
84 .with_slide(Slide::new().with_shape(Shape::AutoShape(plain_shape)))
85 .with_slide(Slide::new().with_shape(Shape::AutoShape(text_box)))
86 .with_slide(
87 Slide::new()
88 .with_shape(Shape::AutoShape(title))
89 .with_shape(Shape::AutoShape(subtitle)),
90 )
91 .with_slide(Slide::new().with_shape(Shape::AutoShape(hyperlinked_shape)));
92
93 presentation.save_to_file(&path)?;
94 println!("Wrote {}", path.display());
95 Ok(())
96}19fn main() -> office_toolkit::Result<()> {
20 // A custom theme and an embedded font. `Theme`/`ColorScheme`/
21 // `FontScheme` have no `with_*` builders in this crate — only
22 // `office_default()` or plain struct literals.
23 let custom_theme = Theme {
24 name: "Custom Brand".to_string(),
25 colors: ColorScheme {
26 dark1: "1B1B1B".to_string(),
27 light1: "FFFFFF".to_string(),
28 dark2: "0A2540".to_string(),
29 light2: "F5F5F5".to_string(),
30 accent1: "0A2540".to_string(),
31 accent2: "E8622C".to_string(),
32 accent3: "2E86AB".to_string(),
33 accent4: "6FB98F".to_string(),
34 accent5: "F4A259".to_string(),
35 accent6: "8E4585".to_string(),
36 hyperlink: "1155CC".to_string(),
37 followed_hyperlink: "6B3FA0".to_string(),
38 },
39 fonts: FontScheme {
40 major_latin: "Georgia".to_string(),
41 minor_latin: "Verdana".to_string(),
42 },
43 };
44
45 // Placeholder bytes — a real .pptx would carry genuine TrueType/
46 // OpenType font data here.
47 let embedded_font = EmbeddedFont::new("Custom Sans")
48 .with_regular(vec![0u8; 16])
49 .with_bold(vec![0u8; 16]);
50
51 // A slide with no shapes at all renders as a blank page — nothing shows
52 // the custom theme actually took effect. `drawing::Color` has no
53 // scheme-relative variant yet (`<a:schemeClr>` isn't modeled, see that
54 // enum's own doc comment), so this can't reference the theme's accent1
55 // symbolically; it uses the same literal hex values the theme itself
56 // was built from, purely so the slide visibly matches the palette above.
57 let title_shape = AutoShape::new(2, "Title")
58 .with_properties(
59 ShapeProperties::new()
60 .with_transform(
61 Transform2D::new()
62 .with_offset(838_200, 838_200)
63 .with_extent(6_000_000, 1_500_000),
64 )
65 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.accent1.clone()))),
66 )
67 .with_text_body(
68 TextBody::new().with_paragraph(
69 TextParagraph::new().with_run(TextRun::text_with_properties(
70 "Custom Brand theme — Georgia / Verdana, accent1 = #0A2540",
71 TextRunProperties::new()
72 .with_font_family(custom_theme.fonts.major_latin.clone())
73 .with_font_size_points(24.0)
74 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.light1.clone()))),
75 )),
76 ),
77 );
78
79 let themed_presentation = Presentation::new()
80 .with_theme(custom_theme)
81 .with_embedded_font(embedded_font)
82 .with_slide(Slide::new().with_shape(Shape::AutoShape(title_shape)));
83 let theme_path = output_path("pptx_theme.pptx");
84 themed_presentation.save_to_file(&theme_path)?;
85 println!("Wrote {}", theme_path.display());
86
87 // Document metadata (docProps/core.xml, app.xml, and custom.xml).
88 let properties = DocumentProperties::new()
89 .with_title("Metadata example")
90 .with_author("Example Author")
91 .with_subject("Presentation-level features")
92 .with_custom_property(
93 "ProjectCode",
94 CustomPropertyValue::Text("PPTX-META".to_string()),
95 );
96 // Same reasoning as `title_shape` above: an empty slide would render
97 // blank, so a text shape spells out where the metadata actually lives.
98 let metadata_shape = AutoShape::new(2, "Note")
99 .with_properties(ShapeProperties::new().with_transform(Transform2D::new().with_offset(838_200, 838_200).with_extent(7_000_000, 1_000_000)))
100 .with_text_body(TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(
101 "This presentation's metadata is in File > Info (title, author, subject, and a custom \"ProjectCode\" property) — not on this slide.",
102 ))));
103 let metadata_presentation = Presentation::new()
104 .with_properties(properties)
105 .with_slide(Slide::new().with_shape(Shape::AutoShape(metadata_shape)));
106 let metadata_path = output_path("pptx_metadata.pptx");
107 metadata_presentation.save_to_file(&metadata_path)?;
108 println!("Wrote {}", metadata_path.display());
109
110 Ok(())
111}Sourcepub fn with_shape(self, shape: Shape) -> Slide
pub fn with_shape(self, shape: Shape) -> Slide
Appends a shape.
Examples found in repository?
14fn main() -> office_toolkit::Result<()> {
15 let path = output_path("hello_world.pptx");
16
17 let text_box = AutoShape::new(2, "Hello box")
18 .with_properties(
19 ShapeProperties::new().with_transform(
20 Transform2D::new()
21 .with_offset(838_200, 1_365_250)
22 .with_extent(7_772_400, 1_200_150),
23 ),
24 )
25 .with_text_body(
26 TextBody::new()
27 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Hello, world!"))),
28 );
29
30 // `Presentation` and `Slide` both come from `office_toolkit::prelude`.
31 let presentation =
32 Presentation::new().with_slide(Slide::new().with_shape(Shape::AutoShape(text_box)));
33 presentation.save_to_file(&path)?;
34 println!("Wrote {}", path.display());
35
36 // Read the file back to confirm it is a valid .pptx.
37 let reopened = Presentation::open_file(&path)?;
38 println!("Slide count: {}", reopened.slides.len());
39
40 Ok(())
41}More examples
12fn main() -> office_toolkit::Result<()> {
13 let path = output_path("pptx_notes_and_comments.pptx");
14
15 let title = |text: &str| {
16 AutoShape::new(2, "Title")
17 .with_properties(
18 ShapeProperties::new().with_transform(
19 Transform2D::new()
20 .with_offset(838_200, 838_200)
21 .with_extent(8_000_000, 1_000_000),
22 ),
23 )
24 .with_text_body(
25 TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(text))),
26 )
27 };
28
29 let notes_slide = Slide::new()
30 .with_shape(Shape::AutoShape(title("A slide with speaker notes")))
31 .with_notes(
32 TextBody::new().with_paragraph(
33 TextParagraph::new()
34 .with_run(TextRun::text("Remember to mention the Q3 numbers here.")),
35 ),
36 );
37
38 let commented_slide = Slide::new()
39 .with_shape(Shape::AutoShape(title("A slide with reviewer comments")))
40 .with_comment(
41 SlideComment::new(
42 "Reviewer",
43 "RV",
44 "2026-07-21T10:00:00",
45 "This claim needs a source.",
46 )
47 .with_position(1_000_000, 2_000_000),
48 )
49 .with_comment(
50 SlideComment::new(
51 "Editor",
52 "ED",
53 "2026-07-21T11:30:00",
54 "Looks good otherwise.",
55 )
56 .with_position(3_000_000, 2_000_000),
57 );
58
59 let presentation = Presentation::new()
60 .with_slide(notes_slide)
61 .with_slide(commented_slide);
62
63 presentation.save_to_file(&path)?;
64 println!("Wrote {}", path.display());
65 Ok(())
66}20fn main() -> office_toolkit::Result<()> {
21 let path = output_path("pptx_media.pptx");
22 let image_bytes = std::fs::read(image_fixture_path())?;
23
24 let embedded_picture = Picture::new(
25 2,
26 "Embedded picture",
27 image_bytes.clone(),
28 PictureFormat::Png,
29 3_000_000,
30 2_000_000,
31 )
32 .with_offset(838_200, 838_200)
33 .with_description("Project test image");
34
35 let linked_picture = Picture::new(
36 2,
37 "Externally linked picture",
38 image_bytes,
39 PictureFormat::Png,
40 3_000_000,
41 2_000_000,
42 )
43 .with_offset(838_200, 838_200)
44 .with_external_link("https://example.com/original-image.png");
45
46 // Placeholder bytes — a real .pptx would carry a genuine video file
47 // here. This example only demonstrates the model/writer plumbing.
48 let poster_image = vec![0x89, 0x50, 0x4E, 0x47]; // fake, just enough bytes to have *some* data
49 let media = SlideMedia::new(
50 2,
51 "Video clip",
52 vec![0u8; 16],
53 MediaFormat::Mp4,
54 4_000_000,
55 2_250_000,
56 )
57 .with_offset(838_200, 838_200)
58 .with_poster_image(poster_image, PictureFormat::Png);
59
60 let chart = SlideChart::new(
61 2,
62 "Quarterly revenue",
63 sample_chart_space(),
64 6_000_000,
65 3_500_000,
66 )
67 .with_offset(838_200, 838_200);
68
69 let presentation = Presentation::new()
70 .with_slide(Slide::new().with_shape(Shape::Picture(embedded_picture)))
71 .with_slide(Slide::new().with_shape(Shape::Picture(linked_picture)))
72 .with_slide(Slide::new().with_shape(Shape::Media(media)))
73 .with_slide(Slide::new().with_shape(Shape::Chart(Box::new(chart))));
74
75 presentation.save_to_file(&path)?;
76 println!("Wrote {}", path.display());
77 Ok(())
78}16fn main() -> office_toolkit::Result<()> {
17 let path = output_path("pptx_tables.pptx");
18
19 let plain_table = SlideTable::new(2, "Plain table", 5_000_000, 1_500_000)
20 .with_offset(838_200, 838_200)
21 .with_column_widths(vec![2_500_000, 2_500_000])
22 .with_row(
23 TableRow::new(500_000)
24 .with_cell(cell("Name"))
25 .with_cell(cell("Score")),
26 )
27 .with_row(
28 TableRow::new(500_000)
29 .with_cell(cell("Alice"))
30 .with_cell(cell("92")),
31 )
32 .with_row(
33 TableRow::new(500_000)
34 .with_cell(cell("Bob"))
35 .with_cell(cell("87")),
36 );
37
38 let merged_table = SlideTable::new(2, "Merged cells", 5_000_000, 1_000_000)
39 .with_offset(838_200, 838_200)
40 .with_column_widths(vec![1_667_000, 1_667_000, 1_666_000])
41 .with_row(
42 TableRow::new(500_000)
43 .with_cell(cell("Spanning header").with_horizontal_span(3))
44 .with_cell(TableCell::horizontally_merged())
45 .with_cell(TableCell::horizontally_merged()),
46 )
47 .with_row(
48 TableRow::new(500_000)
49 .with_cell(cell("A"))
50 .with_cell(cell("B"))
51 .with_cell(cell("C")),
52 );
53
54 let styled_table = SlideTable::new(2, "Styled table", 5_000_000, 1_500_000)
55 .with_offset(838_200, 838_200)
56 .with_style_id("{66BB4812-77A1-49B3-BDF9-0CCEB564D7B5}")
57 .with_style_first_row(true)
58 .with_style_band_rows(true)
59 .with_column_widths(vec![2_500_000, 2_500_000])
60 .with_row(
61 TableRow::new(500_000)
62 .with_cell(cell("Header A"))
63 .with_cell(cell("Header B")),
64 )
65 .with_row(
66 TableRow::new(500_000)
67 .with_cell(cell("1"))
68 .with_cell(cell("2")),
69 )
70 .with_row(
71 TableRow::new(500_000)
72 .with_cell(cell("3"))
73 .with_cell(cell("4")),
74 );
75
76 let presentation = Presentation::new()
77 .with_table_style(
78 SlideTableStyle::new(
79 "{66BB4812-77A1-49B3-BDF9-0CCEB564D7B5}",
80 "Custom Table Style",
81 )
82 .with_first_row(
83 TableStylePart::new()
84 .with_fill(Fill::Solid(Color::Rgb("2E74B5".to_string())))
85 .with_bold(true)
86 .with_text_color(Color::Rgb("FFFFFF".to_string())),
87 )
88 .with_band1_horizontal(
89 TableStylePart::new().with_fill(Fill::Solid(Color::Rgb("F2F2F2".to_string()))),
90 ),
91 )
92 .with_slide(Slide::new().with_shape(Shape::Table(plain_table)))
93 .with_slide(Slide::new().with_shape(Shape::Table(merged_table)))
94 .with_slide(Slide::new().with_shape(Shape::Table(styled_table)));
95
96 presentation.save_to_file(&path)?;
97 println!("Wrote {}", path.display());
98 Ok(())
99}14fn main() -> office_toolkit::Result<()> {
15 let path = output_path("pptx_shapes_and_placeholders.pptx");
16
17 let plain_shape = AutoShape::new(2, "Plain autoshape")
18 .with_properties(
19 ShapeProperties::new().with_transform(
20 Transform2D::new()
21 .with_offset(838_200, 838_200)
22 .with_extent(5_000_000, 1_000_000),
23 ),
24 )
25 .with_text_body(
26 TextBody::new()
27 .with_paragraph(TextParagraph::new().with_run(TextRun::text("A plain autoshape."))),
28 );
29
30 let text_box = AutoShape::new(2, "Text box")
31 .with_text_box(true)
32 .with_properties(
33 ShapeProperties::new().with_transform(
34 Transform2D::new()
35 .with_offset(838_200, 838_200)
36 .with_extent(5_000_000, 1_000_000),
37 ),
38 )
39 .with_text_body(TextBody::new().with_paragraph(
40 TextParagraph::new().with_run(TextRun::text("A genuine text box (txBox=\"1\").")),
41 ));
42
43 let title = AutoShape::new(2, "Title placeholder")
44 .with_placeholder(Placeholder::new(PlaceholderKind::CenterTitle))
45 .with_properties(
46 ShapeProperties::new().with_transform(
47 Transform2D::new()
48 .with_offset(838_200, 838_200)
49 .with_extent(10_515_600, 1_325_563),
50 ),
51 )
52 .with_text_body(
53 TextBody::new()
54 .with_paragraph(TextParagraph::new().with_run(TextRun::text("Title placeholder"))),
55 );
56 let subtitle =
57 AutoShape::new(3, "Subtitle placeholder")
58 .with_placeholder(Placeholder::new(PlaceholderKind::SubTitle).with_index(1))
59 .with_properties(
60 ShapeProperties::new().with_transform(
61 Transform2D::new()
62 .with_offset(838_200, 2_400_000)
63 .with_extent(10_515_600, 800_000),
64 ),
65 )
66 .with_text_body(TextBody::new().with_paragraph(
67 TextParagraph::new().with_run(TextRun::text("Subtitle placeholder")),
68 ));
69
70 let hyperlinked_shape = AutoShape::new(2, "Hyperlinked shape")
71 .with_hyperlink("https://www.rust-lang.org")
72 .with_properties(
73 ShapeProperties::new().with_transform(
74 Transform2D::new()
75 .with_offset(838_200, 838_200)
76 .with_extent(5_000_000, 1_000_000),
77 ),
78 )
79 .with_text_body(TextBody::new().with_paragraph(
80 TextParagraph::new().with_run(TextRun::text("Click this shape to open a link.")),
81 ));
82
83 let presentation = Presentation::new()
84 .with_slide(Slide::new().with_shape(Shape::AutoShape(plain_shape)))
85 .with_slide(Slide::new().with_shape(Shape::AutoShape(text_box)))
86 .with_slide(
87 Slide::new()
88 .with_shape(Shape::AutoShape(title))
89 .with_shape(Shape::AutoShape(subtitle)),
90 )
91 .with_slide(Slide::new().with_shape(Shape::AutoShape(hyperlinked_shape)));
92
93 presentation.save_to_file(&path)?;
94 println!("Wrote {}", path.display());
95 Ok(())
96}19fn main() -> office_toolkit::Result<()> {
20 // A custom theme and an embedded font. `Theme`/`ColorScheme`/
21 // `FontScheme` have no `with_*` builders in this crate — only
22 // `office_default()` or plain struct literals.
23 let custom_theme = Theme {
24 name: "Custom Brand".to_string(),
25 colors: ColorScheme {
26 dark1: "1B1B1B".to_string(),
27 light1: "FFFFFF".to_string(),
28 dark2: "0A2540".to_string(),
29 light2: "F5F5F5".to_string(),
30 accent1: "0A2540".to_string(),
31 accent2: "E8622C".to_string(),
32 accent3: "2E86AB".to_string(),
33 accent4: "6FB98F".to_string(),
34 accent5: "F4A259".to_string(),
35 accent6: "8E4585".to_string(),
36 hyperlink: "1155CC".to_string(),
37 followed_hyperlink: "6B3FA0".to_string(),
38 },
39 fonts: FontScheme {
40 major_latin: "Georgia".to_string(),
41 minor_latin: "Verdana".to_string(),
42 },
43 };
44
45 // Placeholder bytes — a real .pptx would carry genuine TrueType/
46 // OpenType font data here.
47 let embedded_font = EmbeddedFont::new("Custom Sans")
48 .with_regular(vec![0u8; 16])
49 .with_bold(vec![0u8; 16]);
50
51 // A slide with no shapes at all renders as a blank page — nothing shows
52 // the custom theme actually took effect. `drawing::Color` has no
53 // scheme-relative variant yet (`<a:schemeClr>` isn't modeled, see that
54 // enum's own doc comment), so this can't reference the theme's accent1
55 // symbolically; it uses the same literal hex values the theme itself
56 // was built from, purely so the slide visibly matches the palette above.
57 let title_shape = AutoShape::new(2, "Title")
58 .with_properties(
59 ShapeProperties::new()
60 .with_transform(
61 Transform2D::new()
62 .with_offset(838_200, 838_200)
63 .with_extent(6_000_000, 1_500_000),
64 )
65 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.accent1.clone()))),
66 )
67 .with_text_body(
68 TextBody::new().with_paragraph(
69 TextParagraph::new().with_run(TextRun::text_with_properties(
70 "Custom Brand theme — Georgia / Verdana, accent1 = #0A2540",
71 TextRunProperties::new()
72 .with_font_family(custom_theme.fonts.major_latin.clone())
73 .with_font_size_points(24.0)
74 .with_fill(Fill::Solid(Color::Rgb(custom_theme.colors.light1.clone()))),
75 )),
76 ),
77 );
78
79 let themed_presentation = Presentation::new()
80 .with_theme(custom_theme)
81 .with_embedded_font(embedded_font)
82 .with_slide(Slide::new().with_shape(Shape::AutoShape(title_shape)));
83 let theme_path = output_path("pptx_theme.pptx");
84 themed_presentation.save_to_file(&theme_path)?;
85 println!("Wrote {}", theme_path.display());
86
87 // Document metadata (docProps/core.xml, app.xml, and custom.xml).
88 let properties = DocumentProperties::new()
89 .with_title("Metadata example")
90 .with_author("Example Author")
91 .with_subject("Presentation-level features")
92 .with_custom_property(
93 "ProjectCode",
94 CustomPropertyValue::Text("PPTX-META".to_string()),
95 );
96 // Same reasoning as `title_shape` above: an empty slide would render
97 // blank, so a text shape spells out where the metadata actually lives.
98 let metadata_shape = AutoShape::new(2, "Note")
99 .with_properties(ShapeProperties::new().with_transform(Transform2D::new().with_offset(838_200, 838_200).with_extent(7_000_000, 1_000_000)))
100 .with_text_body(TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(
101 "This presentation's metadata is in File > Info (title, author, subject, and a custom \"ProjectCode\" property) — not on this slide.",
102 ))));
103 let metadata_presentation = Presentation::new()
104 .with_properties(properties)
105 .with_slide(Slide::new().with_shape(Shape::AutoShape(metadata_shape)));
106 let metadata_path = output_path("pptx_metadata.pptx");
107 metadata_presentation.save_to_file(&metadata_path)?;
108 println!("Wrote {}", metadata_path.display());
109
110 Ok(())
111}Sourcepub fn add_shape(&mut self, shape: Shape) -> &mut Shape
pub fn add_shape(&mut self, shape: Shape) -> &mut Shape
Appends a shape and returns a mutable reference to it. A &mut self counterpart to
Self::with_shape, same rationale as Presentation::add_slide.
Hides this slide from the normal slide-show sequence (show="0").
Sourcepub fn with_name(self, name: impl Into<String>) -> Slide
pub fn with_name(self, name: impl Into<String>) -> Slide
Sets this slide’s display name (<p:sld name="..">).
Sourcepub fn with_notes(self, notes: TextBody) -> Slide
pub fn with_notes(self, notes: TextBody) -> Slide
Sets this slide’s speaker notes.
Examples found in repository?
12fn main() -> office_toolkit::Result<()> {
13 let path = output_path("pptx_notes_and_comments.pptx");
14
15 let title = |text: &str| {
16 AutoShape::new(2, "Title")
17 .with_properties(
18 ShapeProperties::new().with_transform(
19 Transform2D::new()
20 .with_offset(838_200, 838_200)
21 .with_extent(8_000_000, 1_000_000),
22 ),
23 )
24 .with_text_body(
25 TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(text))),
26 )
27 };
28
29 let notes_slide = Slide::new()
30 .with_shape(Shape::AutoShape(title("A slide with speaker notes")))
31 .with_notes(
32 TextBody::new().with_paragraph(
33 TextParagraph::new()
34 .with_run(TextRun::text("Remember to mention the Q3 numbers here.")),
35 ),
36 );
37
38 let commented_slide = Slide::new()
39 .with_shape(Shape::AutoShape(title("A slide with reviewer comments")))
40 .with_comment(
41 SlideComment::new(
42 "Reviewer",
43 "RV",
44 "2026-07-21T10:00:00",
45 "This claim needs a source.",
46 )
47 .with_position(1_000_000, 2_000_000),
48 )
49 .with_comment(
50 SlideComment::new(
51 "Editor",
52 "ED",
53 "2026-07-21T11:30:00",
54 "Looks good otherwise.",
55 )
56 .with_position(3_000_000, 2_000_000),
57 );
58
59 let presentation = Presentation::new()
60 .with_slide(notes_slide)
61 .with_slide(commented_slide);
62
63 presentation.save_to_file(&path)?;
64 println!("Wrote {}", path.display());
65 Ok(())
66}Sourcepub fn with_comment(self, comment: SlideComment) -> Slide
pub fn with_comment(self, comment: SlideComment) -> Slide
Appends a comment.
Examples found in repository?
12fn main() -> office_toolkit::Result<()> {
13 let path = output_path("pptx_notes_and_comments.pptx");
14
15 let title = |text: &str| {
16 AutoShape::new(2, "Title")
17 .with_properties(
18 ShapeProperties::new().with_transform(
19 Transform2D::new()
20 .with_offset(838_200, 838_200)
21 .with_extent(8_000_000, 1_000_000),
22 ),
23 )
24 .with_text_body(
25 TextBody::new().with_paragraph(TextParagraph::new().with_run(TextRun::text(text))),
26 )
27 };
28
29 let notes_slide = Slide::new()
30 .with_shape(Shape::AutoShape(title("A slide with speaker notes")))
31 .with_notes(
32 TextBody::new().with_paragraph(
33 TextParagraph::new()
34 .with_run(TextRun::text("Remember to mention the Q3 numbers here.")),
35 ),
36 );
37
38 let commented_slide = Slide::new()
39 .with_shape(Shape::AutoShape(title("A slide with reviewer comments")))
40 .with_comment(
41 SlideComment::new(
42 "Reviewer",
43 "RV",
44 "2026-07-21T10:00:00",
45 "This claim needs a source.",
46 )
47 .with_position(1_000_000, 2_000_000),
48 )
49 .with_comment(
50 SlideComment::new(
51 "Editor",
52 "ED",
53 "2026-07-21T11:30:00",
54 "Looks good otherwise.",
55 )
56 .with_position(3_000_000, 2_000_000),
57 );
58
59 let presentation = Presentation::new()
60 .with_slide(notes_slide)
61 .with_slide(commented_slide);
62
63 presentation.save_to_file(&path)?;
64 println!("Wrote {}", path.display());
65 Ok(())
66}Sourcepub fn with_background(self, background: Fill) -> Slide
pub fn with_background(self, background: Fill) -> Slide
Sets this slide’s own background fill, overriding the layout/master.
Sourcepub fn with_hide_master_graphics(self, hide: bool) -> Slide
pub fn with_hide_master_graphics(self, hide: bool) -> Slide
Hides this slide’s inherited slide-master graphics (showMasterSp="0").