Ank.DocToolkit 0.3.1

There is a newer version of this package available.
See the version list below for details.
dotnet add package Ank.DocToolkit --version 0.3.1
                    
NuGet\Install-Package Ank.DocToolkit -Version 0.3.1
                    
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="Ank.DocToolkit" Version="0.3.1" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Ank.DocToolkit" Version="0.3.1" />
                    
Directory.Packages.props
<PackageReference Include="Ank.DocToolkit" />
                    
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 Ank.DocToolkit --version 0.3.1
                    
#r "nuget: Ank.DocToolkit, 0.3.1"
                    
#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 Ank.DocToolkit@0.3.1
                    
#: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=Ank.DocToolkit&version=0.3.1
                    
Install as a Cake Addin
#tool nuget:?package=Ank.DocToolkit&version=0.3.1
                    
Install as a Cake Tool

DocToolkit

Convert HTML to DOCX and PDF, and open/edit DOCX, XLSX and PPTX from .NET.

Pure managed. No native binaries, no browser, no LibreOffice, no Office interop. Works after dotnet restore alone, and runs on Linux.

Offline by default — safe in air-gapped environments

No method on DocToolkit's public API opens a network connection. Not for images, not for stylesheets, not for fonts, not for linked pictures or external workbook references. Once the package is restored, DocToolkit never needs the network again.

There is exactly one way to change that, and you have to ask for it by name:

// The ONLY API that makes an outbound request. It downloads and embeds the images the markup
// names, so it FAILS in an air-gapped environment - a host that will not answer fails the whole
// conversion, after a connect timeout. Leave it alone unless your machines have internet access.
byte[] docx = await HtmlToDocxConverter.ConvertAsync(html, allowRemoteImageDownload: true, ct);
byte[] pdf  = await HtmlToPdfConverter.ConvertAsync(html, allowRemoteImageDownload: true, ct);

Everything else — ConvertAsync(html), ConvertToFileAsync, DocxToPdfConverter, DocxEditor, WorkbookEditor, PresentationEditor — is offline, unconditionally.

This is enforced, not merely intended. The test suite starts a real TCP listener on loopback, feeds every public API markup that names it as an <img src>, a <link rel="stylesheet">, a CSS @import, a background-image, an <a href>, an externally linked DOCX picture, an external XLSX workbook link and more, and requires the accepted-connection count to be exactly zero. A companion test points the same APIs at an unroutable address (TEST-NET-3) and requires them to return promptly rather than stall on a connect timeout.

dotnet restore is the one step that still needs a package feed. THIRD-PARTY-NOTICES.txt lists the full dependency closure with resolved versions, so it can be mirrored onto an internal feed; every entry is a plain managed assembly with no native payload and no post-restore download.

Install

dotnet add package Ank.DocToolkit

Targets net8.0 and net10.0.

Usage

using DocToolkit;

// HTML -> DOCX
byte[] docx = await HtmlToDocxConverter.ConvertAsync("<h1>Invoice</h1><p>Total: 18,100.00</p>");

// HTML -> PDF (pivots through DOCX internally)
byte[] pdf = await HtmlToPdfConverter.ConvertAsync("<h1>Invoice</h1><p>Total: 18,100.00</p>");

// DOCX -> PDF
byte[] rendered = DocxToPdfConverter.Convert(docx);

// Fill a DOCX template - body, headers, footers, footnotes, endnotes and text boxes
byte[] filled = DocxEditor.ReplaceText(docx, new Dictionary<string, string>
{
    ["{{customer}}"] = "Contoso Ltd",
});
string text = DocxEditor.ExtractText(filled);                                 // body only
string all  = DocxEditor.ExtractText(filled, includeHeadersAndFooters: true);

// Spreadsheets
byte[] xlsx = WorkbookEditor.Create("Sales", new[]
{
    new object?[] { "Region", "Total" },
    new object?[] { "North", 1200 },
});
string cell = WorkbookEditor.ReadCell(xlsx, "Sales", "B2");
byte[] updated = WorkbookEditor.SetCell(xlsx, "Sales", "B2", 1500);

// Presentations
byte[] pptx = File.ReadAllBytes("deck.pptx");
int slides = PresentationEditor.SlideCount(pptx);
IReadOnlyList<string> slideText = PresentationEditor.ExtractText(pptx);   // in deck order
byte[] editedPptx = PresentationEditor.ReplaceText(pptx, new Dictionary<string, string>
{
    ["{{title}}"] = "Q3 Results",
});

Placeholder replacement

DocxEditor.ReplaceText and PresentationEditor.ReplaceText substitute against the concatenated text of each paragraph, because Word and PowerPoint routinely split a single visible word across several runs — a per-run string.Replace would miss {{name}} whenever it straddles a boundary.

The result is spliced back into only the runs a match actually overlaps, so:

  • runs outside a match keep their text and their formatting;
  • hyperlinks and text boxes are left alone unless they contain a placeholder themselves;
  • when a placeholder does straddle runs, the value lands in the run holding its first character and inherits that run's formatting.

Keys are matched in one left-to-right pass, longest key first at any given offset, so a substituted value is never rescanned for further placeholders.

How the no-network guarantee is built

HtmlToOpenXml, the HTML parser underneath, defaults to downloading every image it sees, and its resource loader also speaks file:// — so left alone it would give every caller of a byte[]-in/byte[]-out API an SSRF reach, a read of the host's disk, and an unbounded hang. DocToolkit shuts that off in two independent places on the default path:

  1. Image processing is set to EmbedDataUriOnly. Only data: URI images are embedded; http, https and file sources are skipped.
  2. The resource loader is replaced with one that supports no protocol and fetches nothing. The component capable of making a request is never constructed, so the guarantee does not rest on what a future release decides EmbedDataUriOnly means. It also keeps the default path away from HtmlToOpenXml 3.5.0's process-wide static HttpClient, which is not thread-safe.

Self-contained documents still convert in full: data: URI images are decoded by the parser and never go through the loader.

The other converters and editors need no such handling — DocumentFormat.OpenXml, ClosedXML and OfficeIMO do not resolve external relationships, external workbook links or remote fonts. That is asserted, not assumed; see above.

Errors

Every public method reports failure as DocumentConversionException, with the underlying library exception as InnerException. Bad arguments (null, empty, blank) still surface as ArgumentNullException/ArgumentException, and a cancelled CancellationToken as OperationCanceledException.

Why HTML to PDF goes through DOCX

No permissively-licensed, NuGet-only library renders HTML to PDF on Linux: the only free renderers are browsers, and a browser is a native binary. Pivoting through DOCX keeps the whole chain pure managed.

Licence

MIT. See THIRD-PARTY-NOTICES.txt for dependency attribution — in particular the pinned SixLabors.Fonts 1.0.0, which is the last Apache-2.0 release of that package.

Product Compatible and additional computed target framework versions.
.NET net8.0 is compatible.  net8.0-android was computed.  net8.0-browser was computed.  net8.0-ios was computed.  net8.0-maccatalyst was computed.  net8.0-macos was computed.  net8.0-tvos was computed.  net8.0-windows was computed.  net9.0 was computed.  net9.0-android was computed.  net9.0-browser was computed.  net9.0-ios was computed.  net9.0-maccatalyst was computed.  net9.0-macos was computed.  net9.0-tvos was computed.  net9.0-windows was computed.  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 (1)

Showing the top 1 NuGet packages that depend on Ank.DocToolkit:

Package Downloads
Ank.DocToolkit.Extensions.DependencyInjection

Dependency-injection registration for Ank.DocToolkit. services.AddDocToolkit() registers six injectable interfaces (IHtmlToDocxConverter, IDocxToPdfConverter, IHtmlToPdfConverter, IDocxEditor, IWorkbookEditor, IPresentationEditor) over the same pure-managed HTML/DOCX/ PDF/XLSX/PPTX conversion and editing logic, for ASP.NET Core and worker-service consumers.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.9.0 0 8/6/2026
0.8.0 0 8/6/2026
0.7.0 128 8/5/2026
0.6.0 88 8/4/2026
0.5.0 126 8/3/2026
0.4.0 112 8/3/2026
0.3.12 97 8/3/2026
0.3.11 84 8/3/2026
0.3.10 63 8/3/2026
0.3.9 89 8/3/2026
0.3.8 72 8/3/2026
0.3.7 83 8/3/2026
0.3.6 92 8/3/2026
0.3.5 82 8/3/2026
0.3.4 62 8/3/2026
0.3.3 55 8/3/2026
0.3.2 179 8/3/2026
0.3.1 57 8/3/2026
0.3.0 59 8/3/2026
0.2.2 59 8/3/2026
Loading failed