Exis.PdfEditor — The .NET PDF Toolkit

Find & replace text in PDFs, merge, split, build, fill forms, redact, sign, optimize, and convert to PDF/A — all from your C# code. Zero dependencies. Lossless editing.

.NET CLI dotnet add package Exis.PdfEditor

PM Console Install-Package Exis.PdfEditor

Why Exis.PdfEditor?

Most PDF libraries destroy your document

Most libraries convert your PDF to an intermediate format (HTML, image, or DOM), apply changes, then rebuild the entire file from scratch. This destructive render-rebuild cycle inevitably breaks the original document.

What gets broken:

  • Interactive form fields are flattened or lost
  • Digital signatures are invalidated
  • Character spacing and kerning are altered
  • Font substitution changes the appearance
  • Bookmarks, links, and annotations are dropped

Exis.PdfEditor edits content streams directly

Exis.PdfEditor parses the actual PDF content streams and performs surgical replacements at the operator level. No intermediate format. No rebuild. The output is the same file with only the targeted changes applied.

What gets preserved:

  • All form fields remain fully interactive
  • Digital signatures stay valid on unmodified pages
  • Original character spacing is maintained exactly
  • Embedded fonts are reused, not substituted
  • Bookmarks, annotations, and metadata are untouched

Other Libraries

PDF
Convert to intermediate format
Modify intermediate
Rebuild entire PDF
Damaged PDF (forms, sigs, spacing lost)

Exis.PdfEditor

PDF
Parse content streams
Replace at operator level
Incremental save
Identical PDF (only text changed)

Code Samples

Find & Replace Text (3 Lines of Code)

using Exis.PdfEditor;
using Exis.PdfEditor.Licensing;

ExisLicense.Initialize();  // Free 14-day trial - no key needed

var result = PdfFindReplace.Execute(
    "contract.pdf",
    "contract-updated.pdf",
    "Acme Corporation",
    "Globex Industries");

Console.WriteLine($"Replaced {result.TotalReplacements} occurrences " +
                  $"across {result.PagesModified} pages.");

Multiple Find & Replace Pairs

var pairs = new[]
{
    new FindReplacePair("2025", "2026"),
    new FindReplacePair("Draft", "Final"),
    new FindReplacePair("CONFIDENTIAL", "PUBLIC"),
};

var result = PdfFindReplace.Execute(
    "report.pdf",
    "report-final.pdf",
    pairs);

Regex Pattern Matching

var options = new PdfFindReplaceOptions { UseRegex = true };

// Replace all US phone numbers with a placeholder
var result = PdfFindReplace.Execute(
    "document.pdf",
    "redacted.pdf",
    @"\(\d{3}\)\s?\d{3}-\d{4}",
    "[PHONE REDACTED]",
    options);

Licensed Usage

// Purchase at pdfbatcheditor.com/developers - $499/developer/year
ExisLicense.Initialize("XXXX-XXXX-XXXX-XXXX");

// Unlimited pages, no restrictions, no console messages
var result = PdfFindReplace.Execute("large-doc.pdf", "output.pdf", "old", "new");

Text Fitting Options

var options = new PdfFindReplaceOptions
{
    CaseSensitive = true,
    WholeWordOnly = false,
    UseRegex = false,
    UseIncrementalUpdate = true,
    TextFitting = TextFittingMode.Adaptive,  // Best quality text fitting
    MinHorizontalScale = 70,                 // Minimum Tz percentage (50-100)
    MaxFontSizeReduction = 1.5               // Max font size reduction in points
};

var result = PdfFindReplace.Execute(
    "contract.pdf", "updated.pdf",
    "Short Name", "A Much Longer Replacement Name That Needs Fitting",
    options);

Font Color & Highlight

// Color replacement text and add a highlight background
var result = PdfFindReplace.Execute(
    "input.pdf", "output.pdf",
    "old text", "new text",
    new PdfFindReplaceOptions
    {
        ReplacementTextColor = PdfColor.Red,         // Font color of replaced text
        ReplacementHighlightColor = PdfColor.Yellow   // Background highlight behind text
    });

Merge PDFs

// Merge multiple PDFs into one, preserving page dimensions and resources
byte[] merged = PdfMerger.Merge(new[] { "cover.pdf", "report.pdf", "appendix.pdf" });
File.WriteAllBytes("combined.pdf", merged);

// Or write directly to a file
PdfMerger.MergeToFile(new[] { "file1.pdf", "file2.pdf" }, "merged.pdf");

// Merge with page range selection
byte[] selected = PdfMerger.Merge(new[]
{
    new PdfMergeInput(File.ReadAllBytes("doc1.pdf"), new[] { 1, 3, 5 }),
    new PdfMergeInput(File.ReadAllBytes("doc2.pdf"))  // all pages
});

Split PDFs

// Split into individual pages
List<byte[]> pages = PdfSplitter.Split("input.pdf");

// Extract specific pages (1-based)
byte[] subset = PdfSplitter.ExtractPages("input.pdf", new[] { 1, 3, 5 });

// Split to individual files with naming pattern
PdfSplitter.SplitToFiles("input.pdf", "page_{0}.pdf");

Build PDFs from Scratch

byte[] pdf = PdfBuilder.Create()
    .WithMetadata(m => m.Title("Report").Author("Exis"))
    .AddPage(page => page
        .Size(PdfPageSize.A4)
        .AddText("Hello, World!", x: 72, y: 750, fontSize: 24,
            options: o => o.Font("Helvetica").Bold().Color(0, 0, 0.8))
        .AddText("Generated with Exis.PdfEditor", x: 72, y: 720, fontSize: 12)
        .AddLine(72, 710, 523, 710, strokeWidth: 1)
        .AddRectangle(72, 600, 200, 80, fill: true,
            fillRed: 0.95, fillGreen: 0.95, fillBlue: 1.0)
        .AddImage(jpegBytes, x: 300, y: 400, width: 200, height: 150))
    .AddPage(page => page
        .Size(PdfPageSize.Letter)
        .AddText("Page 2", x: 72, y: 700, fontSize: 14))
    .Build();

File.WriteAllBytes("output.pdf", pdf);

Extract Text

// Extract all text from a PDF
PdfTextResult text = PdfTextExtractor.ExtractText("input.pdf");
Console.WriteLine(text.FullText);

// Extract from specific pages only
PdfTextResult partial = PdfTextExtractor.ExtractText("input.pdf", new[] { 1, 3 });

// Structured extraction with position and font data
PdfStructuredTextResult structured = PdfTextExtractor.ExtractStructured("input.pdf");
foreach (var block in structured.Pages[0].TextBlocks)
    Console.WriteLine($"[{block.X:F0},{block.Y:F0}] {block.Text} " +
        $"(font={block.FontName}, size={block.FontSize})");

Inspect Document (No License Required)

PdfDocumentInfo info = PdfInspector.Inspect("input.pdf");

Console.WriteLine($"Pages: {info.PageCount}");
Console.WriteLine($"Title: {info.Title}");
Console.WriteLine($"Fonts: {string.Join(", ", info.FontsUsed)}");
Console.WriteLine($"Encrypted: {info.IsEncrypted}");
Console.WriteLine($"Form fields: {info.FormFieldCount}");

Image Replacement

// Find all images in a PDF
var found = PdfImageEditor.FindImages("input.pdf");
foreach (var img in found.Images)
    Console.WriteLine($"Image #{img.Index}: {img.PixelWidth}x{img.PixelHeight} " +
        $"{img.ColorSpace} {img.Format} on page(s) {string.Join(", ", img.PageNumbers)}");

// Replace all images with a new one
byte[] newLogo = File.ReadAllBytes("new-logo.jpg");
var result = PdfImageEditor.ReplaceAll("input.pdf", "output.pdf", newLogo);
Console.WriteLine($"Replaced {result.ImagesReplaced} of {result.ImagesFound} images");

// Replace specific images by index or page range
var selective = PdfImageEditor.Replace("input.pdf", "output.pdf", newLogo,
    new PdfImageReplaceOptions { ImageIndices = new[] { 0, 2 } });

Auto-Layout Document Builder

byte[] pdf = PdfDocumentBuilder.Create()
    .PageSize(PdfPageSize.A4)
    .Margins(72)
    .WithMetadata(m => m.Title("Report").Author("Exis"))
    .Header(h => h
        .AddText("Quarterly Report", PdfHorizontalAlignment.Center, 12, o => o.Bold())
        .AddLine())
    .Footer(f => f
        .AddLine()
        .AddPageNumber())  // "Page 1 of 3"
    .AddParagraph("Introduction", 18, o => o.Bold())
    .AddSpacing(8)
    .AddParagraph("This report covers Q1 results.")
    .AddSpacing(12)
    .AddTable(t => t
        .Columns(2, 1, 1)
        .AlternatingRowBackground(0.95, 0.95, 1.0)
        .HeaderRow(r => r.AddCell("Product").AddCell("Units").AddCell("Revenue"))
        .AddRow(r => r.AddCell("Widget A").AddCell("1,200").AddCell("$24,000"))
        .AddRow(r => r.AddCell("Widget B").AddCell("850").AddCell("$17,000")))
    .AddPageBreak()
    .AddParagraph("Appendix", 14, o => o.Bold())
    .Build();

Form Filling

// Read form fields
List<PdfFormField> fields = PdfFormFiller.GetFields("form.pdf");
foreach (var field in fields)
    Console.WriteLine($"{field.Name} ({field.FieldType}) = {field.CurrentValue}");

// Fill fields
var result = PdfFormFiller.Fill("form.pdf", "filled.pdf", new Dictionary<string, string>
{
    { "FirstName", "John" },
    { "LastName", "Doe" },
    { "State", "CA" },
    { "AgreeToTerms", "Yes" }  // checkbox
});
Console.WriteLine($"Filled {result.FieldsFilled} fields");

// Flatten form (merge field appearances, remove interactive fields)
PdfFormFiller.Flatten("filled.pdf", "flattened.pdf");

Redaction

var result = PdfRedactor.Redact("input.pdf", "redacted.pdf", new[]
{
    // Text-based redaction
    new PdfRedaction { Text = "CONFIDENTIAL" },

    // Regex pattern (e.g., SSN)
    new PdfRedaction { Text = @"\d{3}-\d{2}-\d{4}", IsRegex = true },

    // Replace with alternative text
    new PdfRedaction { Text = "SECRET", ReplaceWith = "[REDACTED]" },

    // Area-based redaction on specific page
    new PdfRedaction { PageNumber = 3, Area = new PdfRect(100, 200, 300, 50) }
});
Console.WriteLine($"Applied {result.RedactionsApplied} redactions");

Optimization

var result = PdfOptimizer.Optimize("input.pdf", "optimized.pdf", new PdfOptimizeOptions
{
    CompressStreams = true,
    RemoveDuplicateObjects = true,
    RemoveMetadata = false,
    DownsampleImages = true,
    MaxImageDpi = 150
});
Console.WriteLine($"Saved {result.BytesSaved} bytes ({result.ReductionPercent:F1}%)");
Console.WriteLine($"Images downsampled: {result.ImagesDownsampled}");

Digital Signatures (.NET 8, 9, 10+)

using System.Security.Cryptography.X509Certificates;

// Sign a PDF
var cert = new X509Certificate2("certificate.pfx", "password");
PdfSigner.Sign("input.pdf", "signed.pdf", new PdfSignOptions
{
    Certificate = cert,
    Reason = "Approved",
    Location = "New York",
    ContactInfo = "admin@example.com"
});

// Verify a signed PDF
PdfSignatureInfo info = PdfSigner.Verify("signed.pdf");
Console.WriteLine($"Signed: {info.IsSigned}");
Console.WriteLine($"Valid: {info.IsValid}");
Console.WriteLine($"Signer: {info.SignerName}");
Console.WriteLine($"Certificate: {info.CertificateSubject}");
Console.WriteLine($"Issuer: {info.CertificateIssuer}");
Console.WriteLine($"Timestamp: {info.HasTimestamp}");

// Verify all signatures in a multi-signed document
List<PdfSignatureInfo> all = PdfSigner.VerifyAll("multi-signed.pdf");
foreach (var sig in all)
    Console.WriteLine($"{sig.SignerName}: valid={sig.IsValid}");

PDF/A Compliance

// Validate (no license required)
// Levels: PdfA1b, PdfA2b, PdfA2u, PdfA3b, PdfA3u
PdfAValidationResult result = PdfAConverter.Validate("input.pdf", PdfALevel.PdfA2b);
Console.WriteLine($"Compliant: {result.IsCompliant}");
foreach (var v in result.Violations)
    Console.WriteLine($"  [{v.Code}] {v.Message} (auto-fix: {v.CanAutoFix})");

// Convert to PDF/A
byte[] pdfa = PdfAConverter.Convert("input.pdf", PdfALevel.PdfA2b);
File.WriteAllBytes("output-pdfa.pdf", pdfa);

Async API

// All I/O operations have async overloads with CancellationToken support
byte[] merged = await PdfMerger.MergeAsync(inputPaths, cancellationToken);
PdfTextResult text = await PdfTextExtractor.ExtractTextAsync(stream, cancellationToken);
var info = await PdfInspector.InspectAsync(path, cancellationToken);
var result = await PdfOptimizer.OptimizeAsync(data, options, cancellationToken);
var sigs = await PdfSigner.VerifyAllAsync(path, cancellationToken);

// Pattern: ClassName.MethodNameAsync(...) on all classes

How Exis.PdfEditor Compares

Feature Exis.PdfEditor IronPDF Spire.PDF Aspose.PDF Syncfusion
Direct content stream editing Renders via HTML/Chromium Redaction-style replacement Fragment-based replacement Redaction-style replacement
Preserve form fields Partial Partial
Preserve digital signatures On unmodified pages
Preserve character spacing Partial
Zero native dependencies Pure .NET Requires Chromium
DLL size < 500 KB ~250 MB ~20 MB ~40 MB ~15 MB
Batch processing Single-pass multi-pair Manual loop Manual loop Manual loop Manual loop
.NET Framework 4.8 .NET 6+ only
Cross-platform
Regex support
Price (per dev/year) $499 $749 $999 $1,175 $995*
Company HQ 🇺🇸 USA 🇺🇸 USA 🇨🇳 China 🇦🇺 Australia 🇺🇸 USA

* Syncfusion pricing requires a platform license. Prices are approximate and based on publicly available information as of 2026. Contact vendors for current pricing.
"Direct content stream editing" means the library modifies PDF content stream operators in-place rather than converting to an intermediate format and rebuilding.

Everything You Need for PDF Processing

📄

Direct Content Stream Editing

Edit PDF text at the operator level. No intermediate format, no render-rebuild. Your document comes out identical except for the targeted changes.

🔗

Zero Native Dependencies

Pure .NET assembly under 500 KB. No Chromium, no native DLLs, no system-level installs. Works everywhere .NET runs.

🔒

Lossless Editing

Forms, signatures, spacing, fonts, bookmarks, and annotations are preserved. Incremental updates keep signatures valid on unmodified pages.

🎯

Multi-Target Framework

Targets .NET Standard 2.0 (Framework 4.6.1+, Core 2.0+) and .NET 8/9/10+ with optimized builds and digital signature support.

Batch Processing

Process multiple find/replace pairs in a single pass. Built for high-throughput scenarios with thousands of documents.

🔎

Regex Support

Full .NET regex engine for pattern-based find and replace. Redact SSNs, phone numbers, emails, or any custom pattern.

🖥

Cross-Platform

Runs on Windows, Linux, and macOS. Deploy to Azure, AWS, Docker, or on-premises servers without platform-specific dependencies.

📦

Small Footprint

Under 500 KB total. No bloated runtime, no embedded browser engine. Minimal memory usage even on large documents.

📋

PDF Merge

Combine multiple PDFs into one document, preserving page dimensions and resources.

PDF Split

Extract individual pages or page ranges into separate PDFs. Split to files with naming patterns.

🔧

PDF Builder

Create PDFs from scratch with a fluent API. Add text, images, lines, and rectangles with full formatting control.

📝

Text Extraction

Pull text content from PDF pages. Extract from all pages or specific page ranges.

🔍

Document Inspector

Read metadata, fonts, page dimensions, and form field counts. Works without any license.

🖼

Image Replacement

Find, analyze, and replace images in PDFs. Swap logos or graphics by index or page range with JPEG/PNG.

📑

Auto-Layout Builder

Create reports with auto-pagination, text wrapping, tables, headers/footers, and page numbers.

📝

Form Filling

Read and fill AcroForm fields including text, checkbox, and dropdown. Lossless form preservation.

🚫

Redaction

Text-based, regex pattern, or area-based redaction. Permanently remove sensitive content from PDFs.

📈

Optimization

Compress streams, remove duplicate objects, and reduce file size while preserving document quality.

🔐

Digital Signatures

Sign PDFs with X.509 certificates and verify existing signatures. Available on .NET 8, 9, 10+.

PDF/A Compliance

Validate and convert to PDF/A (1b, 2b, 2u, 3b, 3u) for long-term archival. Validation works without a license.

🔄

Async API

All I/O operations have async overloads with CancellationToken support for scalable applications.

Simple, Transparent Pricing

Annual Subscription
$499
auto-renews yearly / cancel anytime
  • Unlimited pages per document
  • Unlimited files per project
  • All features included
  • Email support from the developer
  • Automatic annual renewal

Start with a free 14-day trial. No credit card required. Just install the NuGet package and call ExisLicense.Initialize() with no arguments.

All prices in USD. License keys are delivered via email within minutes of purchase. Volume discounts available for 5+ developers — contact support@exisone.com.

How the Free Trial Works

Install & Initialize

  • Install via NuGet: dotnet add package Exis.PdfEditor
  • Call ExisLicense.Initialize() with no arguments
  • 14-day trial starts automatically
  • No registration, no credit card, no email required

Trial Limitations

  • Maximum 5 pages processed per document
  • Console message printed on each operation
  • All API features are fully available
  • No watermarks added to output
  • Trial resets if you clear local app data

Upgrade to Licensed

  • Purchase a license key above ($499/year)
  • Pass your key: ExisLicense.Initialize("YOUR-KEY")
  • Unlimited pages, no console messages
  • Same API, same code — just add your key

No code changes needed when upgrading — just add your license key to the Initialize() call.

Built by a Team You Can Trust

USA-based company. Exis LLC is incorporated in New Jersey, USA. Your license fees stay onshore and support American software development.
Government-approved vendor. Exis LLC is a registered vendor with U.S. federal and state government procurement systems (SAM.gov). Trusted by government agencies.
15+ years of experience. The team behind Exis.PdfEditor has been building document processing tools since 2010. Battle-tested across millions of documents.
Direct developer support. No ticket queues or chatbots. Email support@exisone.com and get a response from the engineer who wrote the code. Usually within 24 hours.

Frequently Asked Questions

Exis.PdfEditor targets .NET Standard 2.0, which means it works on .NET Framework 4.6.1+, .NET Core 2.0+, and .NET 5-7. It also ships optimized builds for .NET 8, 9, and 10+ that include digital signature support. It runs on Windows, Linux, and macOS with no native dependencies.
Install the NuGet package and call ExisLicense.Initialize() with no arguments. The trial starts automatically — no registration, no credit card, no email. During the trial, documents are limited to 5 pages and a console message is printed on each operation. All API features are fully available.
PDFs store text as sequences of operators in content streams (e.g., Tj, TJ, '). Exis.PdfEditor parses these streams, locates the target text across operator boundaries, and performs surgical replacements at the byte level. The rest of the document — forms, signatures, metadata, fonts — remains completely untouched. Most other libraries convert the PDF to an intermediate format (HTML, DOM, or image), modify that, then rebuild the entire PDF, which destroys forms, signatures, and spacing.
Yes. Exis.PdfEditor is a pure .NET library with no UI dependencies, no native DLLs, and no system-level installs. It works in ASP.NET, Azure Functions, AWS Lambda, Docker containers, Windows Services, and any headless environment. The license is per-developer, not per-server, so you can deploy to as many servers as needed.
Each license key is tied to one developer and is valid for one year from the date of purchase. You can use the key in unlimited projects and deploy to unlimited servers. When the year expires, you need to renew to continue receiving updates and using the library. Volume discounts are available for teams of 5+ developers — contact support@exisone.com.
Yes. Exis.PdfEditor can open and process password-protected PDFs. Pass the password as an optional parameter when loading the document. The library supports both user passwords (for opening) and owner passwords (for permissions). Encrypted PDFs are decrypted in memory during processing.
Exis.PdfEditor includes an adaptive text fitting engine. When replacement text is longer, the engine can apply horizontal scaling (condensing) and slight font size reduction to fit the text in the same space. You control the limits via MinHorizontalScale and MaxFontSizeReduction options. When replacement text is shorter, the original spacing is preserved naturally. The TextFittingMode.Adaptive setting provides the best balance of quality and fit.
Yes. PdfInspector.Inspect() and PdfAConverter.Validate() work without any license or trial. You can read page counts, metadata, font lists, form field counts, and run PDF/A validation completely free. Only operations that modify PDFs (find/replace, merge, split, etc.) require a license or active trial.
We offer a full refund within 30 days of purchase if the library does not meet your needs. Since we provide a free 14-day trial with full API access, we recommend thoroughly testing before purchasing. Contact support@exisone.com for refund requests.
Email support@exisone.com directly. You will reach the engineer who wrote the library — no ticket queues, no chatbots. Most inquiries are answered within 24 hours on business days. For bug reports, include a minimal code sample and the problematic PDF if possible. You can also browse the sample app on GitHub for working examples.

Start Building with Exis.PdfEditor Today

dotnet add package Exis.PdfEditor

Start Free Trial on NuGet Sample App on GitHub

Questions? Email support@exisone.com — you will hear back from the developer who wrote the code.