Gravicode.OfficeNet.Rendering 1.3.0

dotnet add package Gravicode.OfficeNet.Rendering --version 1.3.0
                    
NuGet\Install-Package Gravicode.OfficeNet.Rendering -Version 1.3.0
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Gravicode.OfficeNet.Rendering" Version="1.3.0" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Gravicode.OfficeNet.Rendering" Version="1.3.0" />
                    
Directory.Packages.props
<PackageReference Include="Gravicode.OfficeNet.Rendering" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Gravicode.OfficeNet.Rendering --version 1.3.0
                    
#r "nuget: Gravicode.OfficeNet.Rendering, 1.3.0"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Gravicode.OfficeNet.Rendering@1.3.0
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Gravicode.OfficeNet.Rendering&version=1.3.0
                    
Install as a Cake Addin
#tool nuget:?package=Gravicode.OfficeNet.Rendering&version=1.3.0
                    
Install as a Cake Tool

OfficeNet

Bahasa Indonesia

Word, Excel, PowerPoint and PDF for .NET 10 — no Office install, no native dependency, identical output on Windows, Linux and macOS.

OfficeNet is a rewrite of the Python document stack. Each library mirrors one of the originals and keeps its shape, so if you know the Python you already know the API.

Package Rewrite of What it does
Gravicode.OfficeNet.WordNet python-docx .docx — paragraphs, styles, tables, images, sections, headers, mail merge
Gravicode.OfficeNet.ExcelNet openpyxl + pandas .xlsx — cells, formulas, styles, charts data, CSV/JSON/SQL, DataFrames
Gravicode.OfficeNet.PowerPointNet python-pptx + PptxGenJS .pptx — slides, layouts, themes, tables, charts, media, HTML → slides
Gravicode.OfficeNet.PdfNet PyPDF2 .pdf — merge, split, rotate, extract, forms, encryption, annotations, drawing
Gravicode.OfficeNet.Rendering pdf2image Pages to PNG/JPEG/WebP — the only package with a native dependency
Gravicode.OfficeNet.Core The OPC container, units, colour and chart model every library shares
Gravicode.OfficeNet Meta package pulling in all of the above, plus the Office facade

Dibuat oleh Gravicode Studios, dipimpin oleh Kang Fadhil.


What it produces

Every image below is generated by tools/ScreenshotGen from the libraries' own output and rendered through OfficeNet.Rendering — never captured from Word, Excel or PowerPoint. Re-running the tool regenerates them, so they cannot drift away from what the code actually does.

WordNet — headings, styles, header and footer, page-number fields, a shaded table A Word document rendered to PNG
ExcelNet — typed dates, Rupiah formats, and a SUM the engine actually evaluated An Excel workbook rendered to PNG
PowerPointNet — a native chart, drawn by the PDF exporter from its own cached data A chart slide rendered to PNG
HTML → slides — headings, nested lists and a table become a deck in one call A slide generated from HTML

The sample applications

OfficeNet Gallery — every feature running beside the code that produced it. That source is read out of the embedded demo file at runtime, so it is literally the code that just executed rather than a snippet someone copied and forgot to update.

The gallery: catalog, rendered output, and the source that produced it

Its assistant answers questions about the libraries, with several conversations at once and example prompts grouped by library. Verified against live Azure OpenAI and DeepSeek models, with the web search, date and maths tools all firing.

The assistant, with sessions and clickable example prompts

OfficeNet Dashboard — upload a document and see it rendered and taken apart: every part in the OPC container with its content type and size, plus the whole relationship graph. That panel is the reason the sample exists.

The dashboard, showing a deck and its package anatomy


Documentation

Full guides live in docs/, bilingual throughout. Every code sample on those pages is compiled and run by the test suite, so none of them can go stale.

Guide English Bahasa Indonesia
Index docs/README.md docs/id/README.md
Core concepts — OPC, units, colour, metadata Core.md id/Core.md
WordNet WordNet.md id/WordNet.md
ExcelNet ExcelNet.md id/ExcelNet.md
PowerPointNet PowerPointNet.md id/PowerPointNet.md
PdfNet PdfNet.md id/PdfNet.md
Rendering Rendering.md id/Rendering.md
Unified API and plugins OfficeNet.md id/OfficeNet.md

And elsewhere in the repository:

  • samples/ — five applications: two CLI, a Blazor dashboard, and two Avalonia apps including the Gallery
  • notebooks/ — Polyglot notebooks, one per library; the fastest way to try the API without creating a project
  • benchmarks/ — BenchmarkDotNet results, and the two quadratic paths running them uncovered
  • Plan.md — the roadmap, and what is deliberately out of scope
  • Progress.md — what is done, verified, and still open

Install

dotnet add package Gravicode.OfficeNet          # everything
dotnet add package Gravicode.OfficeNet.WordNet  # or just the one you need

Quick start

Word

using WordNet;
using OfficeNet.Core;

using var doc = WordDocument.Create();
doc.Properties.Title = "Annual Report";

doc.Section.SetPageSize("A4");
doc.Section.SetMargins(Units.Cm(2.5));

doc.AddHeading("Annual Report", 0);
doc.AddParagraph("Prepared by Gravicode Studios.", "Subtitle");

doc.AddHeading("Summary", 1);
var p = doc.AddParagraph();
p.Alignment = ParagraphAlignment.Justify;
p.AddRun("Revenue grew ");
p.AddRun("32%", bold: true);
p.AddRun(" year on year.");

doc.AddList(["Word", "Excel", "PowerPoint", "PDF"]);

doc.AddTable(new[]
{
    new[] { "Region", "Revenue" },
    new[] { "Jakarta", "1,250" },
    new[] { "Bandung", "980" },
});

doc.Save("report.docx");
doc.SaveAsPdf("report.pdf");

Excel

using ExcelNet;
using ExcelNet.Styles;

using var wb = Workbook.Create("Sales");
var sheet = wb["Sales"];

sheet.WriteHeader("A1", ["Date", "Product", "Qty", "Price", "Total"]);

sheet["A2"].Set(new DateTime(2026, 1, 15));
sheet["B2"].Set("WordNet");
sheet["C2"].Set(12);
sheet["D2"].Set(85_000.0).WithNumberFormat(NumberFormats.Rupiah);
sheet["E2"].SetFormula("C2*D2").WithNumberFormat(NumberFormats.Rupiah);

sheet["E3"].SetFormula("SUM(E2:E2)");
wb.Recalculate();                 // fills the cached results Excel would compute on open

Console.WriteLine(sheet["E2"].Number);   // 1020000

sheet.AddColorScale("C2:C100", OfficeColor.Red, OfficeColor.Green);
sheet.AutoFitColumns();

wb.Save("sales.xlsx");
wb.SaveAsPdf("sales.pdf");

DataFrames. ExcelNet does not reimplement pandas — it bridges to GraviFrame, the pandas analogue Gravicode Studios already built:

using ExcelNet.DataFrames;

var frame = sheet.ToDataFrame();
var byRegion = frame.GroupBy("Region").Sum("Total");
wb.WriteDataFrame(byRegion, "Summary");

PowerPoint

using PowerPointNet;
using PowerPointNet.Charts;

using var deck = Presentation.Create();          // 16:9, master + 6 layouts + theme

deck.AddTitleSlide("OfficeNet", "Four libraries, one API");
deck.AddBulletSlide("Components", ["WordNet", "ExcelNet", "PowerPointNet", "PdfNet"]);

var slide = deck.AddSlide(2);
slide.SetTitle("Revenue by region");
slide.AddChart(new ChartData
{
    Type = ChartType.Column,
    Categories = ["Jakarta", "Bandung", "Surabaya"],
    Series = [new ChartSeries("2026", [150, 110, 105])],
    ValueFormat = "#,##0",
    ShowDataLabels = true,
});

deck.Save("deck.pptx");
deck.SaveAsPdf("deck.pdf");

HTML → slides, the feature PptxGenJS calls html2ppt:

using PowerPointNet.Html;

using var deck = HtmlToSlides.CreatePresentation(html, new HtmlSlideOptions
{
    TitleSlide = "Q1 Review",
    SplitOnHeadingLevel = 2,     // h1 and h2 start a new slide
});

Headings become slide titles, content below them becomes the body, and anything that does not fit paginates onto a continuation slide. Inline formatting — bold, italic, underline, colour, font, size, links — survives run by run. TableToSlides splits one large table across as many slides as it needs, repeating the header row.

PDF

using PdfNet.Document;
using PdfNet.Content;

// Merge, split, rotate
using var merged = PdfDocument.ConcatFiles(["a.pdf", "b.pdf"]);
merged.Pages.RotateAll(90);
merged.Save("merged.pdf");

// Extract
using var source = PdfDocument.Open("scan.pdf");
Console.WriteLine(source.ExtractText());
foreach (var image in source.Pages[0].ExtractImages())
    image.SaveTo("out");

// Draw
using var doc = PdfDocument.Create();
var page = doc.Pages.Add(PageSize.A4);
using (var canvas = page.OpenCanvas())
{
    canvas.TopDown = true;
    canvas.SetFont(StandardFont.HelveticaBold, 22);
    canvas.DrawText("Invoice", 50, 60);
}

// Encrypt — AES-256 by default
doc.Encrypt("user-password", "owner-password", PdfPermissions.Print);
doc.Save("invoice.pdf");

Forms fill and flatten, annotations and watermarks are one call each:

var form = AcroForm.Open(doc)!;
form.Fill(new Dictionary<string, string?> { ["name"] = "Kang Fadhil" });
form.Flatten();

page.AddHighlight([new PdfRectangle(50, 700, 200, 715)]);
page.AddWatermark("DRAFT");

Design notes

PdfNet is the leaf. Word, Excel and PowerPoint all export through it, so PDF export needs no extra dependency and behaves the same from all three.

Everything is one OPC container. .docx, .xlsx and .pptx differ only in which parts go inside; OfficeNet.Core implements the container once and all three inherit packaging, relationships, units, colour, image sniffing and metadata.

Parts the library does not model survive a round trip. Open a file, change one paragraph, save: macros, custom XML, pivot caches and vendor extensions all come back byte for byte.

Formatting is tri-state. null means inherit, false means explicitly off. That is what lets you write an unbolded word inside a bold heading — a distinction a plain bool cannot express.

Adding a format takes a handler, not a fork. Office consults a registry, so .vsdx, .one or something of your own joins Office.Open and Office.ExtractText by implementing one interface. Built-in formats always win, so a plugin can never change how existing files are read — details.

Verified against an independent reader. A .docx this library writes and this library reads proves nothing about whether Word can open it, so every format is checked by a validator that shares no code with the library: content-type coverage, relationship resolution, schema child order, and the format-specific invariants Office enforces.

Building

dotnet build OfficeNet.sln -c Release
dotnet test

389 tests, zero warnings.

What is not implemented

Honest gaps, tracked in Progress.md and Plan.md:

  • Video export is deliberately absent: encoding means FFmpeg, which is a native binary, and OfficeNet.Rendering's only native dependency is SkiaSharp. The docs give the ffmpeg line to run over rendered slides instead.
  • PDF → Word/Excel is a reconstruction, not a conversion. A PDF has no paragraphs and no tables, so structure is inferred from where the glyphs landed; what the heuristics miss comes back as paragraphs, and no text is ever dropped. What it does and does not catch.
  • Word→PDF floating objects wrap around a bounding box rather than an outline, and a line breaks around one object rather than several. Hyphenation is not implemented.
  • Font embedding takes TrueType outlines. OpenType fonts with PostScript outlines (.otf with a CFF table) and TrueType collections (.ttc) are refused by name rather than loaded into a PDF with no glyphs in it.
  • Digital signatures are adbe.pkcs7.detached. No trusted timestamp, revocation response or long-term-validation archive — those need a network service, and their absence is why a signature checked years from now may fail even though nothing was tampered with.
  • Formulas do not do array formulas, iterative calculation or cross-workbook references.
  • A pivot table writes its cache and layout; Excel computes the result grid when it opens the file, so a non-Excel consumer sees that area empty. Why.
  • The renderer draws paths, images, text, clipping paths and gradients, and uses the file's own embedded font when that font is TrueType. It does not do tiling patterns, soft masks, transparency groups or mesh shadings, and a CFF or Type 1 font still falls back to a system face. It is for thumbnails and previews, not a viewer. Tracked in Plan.md.

Licence

MIT. Dibuat oleh Gravicode Studios, dipimpin oleh Kang Fadhil.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
1.3.0 80 9/9/2026
1.1.0 72 9/9/2026
1.0.0 96 9/7/2026