-
Notifications
You must be signed in to change notification settings - Fork 0
Installation
-
.NET 10 (
net10.0). The library targets .NET 10 and uses nothing beyond the base class library —System.IO.CompressionandSystem.Xml.Linqare the whole of what it builds on. - Fonts. By default the converter discovers the platform's installed fonts (macOS, Windows and Linux font directories). For reproducible output regardless of what a machine has installed, register fonts explicitly instead — see below.
There is no native code, no external process, and no service to stand up. The assembly is self-contained by construction: the project fails its own build if a PackageReference is ever added (Promises).
NuGet (pending). The package id is n8PDF and the release pipeline builds, tests, and packs it (with symbols and XML documentation) on every release tag — but it has not yet been published to NuGet (#61). Once it is:
dotnet add package n8PDFFrom source (today).
git clone https://github.com/nathanpond/n8PDF.git
dotnet build n8PDF/src/n8PDF --configuration ReleaseThen either reference the project directly:
<ProjectReference Include="path/to/n8PDF/src/n8PDF/n8PDF.csproj" />or pack it locally and consume the .nupkg:
dotnet pack n8PDF/src/n8PDF -c ReleaseBuilds are deterministic — the same input builds the same assembly, whoever builds it.
using n8PDF;
Converter.ConvertFile("report.docx", "report.pdf");Streams and byte arrays work too:
byte[] pdf = Converter.Convert(File.ReadAllBytes("report.docx"));
using var input = File.OpenRead("report.docx");
using var output = File.Create("report.pdf");
Converter.Convert(input, output);Every knob lives on ConversionOptions, passed as the optional last argument. The defaults are chosen so that a plain call does the right thing; see The API for the full surface.
var options = new ConversionOptions
{
Title = "Quarterly Report", // PDF information dictionary
PdfA = true, // claim and honour PDF/A-2b
CreationDate = DateTimeOffset.Parse("2026-01-01T00:00:00Z"), // byte-identical output
};
Converter.ConvertFile("report.docx", "report.pdf", options);Leaving Fonts null discovers the platform's fonts — read once per process and shared, so only the first conversion pays the scan (~600ms for a typical system collection; conversions after that pay nothing, about 1.4ms for a page of text). To make output identical across machines, register exactly the faces you mean:
var fonts = new FontLibrary { UseSystemFonts = false };
fonts.RegisterFile("fonts/TimesNewRoman.ttf");
fonts.RegisterDirectory("fonts/", recursive: true);
Converter.ConvertFile("report.docx", "report.pdf", new ConversionOptions { Fonts = fonts });Registering a file that is not a font throws FontFormatException. Keep and reuse the library — anything registered into it is registered once.
A .docx from an untrusted source is attacker-controlled input. Set Limits and catch PackageTooLargeException:
var options = new ConversionOptions
{
Limits = new PackageLimits
{
MaximumPartBytes = 32 * 1024 * 1024, // per decompressed part
MaximumTotalBytes = 128 * 1024 * 1024, // across the package
MaximumPartCount = 1024,
MaximumImagePixels = 50_000_000, // the default: a 600dpi A4 scan with room to spare
MaximumFontBytes = 16 * 1024 * 1024, // an embedded face past this is left out
}
};
try
{
Converter.ConvertFile(untrusted, output, options);
}
catch (PackageTooLargeException)
{
// The document asked to decompress past the bounds you set.
}Read Security before putting untrusted documents through any converter, this one included — it states plainly what is defended and what is still open.
A document written for a mail merge names a data source only the machine it was written on can reach. Converted as it stands, its fields show what Word shows — «FieldName» in guillemets. Give it a record and the letter fills itself in:
var record = new MailMergeRecord(new Dictionary<string, string>
{
["Title"] = "Dr", ["LastName"] = "Hopper"
});
Converter.ConvertFile("letter.docx", "letter.pdf", new ConversionOptions { MergeRecord = record });Text around a field prints only where the field has something to print, exactly as Word does it.
Using n8PDF
What it does
How it works
Contributing