Read every word on a PDF page with its bounding box in C#, group words into rows, and find the value printed next to a label, with OnePDF.
OnePDF has no table-extraction API. Words with positions are the building block: this recipe reads an invoice’s rows and its total from them.
using OnePdf; using OnePdf.Text; using PdfDocument doc = PdfDocument.Open("invoice.pdf"); PdfPageText text = doc.Pages[0].ExtractText(); // Rows of the page: words grouped by baseline, top to bottom, each row left to right. var rows = text.Words .GroupBy(w => Math.Round(w.Bounds.Bottom)) .OrderByDescending(row => row.Key); // y grows upward foreach (var row in rows) Console.WriteLine($"y={row.Key,4} " + string.Join(" ", row.OrderBy(w => w.Bounds.Left).Select(w => $"{w.Text}@{w.Bounds.Left:F0}"))); // The value printed to the right of a label, on the same baseline. PdfTextWord label = text.Words.First(w => w.Text == "Total"); PdfTextWord value = text.Words .Where(w => w.Bounds.Left > label.Bounds.Right && Math.Abs(w.Bounds.Bottom - label.Bounds.Bottom) < 2) .OrderBy(w => w.Bounds.Left) .First(); Console.WriteLine($"Total: {value.Text} at ({value.Bounds.Left:F1}, {value.Bounds.Bottom:F1})");
y= 725 No.@491 2026-104@512 y= 712 October@473 26,@515 2026@534 y= 708 Invoice@54 y= 680 Bill@54 to:@72 Example@87 Co.,@133 100@156 Main@178 Street,@204 Springfield@240 y= 647 Item@60 Qty@354 Price@436 Amount@511 y= 624 Design@60 review@97 2@367 $450.00@423 $900.00@513 y= 600 Implementation,@60 hours@141 12@361 $120.00@423 $1,440.00@504 y= 576 Hosting,@60 October@103 1@367 $80.00@429 $80.00@519 y= 553 Total@437 $2,420.00@504 y= 54 Payment@248 due@286 within@304 30@330 days.@342 Total: $2,420.00 at (503.6, 552.7)
Boundsis aPdfRectangle(Left,Bottom,Right,Top,Width,Height) in points, with the origin at the lower left of the page and y going up. The page’s/Rotateis already applied, so the coordinates are those of the page as a viewer shows it.- A word is a run of glyphs without a space between them, so punctuation stays attached (“Co.,”).
text.Wordslists every word of the page.text.Blocks, each block’sLinesand each line’sWordsgive the same words grouped in reading order, which suits running text better than tables.- Rounding the baseline to the nearest point is enough for a generated document. For scans with an OCR layer or slightly skewed text, group words whose baselines are within a fraction of the font size instead.
word.IsVisibleis false for invisible text, such as an OCR layer under a scanned image.
To black out the words you found, see Redact text. How words, lines and blocks are formed is in Text layout and reading order.
For the whole extraction workflow, see Extract text from PDF in C#.
Coming from PdfPig’s word API: Migrate from PdfPig.