# Text Extraction

> Extract PDF text in Windows Forms: load it as text into the TextControl, list lines per page with Lines and ContentLine, search with regex and read page areas.

- **Product:** TX Text Control .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for Windows Forms > PDF Processing > Text Extraction
- **4293 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/text-extraction/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/text-extraction/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/text-extraction/llms-full.txt

---

Order numbers, totals and contract clauses often reach a desktop application inside PDF files. TX Text Control reads the text of a PDF in two ways: as a plain-text document in the `TextControl`, where the user reads and searches it, and as a list of text lines with their page and position, which your code searches with strings, regular expressions or areas of the page. The examples below extend a Windows Forms application with a `TextControl` named `textControl1` and a `ListBox` named `resultsListBox` for the results.

Converting a PDF into an editable document with its layout is the subject of [PDF Import and Its Limitations](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/import/llms-full.txt).

### How Text Extraction Works

TX Text Control extracts all text it can identify in a PDF, adds missing spaces and puts the text blocks into their logical order, as [What Happens When a PDF Is Loaded](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/import/#what-happens-when-a-pdf-is-loaded) explains. A scanned page is an image: its text has to be recognized with OCR before it can be extracted.

| Way | Returns | Use it for |
|---|---|---|
| `Load` with [PDFImportSettings](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/pdfimportsettings/enumeration/llms-full.txt) `GenerateLines` | The text of the PDF as a document, without images and paragraph formatting | Reading and searching the text in the editor, full-text indexes |
| The [Lines](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-lines/llms-full.txt) class of the `TXTextControl.DocumentServer.PDF.Contents` namespace | Each text line with its page number and position | Text per page, searches, values at a position |

`Lines` reads all text lines of a PDF file or byte array when you create it, without a `TextControl`. [ContentLines](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-lines/contentlines-property/llms-full.txt) returns them as a list of [ContentLine](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-contentline/llms-full.txt) objects, and each call of [Find](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-lines/find-method/llms-full.txt) filters them, so create one `Lines` object per document and call `Find` as often as you need.

| Property of `ContentLine` | Contains |
|---|---|
| [Page](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-contentline/page-property/llms-full.txt) | The number of the page that contains the line |
| [Text](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-contentline/text-property/llms-full.txt) | The text of the line |
| [X](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-contentline/x-property/llms-full.txt), [Y](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-contentline/y-property/llms-full.txt), [Width](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-contentline/width-property/llms-full.txt), [Height](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-contentline/height-property/llms-full.txt) | The position and size of the line on its page, in points |
| [Rectangle](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-contentline/rectangle-property/llms-full.txt) | The bounds of the line as a `RectangleF` |

The handlers below need these `using` directives in *Form1.cs*:

```csharp
using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using TXTextControl;
using TXTextControl.DocumentServer.PDF.Contents;
```

### Open the Text of a PDF in the Editor

With `PDFImportSettings.GenerateLines`, a PDF is loaded as text only: images and paragraph formatting are discarded, the setting best suited for searching PDF files. The following handler opens the **Open** dialog box with the filter for PDF files and loads the chosen file this way:

```csharp
private void openPdfAsTextButton_Click(object sender, EventArgs e)
{
    LoadSettings loadSettings = new LoadSettings()
    {
        // Text only: images and paragraph formatting are left out
        PDFImportSettings = PDFImportSettings.GenerateLines
    };

    // Opens the Open dialog box with the filter for PDF documents
    textControl1.Load(StreamType.AdobePDF, loadSettings);
}
```

The user now reads the text in the editor and searches it in the **Find** dialog box, which `textControl1.Find()` opens. [Search and Replace](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/editing-text/search-replace/llms-full.txt) shows how to search the text in code. A password-protected PDF needs its password in `LoadSettings`, as [Passwords and Access Permissions](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/passwords/#open-a-password-protected-pdf) shows.

### Read the Text Page by Page

When a summary or a search result refers to a page, your code needs the text of that page. The following handler asks for a PDF file, groups its lines by page and lists them in reading order:

```csharp
private string ChoosePdf()
{
    using (OpenFileDialog openDialog = new OpenFileDialog() { Filter = "PDF documents (*.pdf)|*.pdf" })
    {
        return openDialog.ShowDialog(this) == DialogResult.OK ? openDialog.FileName : null;
    }
}

private void showLinesButton_Click(object sender, EventArgs e)
{
    string path = ChoosePdf();

    if (path == null)
    {
        return;
    }

    Lines lines = new Lines(path);

    resultsListBox.Items.Clear();

    foreach (var page in lines.ContentLines.GroupBy(line => line.Page).OrderBy(group => group.Key))
    {
        resultsListBox.Items.Add($"--- Page {page.Key} ---");

        // From top to bottom, then from left to right
        foreach (ContentLine line in page.OrderBy(line => line.Y).ThenBy(line => line.X))
        {
            resultsListBox.Items.Add(line.Text);
        }
    }
}
```

The [Lines constructor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-pdf/contents-lines/constructor/llms-full.txt) takes the path of a PDF file or the PDF as a byte array. The handler sorts the lines of each page by their `Y` and `X` coordinates, as the blog article [Mining PDFs with Regex in C#: Practical Patterns, Tips, and Ideas](https://www.textcontrol.com/blog/2025/08/12/mining-pdfs-with-regex-in-csharp-practical-patterns-tips-and-ideas/) does.

### Search With Regular Expressions

`Find` with a regular expression returns every line that contains a match. The following handler finds invoice numbers such as INV-2025-001 and lists each one with its page:

```csharp
private void findInvoiceNumbersButton_Click(object sender, EventArgs e)
{
    string path = ChoosePdf();

    if (path == null)
    {
        return;
    }

    // Invoice numbers such as INV-2025-001
    string pattern = @"\bINV-\d{4}-\d{3}\b";

    Lines lines = new Lines(path);
    List<ContentLine> found = lines.Find(pattern, RegexOptions.IgnoreCase);

    resultsListBox.Items.Clear();

    foreach (ContentLine line in found)
    {
        Match match = Regex.Match(line.Text, pattern, RegexOptions.IgnoreCase);
        resultsListBox.Items.Add($"Page {line.Page}: {match.Value}");
    }
}
```

The code works as follows:

- `Find(string regex, RegexOptions options)` takes a .NET regular expression and its options and returns the lines that match.
- `Find` returns whole lines, so `Regex.Match` cuts the matched value out of the text of each line.
- `Find(string text)` without options returns the lines that contain a text.

A value that wraps to the next line isn't found by an expression for a single line. The blog article of the previous section shows patterns for dates, amounts and clause numbers and reads the neighboring lines for context.

### Read a Value From an Area of the Page

Documents of the same layout, such as invoices of one supplier, print a value at the same place. `Find` with a rectangle returns the lines in that area. The following handler takes the area of the invoice number from a sample invoice and reads the same area from every PDF in a folder the user chooses:

```csharp
private void readInvoiceNumbersButton_Click(object sender, EventArgs e)
{
    // Find the area of a known value in a sample document
    Lines sample = new Lines("invoice-sample.pdf");
    ContentLine known = sample.Find("INV-2025-001").FirstOrDefault(line => line.Page == 1);

    if (known == null)
    {
        MessageBox.Show("The sample invoice doesn't contain the invoice number.");
        return;
    }

    RectangleF area = known.Rectangle;

    using (FolderBrowserDialog folderDialog = new FolderBrowserDialog())
    {
        if (folderDialog.ShowDialog(this) != DialogResult.OK)
        {
            return;
        }

        resultsListBox.Items.Clear();

        // Read the same area of other documents of the same layout
        foreach (string file in Directory.GetFiles(folderDialog.SelectedPath, "*.pdf"))
        {
            Lines lines = new Lines(file);

            // true: lines that intersect the area, not only lines completely inside it
            ContentLine value = lines.Find(area, true).FirstOrDefault(line => line.Page == 1);

            resultsListBox.Items.Add($"{Path.GetFileName(file)}: {value?.Text ?? "(no value)"}");
        }
    }
}
```

The code works as follows:

- `Find(RectangleF rectangle, bool partially)` returns the lines in a rectangle. With `false`, a line must lie completely inside it; with `true`, it's enough that the line intersects it, so a longer value is found as well.
- The rectangle comes from a line of the sample, so the coordinates are those of the PDF files themselves rather than values measured by hand. `RectangleF` is part of `System.Drawing`.
- `Find(PointF position, float radius, bool partially)` returns the lines within a radius around a point.

The blog article [Template-Based Text Extraction from PDF Documents in .NET C#](https://www.textcontrol.com/blog/2025/02/12/template-based-text-extraction-from-pdf-documents-in-net-c-sharp/) reads several fields of flattened forms this way.

### Get the Text and the Coordinates in One Load

To extract text without showing it, load the PDF into a [ServerTextControl](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/servertextcontrol/llms-full.txt), the TX Text Control without a user interface. With `LoadEmbeddedData` in the import settings, [LoadSettings.EmbeddedData](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/loadsettings/embeddeddata-property/llms-full.txt) also contains the text coordinates as XML, in which each line has its page number and position:

```csharp
private void textAndCoordinatesButton_Click(object sender, EventArgs e)
{
    using (ServerTextControl tx = new ServerTextControl())
    {
        // Initialize the new instance before using it
        tx.Create();

        LoadSettings loadSettings = new LoadSettings()
        {
            PDFImportSettings = PDFImportSettings.GenerateLines | PDFImportSettings.LoadEmbeddedData
        };

        tx.Load("invoice.pdf", StreamType.AdobePDF, loadSettings);

        File.WriteAllText("invoice.txt", tx.Text);

        if (loadSettings.EmbeddedData != null &&
            loadSettings.EmbeddedData.TryGetValue(EmbeddedDataFormat.TextCoordinates, out object coordinates))
        {
            File.WriteAllText("coordinates.xml", coordinates.ToString());
        }
    }
}
```

[ServerTextControl.Text](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/servertextcontrol/text-property/llms-full.txt) returns the text of the document as one string. The keys of `EmbeddedData` are values of [EmbeddedDataFormat](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/embeddeddataformat/enumeration/llms-full.txt): `TextCoordinates`, `FormFields` and `MetaData`. The dictionary is filled only when `LoadEmbeddedData` is set, and it contains the formats the PDF provides.

### Next Steps

- [PDF Import and Its Limitations](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/import/llms-full.txt): load a PDF as an editable document with its layout.
- [Reading Form Fields and Values](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/forms/reading-fields/llms-full.txt): read the values of PDF form fields.
- [Document Metadata](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/metadata/llms-full.txt): read the title, author and keywords of a PDF.
- [Attachments](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/attachments/llms-full.txt): extract the files embedded in a PDF.

---

## Nearby

- **Previous:** [Attachments](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/attachments/llms-full.txt)
- **Next:** [Document Metadata](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/pdf/metadata/llms-full.txt)
