ZingPDF logo

Developer Documentation

ZingPDF docs

Reference material and integration guidance for the core API surface.

Quick Start

Load, create, edit, and save

The main entry points are Pdf.Load(...) for existing documents and Pdf.Create(...) for new ones.

Load an existing PDF

using var input = File.OpenRead("input.pdf");
using var pdf = Pdf.Load(input);

var pageCount = await pdf.GetPageCountAsync();
var firstPage = await pdf.GetPageAsync(1);

Create a blank PDF

using var pdf = Pdf.Create(options =>
{
    options.MediaBox = Rectangle.FromDimensions(595, 842);
});

using var output = File.Create("blank.pdf");
await pdf.SaveAsync(output);

Append, insert, and delete pages

using var pdf = Pdf.Load(File.OpenRead("input.pdf"));

await pdf.AppendPageAsync(options =>
{
    options.MediaBox = Rectangle.FromDimensions(595, 842);
});

await pdf.InsertPageAsync(1, options =>
{
    options.MediaBox = Rectangle.FromDimensions(300, 300);
});

await pdf.DeletePageAsync(2);
await pdf.SaveAsync(File.Create("pages-updated.pdf"));

Text extraction

var textItems = await pdf.ExtractTextAsync();
foreach (var item in textItems)
{
    Console.WriteLine(item.Text);
}

Watermarking and compression

await pdf.AddWatermarkAsync("DRAFT");
pdf.Compress(dpi: 72, quality: 75);
await pdf.SaveAsync(output);

Packages

NuGet packages and support scope

The ZingPDF solution is split into a small set of packages and support projects with different runtime expectations. If you are choosing what to ship, start here.

ZingPDF

The main PDF library for loading, creating, editing, merging, watermarking, compression, forms, metadata, and encryption.

  • Target framework: net8.0
  • Intended role: primary package for most users
  • Compatibility goal: cross-platform on Windows, Linux, and macOS
  • Current notes: depends on SkiaSharp and ImageSharp, so runtime validation across operating systems matters

ZingPDF.FromHTML

Optional HTML-to-PDF support layered on top of the main package.

  • Target framework: net8.0
  • Intended role: optional add-on, not the default package
  • Compatibility goal: cross-platform in principle, but operationally heavier because it relies on browser automation
  • Current notes: keep this separate from the core package when documenting deployment requirements

Support recommendations

  • For application integrations, prefer ZingPDF unless you specifically need HTML conversion.
  • Treat ZingPDF.FromHTML as a separate deployment concern with its own operational requirements.
  • Expect the core library to remain net8.0-first until the dependency surface is slimmed enough to justify broader multi-targeting.
  • Validate your exact deployment platform if your workflow depends on image handling, font metrics, or browser automation.

API reference

The symbol-by-symbol reference now lives on a dedicated static page generated from the XML docs and source signatures.

Open the API reference

Metadata

Inspect and update document info safely

Use GetMetadataAsync() to read or update the trailer Info dictionary through a higher-level wrapper.

  • Editable fields: Title, Author, Subject, Keywords, Creator, and CreationDate.
  • Save-managed fields: Producer is stamped to ZingPDF and ModifiedDate is refreshed on save.
  • If no info dictionary exists, ZingPDF creates one during save.
  • Date values may be read from either PDF date objects or strings.
var metadata = await pdf.GetMetadataAsync();
metadata.Title = "Quarterly Report";
metadata.Author = "Taylor Smith";
metadata.Subject = "Q1 FY2026";
metadata.Keywords = "finance,quarterly";
metadata.Creator = "Back Office Importer";
metadata.CreationDate = new DateTimeOffset(2026, 3, 1, 9, 0, 0, TimeSpan.Zero);

await pdf.SaveAsync(output);

Forms

AcroForm access with typed field wrappers

If a document contains an AcroForm, GetFormAsync() returns a Form wrapper that can enumerate terminal fields and expose typed behavior for supported field families.

Field discovery

  • Form.GetFieldsAsync() returns terminal fields as IFormField instances.
  • Nested names are flattened into dot-separated paths like Applicant.Address.Suburb.
  • Shared field metadata includes name, description, field flags, and field dimensions.

Recommended typed pattern

var form = await pdf.GetFormAsync();
if (form is null)
{
    return;
}

foreach (var field in await form.GetFieldsAsync())
{
    switch (field)
    {
        case TextFormField textField when textField.Name == "Applicant.Name":
            await textField.SetValueAsync("Taylor Smith");
            break;

        case ChoiceFormField choiceField when choiceField.Name == "Applicant.State":
            var options = await choiceField.GetOptionsAsync();
            var selected = options.FirstOrDefault(x => x.Text.DecodeText() == "NSW");
            if (selected is not null)
            {
                await selected.SelectAsync();
            }
            break;
    }
}

Text fields

TextFormField currently has the richest editing support.

  • GetValueAsync()
  • SetValueAsync(string?)
  • ClearAsync()

Choice and button fields

Choice items and selectable button options can be read and toggled through option wrappers like ChoiceItem and SelectableOption.

Current public limitations

  • Push-button actions are not yet exposed through the high-level API.
  • Signature fields are discoverable, but high-level signing is not yet implemented.
  • Unusual viewer-specific appearance behavior may still require lower-level object work.

Encryption

Password-protected workflows

ZingPDF supports authenticating encrypted PDFs, applying password protection to plain PDFs, and saving decrypted output from encrypted input.

Open an encrypted PDF

using var pdf = Pdf.Load(File.OpenRead("encrypted.pdf"));

await pdf.AuthenticateAsync("password");
var pageCount = await pdf.GetPageCountAsync();

Encrypt a previously unencrypted PDF

using var pdf = Pdf.Create();

await pdf.EncryptAsync("user-password", "owner-password");
await pdf.SaveAsync(File.Create("protected.pdf"));

Decrypt an encrypted PDF

using var pdf = Pdf.Load(File.OpenRead("encrypted.pdf"));

await pdf.DecryptAsync("password");
await pdf.SaveAsync(File.Create("decrypted.pdf"));

Save Behavior

Understand the incremental save model

ZingPDF saves by writing an incremental update. That gives you a predictable editing model, but it comes with a few practical constraints you should understand before shipping at scale.

  1. The input stream passed to Pdf.Load(...) must be seekable.
  2. The output stream passed to SaveAsync(...) must be writable and seekable.
  3. If saving to a different stream, that stream must be empty.
  4. If saving back to the original stream, ZingPDF appends a new incremental revision.

Form updates and metadata stamping are both applied as part of the save pipeline.

using var pdf = Pdf.Load(File.OpenRead("input.pdf"));

await pdf.AddWatermarkAsync("INTERNAL");
await pdf.SaveAsync(File.Create("output.pdf"));

Implementation Notes

The details most likely to affect production usage

  • Encryption currently writes Standard security handler encryption using RC4 with V=2 and R=3.
  • DecryptAsync(...) removes encryption in the latest saved revision, but older encrypted revisions may still exist in the file bytes because saves are incremental.
  • Compress(...) currently compresses unfiltered streams and can recompress JPEG image streams.
  • DecompressAsync() skips JPEG image streams to avoid forced decompression corruption.
  • InsertPageAsync(...) inserts before the requested page number, while AppendPageAsync(...) adds to the end.

Low-Level Access

Drop into the object model when the high-level API is not enough

If you need lower-level control, IPdf.Objects exposes the underlying PDF object collection and page tree. Most application code should prefer the higher-level Pdf and Page APIs first, but the lower-level surface is there for advanced integrations.