Exis.PdfEditor logo

PDF Find & Replace SDK for .NET

Find and replace text in PDF files programmatically with C#. Direct content stream editing — no conversion to DOCX, no external dependencies, no data loss.

.NET CLI dotnet add package Exis.PdfEditor

PM Console Install-Package Exis.PdfEditor

Why Exis.PdfEditor

How other libraries work

Most .NET PDF libraries — IronPDF, Spire.PDF, Aspose, Syncfusion — replace text by converting the PDF to an intermediate format, redacting text and drawing new text on top, or rebuilding pages from scratch.

This approach breaks:

  • Form fields and checkbox values
  • Digital signatures
  • Text spacing and kerning
  • Page layout and positioning
  • Bookmarks and link destinations

How Exis.PdfEditor works

Exis.PdfEditor parses PDF content streams directly at the byte level. It locates text in the actual PDF operators, modifies only the targeted string operands, and writes back using PDF incremental update.

Everything not touched stays byte-for-byte identical:

  • Form fields and AcroForms: untouched
  • Digital signatures on unmodified pages: preserved
  • Text spacing and kerning: preserved
  • Page layout and structure: preserved
  • Bookmarks, annotations, embedded files: preserved

Other libraries

PDF
Convert to intermediate
Modify
Convert back to PDF
Output (damaged)

Exis.PdfEditor

PDF
Parse content streams
Replace text operands
Incremental update
Output (identical except replaced text)

Code Samples

Replace text in a PDF — 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 replacements in one pass

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

Pattern-based replacement with regular expressions

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

Activate your subscription

// Purchase at officefindreplace.com/Home/pdf-find-replace-csharp - $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 HTML Redaction overlay Fragment replace Redaction overlay
Preserves form fields Partial Partial
Preserves digital signatures Unmodified pages
Preserves text spacing/kerning Partial
Zero native dependencies Pure .NET Chromium engine
DLL size < 500 KB ~250 MB ~20 MB ~40 MB ~15 MB
Batch multi-pair replacement Single pass Manual loop Manual loop Manual loop Manual loop
.NET Framework 4.8 .NET 6+ only
Cross-platform
Regex support
Price (per developer/year) $499 $749 $999 $1,175 $995*
Company HQ 🇺🇸 USA 🇺🇸 USA 🇨🇳 China 🇦🇺 Australia 🇺🇸 USA

Comparison based on publicly available documentation as of February 2026. Feature support may vary by version.
"Direct content stream editing" means the library modifies PDF text operators in-place without converting, re-rendering, or overlaying.

Features

Direct PDF editing

Modifies content stream operators. No intermediate conversion.

Zero dependencies

No Ghostscript, no LibreOffice, no Chromium. Pure managed .NET.

Lossless output

Forms, signatures, annotations, bookmarks — all preserved.

Multi-target

.NET 8, 9, 10+ and .NET Standard 2.0 (.NET Framework 4.6.1+, .NET Core 2.0+, .NET 5-7).

Batch processing

Multiple find/replace pairs executed in a single pass.

Regular expressions

Full .NET regex support for pattern-based replacements.

Cross-platform

Windows, Linux, macOS. Anywhere .NET runs.

Small footprint

Single DLL, under 500 KB. No native binaries to deploy.

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.

Pricing

Annual Subscription
$499
auto-renews yearly / cancel anytime
  • Unlimited pages
  • Unlimited files
  • All features included
  • Email support
  • Automatic annual renewal

Install the NuGet package and call ExisLicense.Initialize() — full functionality for 14 days. After trial, evaluation mode processes up to 3 pages per document. No watermarks. When ready, purchase a license key at officefindreplace.com/Home/pdf-find-replace-csharp.

Prices in US dollars. One key per developer. Works on dev machine, build server, and production — no per-machine or per-deployment limits.

How the trial works

Trial (Days 1–14)

  • Install the NuGet package
  • Call ExisLicense.Initialize()
  • Full access — unlimited pages
  • No key, no signup, no credit card

Evaluation (After Day 14)

  • Trial expires automatically
  • Library continues working
  • Limited to 3 pages per document
  • No watermarks on output
  • Your existing code keeps running

Licensed

  • Purchase key at officefindreplace.com/Home/pdf-find-replace-csharp
  • Call ExisLicense.Initialize("your-key")
  • Unlimited pages, no restrictions
  • Silent operation — no console messages

Your code does not change between trial and licensed mode. Just add your key when ready.

Built by Exis LLC

Made in USA — Exis LLC, New Jersey. US-based development and support.
Government-trusted — The same PDF engine powers Global Office Find Replace Professional, used by US federal agencies for document processing.
35+ years in software — 8 patents across document processing, sensors, cryptography, and industrial automation.
Responsive support — Direct email access to the development team. Not a ticketing queue.

Frequently Asked Questions

No. Exis.PdfEditor is a pure .NET library with zero external dependencies. It does not use Office, Acrobat, Ghostscript, LibreOffice, Chromium, or any other external tool.
IronPDF renders PDFs via a Chromium engine — it effectively re-creates the page, which destroys form fields, spacing, and signatures. Aspose.PDF uses a text fragment replacement approach that can shift positioning. Exis.PdfEditor operates directly on PDF content stream operators, preserving everything except the targeted text.
Form fields (AcroForms), checkbox values, radio buttons, digital signatures (on unmodified pages), annotations, bookmarks, embedded files, hyperlinks, and all layout and spacing. Only the text you target is modified.
Yes. The developer seat license covers your development machine, build server, and production deployment. No per-machine or per-deployment licensing.
The library enters evaluation mode. It continues working but limits processing to 3 pages per document. No exceptions thrown on small files, no watermarks added. Your existing code keeps running. Add a license key when you are ready.
Yes. The NuGet package includes a .NET Standard 2.0 build that works on .NET Framework 4.6.1 and later, including 4.8. It also ships a .NET 8 optimized build.
One license key per developer. The key lives in your source code. It works on your dev machine, build server, staging, and production without per-machine limits. For teams, each developer needs their own key. No machine fingerprinting or activation servers to manage.
Yes. PdfTextExtractor.ExtractText() returns the full text content. PdfInspector.Inspect() returns document metadata and page count — PdfInspector does not require a license at all.
Exis.PdfEditor works with text-based PDFs where text is encoded in content streams. For scanned documents where the content is a raster image, you would need to run OCR first to produce a text layer.
The library resolves font encodings automatically — ToUnicode CMaps, WinAnsiEncoding, MacRomanEncoding, custom encoding dictionaries with /Differences, and composite (CID/Type0) fonts for CJK text.

Start your 14-day free trial

dotnet add package Exis.PdfEditor

Start Free Trial Sample App on GitHub

Questions? Email support@exisone.com — you will hear from a developer, not a bot.