ZingPDF logo

Docs

ZingPDF docs

Curated documentation for the main API surface, fluent authoring, package choices, and PDF behavior.

Quick Start

Load, create, edit, and save

Start by installing the package, importing the core namespaces, and deciding whether you are loading an existing PDF or creating a new one from scratch. The main entry points are Pdf.Load(...) for existing documents, Pdf.Create(...) for low-level blank documents, and Pdf.New() for the fluent authoring surface.

Install the package

dotnet add package ZingPDF

Import the namespaces used in the examples

using ZingPDF;
using ZingPDF.Syntax.CommonDataStructures;

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);

Author a new PDF fluently

await Pdf.New()
    .Page(page => page
        .Size(595, 842)
        .Text(text => text
            .Value("Monthly delivery report")
            .HelveticaBold()
            .FontSize(24)
            .At(48, 780))
        .Rectangle(box => box
            .At(48, 720)
            .Size(220, 40)
            .Stroke(RGBColour.PrimaryBlue, 1)
            .Fill(new RGBColour(0.9, 0.97, 1)))
        .Text(text => text
            .Value("Generated with the fluent authoring API")
            .Helvetica()
            .FontSize(11)
            .InBox(60, 730, 196, 20)
            .AlignStart()
            .AlignMiddle()
            .Padding(0)))
    .SaveToFileAsync("authored.pdf");

Pdf.New() is a builder for authored pages. It covers page sizing, text, shapes, paths, images, watermarks, boxed text alignment, wrapping, and font registration through the same core document APIs. Use pdf.Pages(...) when you want the same page-level fluent operations on an existing document.

Use the standard API when you are loading an existing PDF, working directly with Pdf and Page, or need explicit control over each step. Use the fluent API when you are building a new document from authored content and want the page layout to read top to bottom.

Edit an existing PDF

Standard API:

using System.Text.RegularExpressions;

using var pdf = Pdf.Load(File.OpenRead("input.pdf"));
var font = await pdf.RegisterStandardFontAsync(StandardPdfFonts.HelveticaBold);

var firstPage = await pdf.GetPageAsync(1);
await firstPage.AddTextAsync(
    "Approved",
    Rectangle.FromCoordinates(
        new Coordinate(48, 780),
        new Coordinate(168, 804)),
    font,
    18,
    RGBColour.Black);

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

await summaryPage.AddTextAsync(
    "Summary",
    Rectangle.FromCoordinates(
        new Coordinate(48, 780),
        new Coordinate(220, 808)),
    font,
    24,
    RGBColour.Black);

await pdf.SaveAsync(File.Create("edited.pdf"));

Fluent API:

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

await pdf.Pages(pages => pages
        .Page(1, page => page
            .Text(text => text
                .Value("Approved")
                .HelveticaBold()
                .FontSize(18)
                .At(48, 780)))
        .Append(page => page
            .Size(595, 842)
            .Text(text => text
                .Value("Summary")
                .HelveticaBold()
                .FontSize(24)
                .At(48, 780))))
    .SaveAsync(File.Create("edited.pdf"));

Remove(...) and Delete(...) are also available when you want to drop pages from an existing document.

Dedicated guide: How to create PDFs with the fluent authoring API in C#.

When saving, use an output stream that is writable and seekable. If you save to a different stream than the input stream, it must also be empty.

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"));

Export selected pages or split a document

using var pdf = Pdf.Load(File.OpenRead("input.pdf"));
using var selectedPages = await pdf.ExportPagesAsync([1, 3, 5]);
using var selectedOutput = File.Create("selected-pages.pdf");

await selectedPages.SaveAsync(selectedOutput);

var parts = await pdf.SplitAsync(10);

try
{
    for (var index = 0; index < parts.Count; index++)
    {
        using var output = File.Create($"part-{index + 1}.pdf");
        await parts[index].SaveAsync(output);
    }
}
finally
{
    foreach (var part in parts)
    {
        part.Dispose();
    }
}

Text extraction

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

Watermarks and compression

using var output = File.Create("watermarked.pdf");

var firstPage = await pdf.GetPageAsync(1);
await firstPage.AddWatermarkAsync("DRAFT");

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

Page.AddWatermarkAsync(...) targets one page. Pdf.AddWatermarkAsync(...) applies the same text across the whole document.

Related guides: Create a blank PDF, Insert, append, and delete pages, Export selected pages or split a document, Extract text, Add watermarks, and Compress output.

Runnable examples: CreateBlankPdf and CreateProjectStatusReport.

Packages

NuGet packages

ZingPDF ships as a small set of packages. Use the core package unless you specifically need HTML rendering, Liquid HTML templates, Google Fonts, or OCR support for scanned or image-based pages.

Which package should I install?

Start with ZingPDF. Add ZingPDF.FromHTML for HTML-to-PDF, ZingPDF.Templates.LiquidHtml for Liquid HTML templates, ZingPDF.GoogleFonts for Google Fonts, and ZingPDF.OCR for scanned or image-based pages.

ZingPDF

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

  • Target framework: net8.0
  • Use for most applications
  • Runs on Windows, Linux, and macOS
  • Depends on SkiaSharp and ImageSharp, so test on your target platform

ZingPDF.FromHTML

HTML-to-PDF package for Chromium-based rendering.

  • Target framework: net8.0
  • Use for HTML-to-PDF conversion
  • Cross-platform in principle, but heavier because it relies on browser automation
  • Keep its deployment requirements separate from the core package

ZingPDF.Templates

Shared source and diagnostic types for template renderer packages.

  • Target framework: net8.0
  • Use when building or referencing renderer packages
  • No dependency on HTML, Liquid, or browser automation
  • Contains template sources, diagnostics, and render exceptions

ZingPDF.Templates.LiquidHtml

Liquid HTML template package for creating PDFs from data models.

  • Target framework: net8.0
  • Uses Fluid for Liquid rendering
  • Uses ZingPDF.FromHTML for HTML-to-PDF conversion
  • Has the same browser automation requirements as ZingPDF.FromHTML

ZingPDF.GoogleFonts

Google Fonts integration package for registering Google Fonts in a PDF document.

  • Target framework: net8.0
  • Use for fetching Google Fonts at document build time
  • Cross-platform with outbound HTTPS access
  • Requires a Google Fonts Developer API key at registration time

ZingPDF.OCR

OCR companion package for scanned and image-based pages, with options for embedded-text-first or OCR-first workflows.

  • Target framework: net8.0
  • Use for OCR-driven text extraction on scanned or image-based pages
  • Best fit for image-based pages and supported image XObjects
  • Ships with a Tesseract-backed engine option

Package selection notes

  • For application integrations, prefer ZingPDF unless you specifically need HTML conversion.
  • Use ZingPDF.Templates.LiquidHtml for Liquid variables, loops, and conditionals in HTML templates that render to PDF.
  • The core package already covers standard PDF fonts and embedded TrueType font registration.
  • Use ZingPDF.GoogleFonts if you need to register Google Fonts directly from the Google Fonts catalog.
  • Use ZingPDF.OCR when the page is primarily image-based or when OCR is part of your extraction workflow.
  • Treat ZingPDF.FromHTML as a separate deployment concern with its own runtime requirements.
  • Validate your exact deployment platform if you depend on image handling, font metrics, or browser automation.

Templates

Liquid HTML templates

ZingPDF.Templates.LiquidHtml renders a Liquid HTML template with a .NET model, converts the rendered HTML to PDF through ZingPDF.FromHTML, and writes the PDF stream you provide.

Install the renderer package

dotnet add package ZingPDF.Templates.LiquidHtml

Render a template file

using ZingPDF.Templates.LiquidHtml;

var invoice = new
{
    Number = "INV-1001",
    CustomerName = "Ada Lovelace",
    Items = new[]
    {
        new { Description = "Consulting", Total = 240m },
        new { Description = "Support", Total = 80m }
    }
};

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

await LiquidHtmlPdfTemplate
    .FromFile("invoice.liquid.html")
    .RenderAsync(invoice, output);

Inspect rendered HTML

var html = await LiquidHtmlPdfTemplate
    .FromFile("invoice.liquid.html")
    .RenderHtmlAsync(invoice);

Template behavior

  • Liquid variables, loops, conditionals, and includes are handled by Fluid.
  • File-backed templates resolve Liquid includes from the template directory by default.
  • The package uses browser automation through ZingPDF.FromHTML after Liquid rendering.
  • Use PdfTemplateRenderException.Diagnostics for template parse, load, and render failures.

Dedicated guide: Create a PDF from a Liquid HTML template.

Fonts

Font registration

ZingPDF registers standard PDF fonts and embedded TrueType fonts. ZingPDF.GoogleFonts adds Google Fonts registration through the same document-level font path.

Register a standard PDF font

using ZingPDF.Fonts;
using ZingPDF.Graphics;

using var pdf = Pdf.Create();
var page = await pdf.GetPageAsync(1);
var font = await pdf.RegisterStandardFontAsync(StandardPdfFonts.Helvetica);

await page.AddTextAsync(
    "Hello, world",
    Rectangle.FromDimensions(240, 80),
    font,
    18,
    RGBColour.Black);

Use a standard font in the fluent API

await Pdf.New()
    .Page(page => page
        .Text(text => text
            .Value("Hello, world")
            .Helvetica()
            .FontSize(18)
            .At(48, 780)))
    .SaveToFileAsync("hello.pdf");

Usable standard PDF fonts

  • StandardPdfFonts.Helvetica
  • StandardPdfFonts.HelveticaBold
  • StandardPdfFonts.HelveticaOblique
  • StandardPdfFonts.HelveticaBoldOblique
  • StandardPdfFonts.TimesRoman
  • StandardPdfFonts.TimesBold
  • StandardPdfFonts.TimesItalic
  • StandardPdfFonts.TimesBoldItalic
  • StandardPdfFonts.Courier
  • StandardPdfFonts.CourierBold
  • StandardPdfFonts.CourierOblique
  • StandardPdfFonts.CourierBoldOblique

Register an embedded TrueType font from disk

var font = await pdf.RegisterTrueTypeFontAsync(
    "MyFont-Regular.ttf");

await page.AddTextAsync(
    "Custom font text",
    Rectangle.FromDimensions(240, 80),
    font,
    18,
    RGBColour.Black);

Use an embedded TrueType font in the fluent API

await Pdf.New()
    .Page(page => page
        .Text(text => text
            .Value("Custom font text")
            .WithTrueTypeFont("MyFont-Regular.ttf", fontName: "MyFont-Regular")
            .FontSize(18)
            .At(48, 780)))
    .SaveToFileAsync("custom-font.pdf");

Register a Google Font

using ZingPDF.GoogleFonts;

var client = new GoogleFontsClient("<google-fonts-api-key>");
var font = await pdf.RegisterGoogleFontAsync(
    client,
    new GoogleFontRequest
    {
        Family = "Inter",
        Variant = "regular"
    });

await page.AddTextAsync(
    "Google Fonts text",
    Rectangle.FromDimensions(240, 80),
    font,
    18,
    RGBColour.Black);

Font notes

  • The current high-level registration path targets WinAnsi / Windows-1252 text.
  • Symbol and ZapfDingbats are not yet exposed through the high-level registration API.
  • ZingPDF.GoogleFonts requires a Google Fonts Developer API key and network access.

Related guides: Use standard PDF fonts, Use Google Fonts in a PDF, Embed a TrueType font, and Add text to a page.

Drawing

Draw vector paths and authored page content

The page API supports drawing vector paths with stroke and fill options. The fluent authoring API uses the same drawing primitives for rectangles, lines, paths, images, watermarks, and positioned or boxed text.

Draw a stroked path

using ZingPDF.Elements.Drawing;
using ZingPDF.Graphics;

await page.AddPathAsync(new Path(
    new StrokeOptions(RGBColour.PrimaryRed, 2),
    null,
    PathType.Linear,
    [
        new Coordinate(10, 10),
        new Coordinate(50, 60),
        new Coordinate(80, 20)
    ]));

Fill a bezier shape

await page.AddPathAsync(new Path(
    null,
    new FillOptions(RGBColour.PrimaryBlue),
    PathType.Bezier,
    [
        new Coordinate(20, 20),
        new Coordinate(40, 80),
        new Coordinate(90, 80),
        new Coordinate(110, 20)
    ]));

Draw the same kind of content fluently

await Pdf.New()
    .Page(page => page
        .Line(line => line
            .From(48, 720)
            .To(220, 720)
            .Stroke(RGBColour.PrimaryRed, 2))
        .Rectangle(box => box
            .At(48, 660)
            .Size(120, 40)
            .Stroke(RGBColour.PrimaryBlue, 1)
            .Fill(new RGBColour(0.9, 0.97, 1)))
        .Path(path => path
            .Bezier()
            .Point(220, 660)
            .Point(260, 720)
            .Point(320, 720)
            .Point(360, 660)
            .Fill(RGBColour.PrimaryBlue)))
    .SaveToFileAsync("drawing.pdf");

Boxed text, alignment, and wrapping

await Pdf.New()
    .Page(page => page
        .Text(text => text
            .Value("A longer note that should wrap inside the box.")
            .Helvetica()
            .FontSize(11)
            .InBox(48, 640, 180, 42)
            .AlignStart()
            .AlignTop()
            .Padding(0)
            .Wrap()
            .ClipOverflow()))
    .SaveToFileAsync("boxed-text.pdf");

Related guides: Add text to a page, Use standard PDF fonts, and Embed a TrueType font.

API reference

The symbol-by-symbol reference is generated from the source and XML documentation comments, and is best used when you need exact member signatures or type-level detail.

Open the API reference

Metadata

Document metadata

GetMetadataAsync() reads and updates 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.
using var output = File.Create("metadata-updated.pdf");

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);

Related guide: How to update PDF metadata in C#.

Forms

AcroForm fields

GetFormAsync() returns a Form wrapper for terminal field enumeration, typed field lookup, and field-family-specific behavior.

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, field bounds, and field dimensions.

Known field names

If you already know the fully qualified field name, fetch the field directly instead of enumerating the whole form.

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

var nameField = await form.GetFieldAsync("Applicant.Name");
if (nameField is not null)
{
    await nameField.SetValueAsync("Taylor Smith");
}

var stateField = await form.GetFieldAsync("Applicant.State");
if (stateField is not null)
{
    await stateField.SelectOptionByTextAsync("NSW");
}

Field enumeration

GetFieldsAsync() returns terminal fields in document order so you can inspect names and map them into your own data model.

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

foreach (var field in await form.GetFieldsAsync())
{
    Console.WriteLine(field.Name);
}

Form flattening

FlattenAsync() writes the current field appearances into page content and removes the interactive form structure.

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

await form.FlattenAsync();
await pdf.SaveAsync(File.Create("form-flattened.pdf"));

Text fields

TextFormField is the simplest path when you need to fill names, dates, IDs, or other typed values.

  • Read the current value with GetValueAsync().
  • Write or clear values with SetValueAsync(...) and ClearAsync().
  • Look fields up directly with Form.GetFieldAsync<TextFormField>(name).

Choice fields

ChoiceFormField covers dropdowns and list boxes.

  • Inspect available options with GetOptionsAsync().
  • Select by label or export value with SelectOptionByTextAsync(...) and SelectOptionByValueAsync(...).
  • Look fields up directly with Form.GetFieldAsync<ChoiceFormField>(name).

Checkboxes and radio buttons

CheckboxFormField and RadioButtonFormField expose selectable options through SelectableOption.

  • Inspect choices with GetOptionsAsync().
  • Toggle state with SelectAsync() and DeselectAsync().
  • Use this path when the PDF stores export values rather than plain text.

Push buttons

PushButtonFormField is read-only at the high level today.

  • Inspect captions and primary action type.
  • Read URI actions, named actions, and additional-action triggers.
  • Use this when you need to understand how an interactive form behaves before flattening or replacing that behavior elsewhere.

Signature fields

SignatureFormField supports both inspection and signing.

  • Read signed state and signature metadata such as signer name, reason, filter, and signing time.
  • Use SignAsync(...) to sign an existing visible field.
  • Use Pdf.SignInvisibleAsync(...) when you only need cryptographic validation and want to add a hidden field automatically.
  • Signing saves rewritten output so the signed byte ranges are stable and do not depend on incremental history.

Current gaps

  • Push-button action details can be inspected, but action execution is not yet exposed through the high-level API.
  • High-level signing supports existing visible signature fields and hidden validation-only fields on unencrypted PDFs. It does not sign encrypted PDFs yet, and it does not create visible signature fields automatically.

Related guides: Fill PDF form fields and Flatten a PDF form and Sign a PDF form field.

Encryption

Passwords and encryption

ZingPDF supports authenticating encrypted PDFs, applying password protection to plain PDFs, controlling user permissions, and saving decrypted output from encrypted input. New encrypted output can use legacy RC4-128 for compatibility or AES-128 and AES-256 through the Standard security handler.

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"));

Choose AES-128 or AES-256 when saving

If you do not pass an algorithm, ZingPDF writes RC4-128 for compatibility. Pass PdfEncryptionAlgorithm.Aes128 or PdfEncryptionAlgorithm.Aes256 when you want AES output.

// AES-128
using var aes128Pdf = Pdf.Create();

await aes128Pdf.EncryptAsync(
    "user-password",
    "owner-password",
    PdfEncryptionAlgorithm.Aes128);

await aes128Pdf.SaveAsync(File.Create("protected-aes128.pdf"));

// AES-256
using var aes256Pdf = Pdf.Create();

await aes256Pdf.EncryptAsync(
    "user-password",
    "owner-password",
    PdfEncryptionAlgorithm.Aes256);

await aes256Pdf.SaveAsync(File.Create("protected-aes256.pdf"));

Restrict copy, edit, or print access

Pass PdfEncryptionPermissions when the file should open with a password but still limit what the user can do afterward.

using var restrictedPdf = Pdf.Create();

await restrictedPdf.EncryptAsync(
    "user-password",
    "owner-password",
    PdfEncryptionAlgorithm.Aes256,
    PdfEncryptionPermissions.Print | PdfEncryptionPermissions.FillForms);

await restrictedPdf.SaveAsync(File.Create("restricted.pdf"));

EncryptAsync(...) supports Standard security handler RC4-128, AES-128, and AES-256 output. If you do not pass an algorithm, ZingPDF writes RC4-128 for compatibility.

Decrypt an encrypted PDF

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

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

DecryptAsync(...) removes encryption from the latest saved revision. If you also need to remove older encrypted history from the file bytes, call RemoveHistoryAsync() before saving.

Related guides: Encrypt a PDF with AES and Remove a password from a PDF.

Redaction

Redaction marks and rewritten output

ZingPDF can mark exact extracted-text matches or explicit page regions, remove matched text from supported page content, redact intersecting vector and XObject content, draw visible redaction overlays, and rewrite the document so earlier file history is not preserved.

Mark exact text and explicit regions

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

var plan = await pdf.RedactionAsync();

await plan.MarkTextAsync("12345");
await plan.MarkTextAsync(new Regex(@"\b\d{3}-\d{2}-\d{4}\b"));
plan.MarkRegion(
    1,
    Rectangle.FromCoordinates(
        new Coordinate(72, 520),
        new Coordinate(180, 548)));

await plan.ApplyAsync(new PdfRedactionOptions
{
    OverlayText = "REDACTED"
});

await pdf.SaveAsync(File.Create("redacted.pdf"));

What v1 redaction does

  • MarkTextAsync(...) uses extracted glyph runs to find exact string or regex matches and maps those matches back to supported text-showing operators.
  • MarkRegion(...) adds an explicit rectangle on a known page and removes intersecting supported text, vector, image XObject, and form XObject content.
  • ApplyAsync(...) rewrites matched content, draws the redaction overlay, and switches the document to rewritten-file save behavior.
  • PdfRedactionOptions controls fill colour and overlay text. Incremental-save redaction is not supported.

Current limits

This version removes matched text from supported page content and structurally redacts intersecting vector paths, image XObjects, and form XObjects. It still refuses inline images and shading content, and it does not yet derive OCR bounds for scanned pages.

Redaction currently uses the standard Pdf API because it is a document-level workflow over an existing file, rather than an authored page layout.

Related guide: Redact PDF content in C#.

Save Behavior

How saving works

By default, SaveAsync(...) writes an incremental update. That preserves earlier revisions in the file history.

Incremental save

SaveAsync(...) appends a new revision to the file by default, leaving earlier revisions in the document history.

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

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

Removing file history

Call RemoveHistoryAsync() before saving if you want the file rewritten with only the latest live objects. This removes earlier incremental revisions, helping with file size and document security.

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

await pdf.RemoveHistoryAsync();
await pdf.SaveAsync(File.Create("sanitized.pdf"));

Stream requirements

  • Pdf.Load(...) requires a seekable input stream. That is a parsing requirement and does not change if you later call RemoveHistoryAsync().
  • SaveAsync(...) currently requires a writable, seekable output stream because the save pipeline checks stream length and, in some paths, resets and truncates the stream before writing.
  • If you save to a different stream, that stream must be empty.

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

Compress(...) works on eligible unfiltered streams and can recompress JPEG image streams. DecompressAsync() skips JPEG image streams.

Related guides: Rewrite a PDF without incremental history, Redact PDF content, Add watermarks, and Compress output.

OCR

OCR for scanned and image-based pages

The core package extracts embedded PDF text. Add ZingPDF.OCR when you need OCR-based text extraction for scanned or image-based pages.

using ZingPDF.OCR;

using var pdf = Pdf.Load(File.OpenRead("scanned.pdf"));
var engine = new TesseractOcrEngine("./tessdata", "eng");

var text = await pdf.ExtractPlainTextWithOcrAsync(engine);
  • ExtractTextWithOcrAsync(...) prefers embedded text first by default, and that behavior can be changed with PdfOcrOptions.
  • ExtractPlainTextWithOcrAsync(...) returns a joined plain-text view across pages.
  • The current OCR path works best on image-based pages and supported image XObjects.

Low-Level Access

Low-level object access

IPdf.Objects exposes the underlying PDF object collection and page tree for integrations that need direct syntax-level access.

For exact member signatures and the generated type reference, go straight to the API docs.

Technical FAQ

Technical FAQ

Memory model

ZingPDF keeps the input stream open and resolves PDF objects on demand. It does not materialize the whole file into a full in-memory document model at load time.

  • Pdf.Load(...) holds a seekable input stream for the lifetime of the Pdf instance.
  • Document versions, trailers, the catalog, and indirect objects are parsed lazily as code touches them.
  • Parsed objects are cached after resolution.
  • Compressed object streams use a bounded cache rather than staying permanently expanded in memory.
  • Some save paths still stage full output in memory, including signing and rewriting back to the source stream.

Thread safety

Pdf instances should be treated as not thread-safe. The document model is mutable, the object collection keeps mutable caches and update state, and parsing operates against a shared underlying stream. That model keeps single-document workflows fast and predictable.

  • Do not share a single Pdf instance across concurrent operations.
  • Use one document instance per logical request or workflow.
  • If you need parallel work, open separate Pdf instances on separate streams.

Malformed PDFs

ZingPDF tolerates some malformed content and common cross-reference defects, but it does not try to repair every damaged file structure.

  • Content stream parsing returns the successfully parsed prefix when unsupported or malformed sections appear later in the stream.
  • Cross-reference stream parsing repairs the common case where the xref stream does not include a reference to itself.
  • The loader can recover when startxref is missing or out of range and a classic xref table still exists near the end of the file.
  • ZingPDF does not yet rebuild a full xref graph by scanning every indirect object in the file.

Evaluation FAQ

Evaluation FAQ

Package selection

ZingPDF is the default package for loading, creating, editing, forms, encryption, and save workflows. Add companion packages only for the extra capability they provide.

  • Add ZingPDF.FromHTML for Chromium-based HTML-to-PDF.
  • Add ZingPDF.Templates.LiquidHtml for Liquid HTML templates that render to PDF.
  • Add ZingPDF.GoogleFonts for Google Fonts registration.
  • Add ZingPDF.OCR for OCR on scanned or image-based pages.

Licensing

Evaluation and other non-commercial use stay free. Paid seats are required when the library is used for commercial work or internal business operations outside genuine evaluation.

  • Seats are licensed per developer.
  • Contractors can use seats licensed to the same customer legal entity.
  • See the pricing section and legal terms for the exact commercial contract.

Deployment environments

ZingPDF targets net8.0 and is intended for Windows, Linux, and macOS deployments that support .NET 8.

  • The core library fits desktop apps, background jobs, services, workers, and CLI tools.
  • ZingPDF.FromHTML has additional browser-runtime requirements.
  • ZingPDF.Templates.LiquidHtml has the same browser-runtime requirements after Liquid rendering.
  • Input streams passed to Pdf.Load(...) must be seekable.

Current limits

ZingPDF covers the main document-editing path, but some PDF features are still outside the current high-level API.

  • Signing does not yet support encrypted PDFs or create visible signature fields automatically.
  • OCR works best on image-based pages and supported image XObjects rather than arbitrary rendered page content.
  • Push-button actions can be inspected but are not executed through the high-level API.
  • Malformed file repair is limited to a few common recovery paths rather than full document reconstruction.