All posts
Engineering8 min read

How to extract data from a PDF in C#

A working engineer's tour of the PDF extraction libraries in the .NET ecosystem — iText, PdfPig, Azure Document Intelligence, and the API-first alternative when you don't want to ship a parser at all.

By · Updated

PDF extraction in C# splits into two questions: do you have structured PDFs (text layer present, predictable layout) or unstructured ones (scans, images, varying layouts)? The library you reach for depends entirely on which side you're on.

Structured PDFs

PdfPig

Free, MIT-licensed, pure .NET. Reads text and basic layout from any PDF with a text layer. No write support, no advanced features — just clean reading.

using UglyToad.PdfPig; using var doc = PdfDocument.Open("invoice.pdf"); foreach (var page in doc.GetPages()) { Console.WriteLine(page.Text); }

For structured invoices and reports with selectable text, this gets you 80% of the way in 10 lines.

Beyond page.Text: layout details

PdfPig exposes more than flat text. page.GetWords() returns grouped words with bounding boxes; page.Letters goes down to individual glyphs with fonts and positions. That's how you build a targeted extractor — find the label, grab the value to its right:

using var doc = PdfDocument.Open("invoice.pdf"); var page = doc.GetPage(1); foreach (var word in page.GetWords()) { if (word.Text == "Total") Console.WriteLine($"Label at {word.BoundingBox.Left},{word.BoundingBox.Bottom}"); }

Coordinate-based extraction breaks the moment a layout shifts, so use it for stable templates — not for arbitrary vendor documents.

iText 7

More powerful, with read, write, fill-form, and digital signature support. Note the licensing: iText is AGPL by default — you need a commercial license for non-OSS use. For a lot of teams that alone rules it out; for others it's worth the spend.

PDFsharp / MigraDoc

Mature, MIT-licensed alternative. Stronger on PDF generation than extraction, but it does both. Less surface area than iText.

Password-protected PDFs

PdfPig opens encrypted files when you pass the password: PdfDocument.Open(bytes, new ParsingOptions { Password = "..." }). iText handles them through PdfReader with the owner password. Neither library cracks unknown passwords — if the sender locked the file, ask for the password or an unlocked copy.

Tables specifically

PdfPig has a community Table extraction add-on, but for serious table work most .NET teams either shell out to a Java tool like Tabula or call a hosted service. Native C# table extraction is the weakest part of the ecosystem.

Unstructured PDFs (scans, images, varying layouts)

Azure AI Document Intelligence

Microsoft's hosted service. Pre-built models for invoices, receipts, and IDs; custom models you train on your own samples. The .NET SDK is first-class:

var client = new DocumentAnalysisClient(endpoint, credential); var operation = await client.AnalyzeDocumentAsync( WaitUntil.Completed, "prebuilt-invoice", fileStream); var result = operation.Value;

Pricing is per-page; for high volumes it adds up. Quality is good on the prebuilt invoice/receipt models, less reliable on long-tail document types.

AWS Textract

Equivalent service from AWS, accessible from .NET via AWSSDK.Textract. Strong on tables and forms, weaker than Azure on prebuilt domain models.

API-first: ExtractFox

If you don't want to ship a PDF library at all and prefer to call a hosted endpoint with HttpClient, ExtractFox exposes a JSON API that handles structured and unstructured PDFs through the same call. You send the file (or a URL), declare what you want as a JSON schema or a free-text description, and get structured output back.

var content = new MultipartFormDataContent(); content.Add(new StreamContent(fileStream), "file", "invoice.pdf"); content.Add(new StringContent("invoice"), "vertical"); var response = await http.PostAsync("https://extractfox.com/api/extract", content);

See the API docs for the full schema and authentication details.

Common pitfalls in PDF text extraction

  • Ligatures and smart quotes come back as single glyphs (fi, fl) — normalize the text before comparing or matching strings.
  • Line breaks don't match visual rows — PDF stores text in draw order, not reading order. Multi-column layouts interleave badly; use word coordinates to reconstruct rows.
  • Hyphenated words split across lines stay split — strip trailing hyphen + newline pairs when reflowing paragraphs.
  • Scanned PDFs return empty text — there is no text layer. Detect this (page.Text comes back empty or near-empty) and route to OCR or a vision model instead of parsing nothing.

Options compared

OptionCostBest for
PdfPigFree (MIT)Reading text-layer PDFs in pure .NET
iText 7AGPL or commercialReading + writing, forms, signatures
PDFsharp / MigraDocFree (MIT)Generation-first projects
Azure Document IntelligencePer pageScans, invoices, receipts at scale
ExtractFox APIPer callStructured output without shipping a parser

Test before you ship

PDF parsing fails quietly — the regex still matches, just against the wrong line. Keep a small set of golden files (real documents with known expected output) in the repo and run the extractor against them in CI. The first time a vendor changes their invoice layout, the test fails instead of your downstream data.

Choosing

  • Structured PDFs, simple text extraction → PdfPig.
  • Structured PDFs, complex manipulation → iText (mind the license) or PDFsharp.
  • Scanned/varied invoices and receipts → Azure Document Intelligence or ExtractFox.
  • Don't want to maintain any of this → ExtractFox, or one of the hosted services.

Related reading

Stop reading, start extracting

Drop a PDF or image into ExtractFox and get structured data back in seconds.

Try a free extraction →