Table of Contents

Spreadsheets and presentations

WorkbookEditor covers XLSX and PresentationEditor covers PPTX. Both follow the same conventions as the Word surface: static methods, byte[] by default, Stream and path overloads where you need them.

Creating a workbook

byte[] xlsx = WorkbookEditor.Create("Sales", new object?[][]
{
    new object?[] { "Region", "Total" },
    new object?[] { "North",  1200 },
    new object?[] { "South",  950 },
});

string before = WorkbookEditor.ReadCell(xlsx, "Sales", "B2");
byte[] updated = WorkbookEditor.SetCell(xlsx, "Sales", "B2", 1500);
string after = WorkbookEditor.ReadCell(updated, "Sales", "B2");

Cell values are object?. Numbers are written as numbers and strings as strings, so a column of totals arrives in Excel as something you can sum rather than as text that merely looks numeric. ReadCell returns a string — the cell's value as displayed — because that is what almost every caller does with it next.

Reading a workbook you were handed

You do not need to know the shape in advance.

IReadOnlyList<string> sheets = WorkbookEditor.SheetNames(updated);
IReadOnlyList<IReadOnlyList<string>> grid = WorkbookEditor.ReadSheet(updated, sheets[0]);

SheetNames tells you what is in the file and ReadSheet returns the used range as rows of strings. Together they are enough to walk an upload you have never seen.

Several sheets, and formulas between them

byte[] workbook = WorkbookEditor.Create(new[]
{
    XlsxSheet.Named("Q1", new[]
    {
        new object?[] { "Region", "Revenue" },
        new object?[] { "EMEA", 1200 },
        new object?[] { "APAC", 980 },
    }),
    XlsxSheet.Named("Summary", new[]
    {
        new object?[] { "Grand total", XlsxFormula.From("SUM(Q1!B2:B4)") },
    }),
});

// Rows append after the sheet's last used row, leaving every other sheet untouched.
workbook = WorkbookEditor.AppendRows(workbook, "Q1", new[]
{
    new object?[] { "AMER", 1450 },
});

Two details in there are worth calling out.

A cell holding an XlsxFormula is written as a formula, not as text that starts with =. XlsxFormula.From("SUM(Q1!B2:B4)") is how you say "this is a computation" — and note the formula has no leading =, which the writer adds.

Reading that formula back through this library gives you the computed value. The underlying engine evaluates it, because a file written this way carries no cached result. A reader that only reads cached values — which is most of them — sees an empty cell until Excel has opened and saved the file. This is a genuinely surprising interop failure, and it is worth knowing which side of it you are on.

AppendRows adds after the sheet's last used row and leaves every other sheet untouched, which is the operation you want for a log or an export that accumulates.

Presentations

PresentationEditor.Create builds a deck from a typed model — no template file involved.

byte[] pptx = PresentationEditor.Create(new[]
{
    PptxSlide.Titled("Hello {{who}}", "Built from a typed model", "No template file involved"),
    PptxSlide.Titled("Second slide", "Bullets are optional"),
});

int slides = PresentationEditor.SlideCount(pptx);
IReadOnlyList<string> text = PresentationEditor.ExtractText(pptx);

@DocToolkit.PptxSlide.Titled gives you a title and any number of bullets, emitted as real title and body placeholders rather than free-floating text boxes. That matters if anyone opens the deck in PowerPoint afterwards: placeholders inherit the theme, respond to layout changes, and appear in the outline view.

Warning

ExtractText returns one entry per text-bearing body, not one per slide. Create emits two shapes per slide — a title and a content placeholder — so a two-slide deck reports four bodies. Use SlideCount for the slide count; ExtractText(...).Count is not it.

ReplaceText works the same way it does for Word documents, so a deck can be a template too:

byte[] edited = PresentationEditor.ReplaceText(pptx, new Dictionary<string, string>
{
    ["{{who}}"] = "World",
});

Rendering either one to PDF

XlsxToPdfConverter and PptxToPdfConverter mirror DocxToPdfConverter exactly — the same three members, the same behaviour.

byte[] fromSheet = XlsxToPdfConverter.Convert(xlsx);
byte[] fromDeck  = PptxToPdfConverter.Convert(pptx);

XlsxToPdfConverter.ConvertFile("report.xlsx", "report.pdf");
await PptxToPdfConverter.ConvertAsync(source, destination, ct);

The same fidelity limit applies as everywhere else: features the rendering engine cannot represent — charts, conditional formatting, some shape effects — are dropped silently. There is no warning channel on the public API. The PDF is valid; it just will not have the chart in it. If a chart is the point of the document, render it to an image yourself and place that.

Choosing a starting point

You have Use
A file somebody made in Excel or PowerPoint SetCell / AppendRows / ReplaceText — edit in place, keep the formatting
Data, and no file Create — describe the content, let the library write the file
A file you did not write and have never seen SheetNames + ReadSheet, or SlideCount + ExtractText