Unchained.Pdf 0.1.0-rc.4

This is a prerelease version of Unchained.Pdf.
dotnet add package Unchained.Pdf --version 0.1.0-rc.4
                    
NuGet\Install-Package Unchained.Pdf -Version 0.1.0-rc.4
                    
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="Unchained.Pdf" Version="0.1.0-rc.4" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Unchained.Pdf" Version="0.1.0-rc.4" />
                    
Directory.Packages.props
<PackageReference Include="Unchained.Pdf" />
                    
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 Unchained.Pdf --version 0.1.0-rc.4
                    
#r "nuget: Unchained.Pdf, 0.1.0-rc.4"
                    
#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 Unchained.Pdf@0.1.0-rc.4
                    
#: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=Unchained.Pdf&version=0.1.0-rc.4&prerelease
                    
Install as a Cake Addin
#tool nuget:?package=Unchained.Pdf&version=0.1.0-rc.4&prerelease
                    
Install as a Cake Tool

Unchained.Pdf

MIT-licensed PDF engine for .NET. Load, save, extract text, generate tables, merge documents, add annotations, fill forms, sign, encrypt, validate PDF/A, validate PDF/UA, produce linearized (web-optimized) output, generate tagged accessible PDFs, and import from Markdown, plain text, or SVG — all in pure managed code, no native dependencies.

Targets: net8.0 · net9.0 · net10.0
License: MIT


Installation

<PackageReference Include="Unchained.Pdf" Version="0.1.0" />

For page rendering to PNG, install Unchained.Pdf.Rendering instead — it depends on this package.


Usage

Load & save

using Unchained.Pdf.Engine;

var processor = new DocumentProcessor();

// From file or stream
await using var doc = await processor.LoadAsync("invoice.pdf");
await using var fromStream = await processor.LoadAsync(myStream);

// Password-protected
await using var secured = await processor.LoadAsync("secure.pdf", password: "1234");

// Save
await processor.SaveAsync(doc, "output.pdf");
await processor.SaveAsync(doc, outputStream);

Text extraction

// Plain text
string text = doc.Pages[1].ExtractText();

// Positioned spans with font name, size, and coordinates
IReadOnlyList<TextSpan> spans = doc.Pages[1].GetTextSpans();

Content operators

// Raw PDF content operators for advanced use
IReadOnlyList<ContentOperator> ops = doc.Pages[1].GetContentOperators();

Table generation

var generator = new TableGenerator();
var data = new TableData
{
    Headers = ["Name", "Amount"],
    Rows    = [["Alice", "$1,200"], ["Bob", "$950"]]
};
await using var tableDoc = await generator.GenerateAsync(data, TableStyle.Default);
await processor.SaveAsync(tableDoc, "report.pdf");

Document merging

var merger = new DocumentMerger();
await using var merged = await merger.MergeAsync([doc1, doc2, doc3], MergeOptions.Default);

Stamps & watermarks

var applier = new StampApplier();
await applier.StampAsync(doc,
    new TextStamp("DRAFT", X: 150, Y: 400, FontSize: 60f, GrayLevel: 0.8f,
                  RotationDegrees: 45f, IsBackground: true));

Annotations

var editor = new AnnotationEditor();
await editor.AddAnnotationAsync(doc, pageNumber: 1,
    new Annotation(AnnotationSubtype.Text, X: 72, Y: 720, Width: 200, Height: 40,
                   Contents: "Please review"));

// Export/import XFDF
var xfdfEditor = new XfdfEditor();
string xfdf = xfdfEditor.ExportAnnotationsToXfdf(doc);
await xfdfEditor.ImportAnnotationsFromXfdfAsync(doc, xfdfXml);

Bookmarks

var bookmarkEditor = new BookmarkEditor();
await bookmarkEditor.SetBookmarksAsync(doc,
[
    new Bookmark("Introduction", PageNumber: 1),
    new Bookmark("Chapter 1",    PageNumber: 5)
]);

IReadOnlyList<Bookmark> bookmarks = doc.GetBookmarks();

Form filling

var filler = new FormFiller();
IReadOnlyList<FormField> fields = doc.GetFormFields();

await filler.FillAsync(doc, new Dictionary<string, string>
{
    ["FirstName"] = "Alice",
    ["LastName"]  = "Smith"
});

await filler.FlattenAsync(doc); // embed field values into page content

Digital signatures

using var cert = X509CertificateLoader.LoadPkcs12File("cert.pfx", "pass");

// Sign
await processor.SignAsync(doc, cert, "signed.pdf",
    new SignatureOptions(Reason: "Approved", Location: "Berlin"));

// Verify
var signatures = await processor.VerifySignaturesAsync(pdfBytes);
foreach (var sig in signatures)
    Console.WriteLine($"{sig.SignerName}: valid={sig.IsSignatureValid}");

Encryption

// Encrypt
await processor.SaveAsync(doc, "secure.pdf",
    new SaveOptions(Encryption: new EncryptionOptions(
        UserPassword:  "user",
        OwnerPassword: "owner",
        Algorithm:     PdfEncryptionAlgorithm.Aes256)));

// Decrypt on load — transparent
await using var open = await processor.LoadAsync("secure.pdf", password: "user");

// Change passwords
using var ms = new MemoryStream();
await processor.ChangePasswordsAsync(doc, "newUser", "newOwner", ms);

PDF/A validation & conversion

// Validate
var result = await processor.ValidatePdfAAsync(pdfBytes, PdfAProfile.PdfA1B);
Console.WriteLine(result.IsConformant);
foreach (var violation in result.Errors)
    Console.WriteLine($"[{violation.RuleId}] {violation.Description}");

// Convert
using var output = new MemoryStream();
await processor.ConvertToPdfAAsync(doc, output, PdfAProfile.PdfA1B);

PDF/UA validation

Validates against ISO 14289-1 (PDF/UA-1). Checks tagged-PDF marker, document language, structure tree root, parent tree, figure alt text, heading level sequence, table and list structure, untagged content, annotation accessible names, action restrictions, and XMP pdfuaid metadata.

var result = await processor.ValidatePdfUAAsync(pdfBytes);
Console.WriteLine(result.IsConformant);
foreach (var v in result.Violations)
    Console.WriteLine($"[{v.RuleId}] {v.Severity}: {v.Description}");

Linearization (web-optimized output)

Produces a linearized PDF (ISO 32000-1 Annex F) so that PDF readers can render the first page before the full file downloads. Includes a hint stream, two xref sections, and the linearization parameter dictionary in the first 1024 bytes.

// Via SaveOptions
await processor.SaveAsync(doc, "fast.pdf", new SaveOptions(Linearize: true));

// Via preset
await processor.SaveAsync(doc, "fast.pdf", SaveOptions.WebOptimized);

Tagged PDF (accessibility)

Produces tagged PDFs with a full ISO 32000-1 §14.7 structure tree when converting from text, Markdown, or SVG. Tagged output passes ValidatePdfUAAsync §7.2, §7.4, and §7.5 checks. Set Tagged: true on the load options and supply a BCP 47 language tag.

// Plain text → tagged PDF
await using var txt = await processor.LoadFromTxtAsync(
    "Accessible content",
    new TxtLoadOptions(Tagged: true, Language: "en-US"));

// Markdown → tagged PDF (H1–H6, P, Code, L/LI/LBody)
await using var md = await processor.LoadFromMarkdownAsync(
    "# Title\n\nParagraph text.\n\n- Item 1\n- Item 2",
    new MdLoadOptions(Tagged: true, Language: "en-US"));

// SVG → tagged PDF (/Figure with /Alt text)
await using var svg = await processor.LoadFromSvgAsync(
    svgString,
    new SvgLoadOptions(Tagged: true, Language: "en-US", AltText: "Chart showing sales data"));

// Validate the result
using var ms = new MemoryStream();
await processor.SaveAsync(md, ms);
var uaResult = await processor.ValidatePdfUAAsync(ms.ToArray());

Format imports

// Plain text → PDF (word-wrap, pagination, configurable font/margins)
await using var txt = await processor.LoadFromTxtAsync(
    "Long text content...",
    new TxtLoadOptions(FontSize: 12, PageMargin: 72));

// Markdown → PDF (headings, bold/italic, lists, code, thematic breaks)
await using var md = await processor.LoadFromMarkdownAsync(
    "# Title\n\n- Item 1\n- Item 2\n\n**Bold text**");

// SVG → PDF (shapes, paths, text, transforms, viewBox)
await using var svg = await processor.LoadFromSvgAsync(svgString);

Viewer preferences & metadata

// Viewer preferences
var prefEditor = new ViewerPreferencesEditor();
await prefEditor.SetViewerPreferencesAsync(doc, new ViewerPreferences(HideToolbar: true));
await prefEditor.SetPageLayoutAsync(doc, PageLayout.TwoColumnLeft);

// XMP metadata
var xmpEditor = new XmpMetadataEditor();
await xmpEditor.SetXmpMetadataAsync(doc, "<x:xmpmeta>...</x:xmpmeta>");
string? xmp = doc.GetXmpMetadata();

// /Info metadata (Title, Author, Subject, Keywords, Creator, Producer)
await processor.SetMetadataAsync(doc,
    new DocumentMetadata(
        Title:    "Annual Report",
        Author:   "Alice",
        Subject:  "Finance",
        Keywords: "report finance annual",
        Creator:  null,   // null = leave unchanged
        Producer: null,
        CreationDate:     null,
        ModificationDate: null));

// Named destinations
var destEditor = new NamedDestinationEditor();
await destEditor.SetDestinationAsync(doc, "toc", pageNumber: 3);

Optimization & repair

var optimizer = new DocumentOptimizer();
await optimizer.OptimizeAsync(doc);          // compress uncompressed streams
await optimizer.OptimizeResourcesAsync(doc); // deduplicate identical objects

// Recover from corrupted files
await using var repaired = await processor.RepairAsync(corruptedBytes);

All stream filters — pure managed

FlateDecode · LZWDecode · CCITTFaxDecode · ASCIIHexDecode · ASCII85Decode · RunLengthDecode · DCTDecode (JPEG) · JBIG2Decode · JPXDecode (JPEG 2000)


License

MIT. No AGPL/GPL dependencies. Safe for commercial and open-source use.

GitHub · Report an issue

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 is compatible.  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 Unchained.Pdf:

Package Downloads
Unchained.Pdf.Rendering

Package Description

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.1.0-rc.4 0 6/20/2026