Extract Text from PDFs Programmatically
Reading order and layout recovery decide whether extracted PDF text is usable. Smart Data Extraction pairs a deterministic structure foundation with purpose-built AI for key-value extraction and classification. It is part of Apryse document extraction and parsing, and it runs inside your own infrastructure.
How to Extract Text from a PDF Programmatically
Reading order and layout recovery decide whether text pulled from a PDF is usable. A PDF has no concept of a paragraph, sentence, or table, so every extractor infers structure from where text sits on the page. To extract text programmatically, initialize PDFNet with your license key, open the file with the Apryse Server SDK, and read each page with TextExtractor. That step belongs to the base Server SDK, runs on Windows, Linux, and macOS, and returns Unicode text with word and line positions. When your code needs headers, footers, lists, and tables identified as separate blocks, add Smart Data Extraction. It returns JSON with page numbers and bounding rectangles, needs a separate add-on license, and runs on Windows and Linux (x64 only). A scanned PDF has no text layer, so the OCR Module, also a separate add-on, creates one first. All of it runs inside your own infrastructure.
Why Reading Order Decides Whether Extracted Text is Usable
A PDF stores positioned text runs, not paragraphs. The ISO PDF standard does not define reading order, and a typical PDF has no concept of a sentence, paragraph, or table. The run order follows the program that wrote the file, not the order a person reads.
Three layouts expose the gap: multi-column pages, running headers and footers, and tables set inside running text. Reading order also changes with document type. A magazine page, a newspaper article, and an academic paper each ask for a different order.
Each failure carries into whatever consumes the text. A language model that ingests interleaved columns reads sentences the author never wrote. A search index that stores footers inside paragraphs returns the wrong passages. A review screen that highlights the wrong region teaches your users to distrust it.
Three separate jobs sit under the phrase text extraction. Reading the text layer, with words, lines, paragraphs, and positions, is a base Server SDK operation. Recovering structure, meaning which blocks are headers, footers, lists, and tables, is the job of Smart Data Extraction, an add-on that handles document structure recovery. Generating a text layer where none exists is OCR, a separate add-on. Scope them separately.
The structure foundation is deterministic: the same PDF produces the same recovered structure on every run. Purpose-built AI handles the fields that need interpretation, such as key-value pairs and page classification.
Tables inside running text are a parsing problem with their own method. This page stops at that boundary, and document parsing covers tables.
Extracting the Text Layer
This section covers Apryse Server SDK integration using C#, Java, and Python 3 on Windows and Linux. For other languages or platforms, see the Server SDK get-started guide.
TextExtractor is part of the base Server SDK. It needs no add-on module and no add-on license. It normalizes text to Unicode, assembles words, lines, and paragraphs, removes duplicated strings, and reconstructs reading order. The text extraction guide states the limit: the reconstructed order is not guaranteed to match the order a person reading the page would follow.
You need a trial key from dev.apryse.com and a call to PDFNet.initialize() before any extraction call. It sets up the library, registers your license key, and runs once per process. The call name changes by binding, as the table shows.
Getting Started with Text Extraction
Keep the license key out of source control. The examples read it from the APRYSE_LICENSE_KEY environment variable.
Text Extraction Code Examples
Text Extraction in C#
Reference the extracted PDFNetC64 files from your project. The program initializes PDFNet once, reads page 1, and releases PDFNet in a finally block.
Text Extraction in Java
Call doc.close() after each document and PDFNet.terminate() at shutdown. The native library must be on the Java library path when you run the class, or the JVM throws an UnsatisfiedLinkError.
Text Extraction in Python 3
Install from the Apryse package index, not public PyPI. The legacy PDFNetPython3 package on public PyPI is no longer updated.
Expected Output
Run against a sample contract, each program prints page 1 as plain text. Words are separated by spaces or new lines:
The footer arrives as one more line. Plain text tells you what was written on the page, not which block is a heading, a body paragraph, or a footer.
The full working reference is the text extraction sample, and the classes are listed in the extraction API reference.
At volume, initialize once per worker and keep PDFNet alive for the life of the process. The Server SDK has no work queue, job scheduler, or batch orchestration, so your code owns the loop. Open one PDFDoc per thread or lock a shared document with the documented Lock and LockRead calls.
Extracting Text with Position and Layout Data
The base TextExtractor already returns positions. Every line and word carries a bounding box and style, and getAsXML returns paragraphs, lines, and words as XML when you pass the flags below.
A bounding box tells you where text sits but not what a block is. Smart Data Extraction answers that, and it returns each block with its page number and bounding rectangle as JSON.
This feature requires the Smart Data Extraction add-on module, which is a separate download from the base Server SDK. See the modules documentation for download and installation instructions.
The module needs an add-on license. Trial keys include it, but trial output is limited to 100 pages and a random evaluation page is inserted into the output. Once you license the module, neither limit applies.
Install Smart Data Extraction by language
A DataExtractionTest sample application ships in the main SDK download. The programs below follow the same pattern: initialize PDFNet, register the module, confirm it is available, then extract.
Document Structure as JSON
Document Structure as JSON in C#
Document Structure as JSON in Java
Document Structure as JSON in Python 3
Expected JSON Output
Each program prints the same structure. The excerpt below is trimmed to page 1 of the sample contract. Every element carries a type and a rect of the form [left, top, right, bottom] in PDF points, and each page object carries its pageNumber. The root object also holds document properties: the coordinate system, the producer, and the schema version. The JSON specification defines every element type.
Your application uses the page number and rect to overlay or annotate the source page, to route a paragraph to a reviewer, or to cite the page a passage came from. The same JSON feeds semantic search and RAG preprocessing.
Confidence scores differ by mode. Form field identification, key-value extraction, CAD title block extraction, and document classification each return a confidence score. Table extraction does not, so treat table output as unscored.
Apryse supplies the extraction building blocks. Your application owns the pipeline around them, including queues, review, and storage.
Multi-Column Pages and Reading Order
Multi-column pages, sidebars, and running headers break order-based extraction first. The base TextExtractor reconstructs reading order from word and line positions, and the e_extract_using_zorder flag switches it to the order the content was drawn in. Both return text. Neither labels a block.
Smart Data Extraction recognizes the page the way a person sees it. Its Document Structure Recognition engine separates paragraphs and lists, headers and footers, section columns from table columns, and tables embedded inside paragraphs. It reads visual positioning, spacing, indentation, and structural boundaries to do so. Your code receives blocks instead of rebuilding them from coordinates.
SDK 12.0 added Markdown output to the Document Structure API. It carries paragraphs in reading order, heading levels 1 through 6, nested lists, and tables into the format RAG and LLM pipelines ingest. The output is data for a pipeline, not a visual reproduction of the page. It runs on Windows and Linux in every supported SDK language and is included in an existing Smart Data Extraction license.
What this does not cover: Smart Data Extraction does not convert PDFs to Word, Excel, or PowerPoint. The Structured Output Module does that.
When a PDF Has No Text Layer
A scanned PDF stores each page as an image. TextExtractor analyzes textual content only, so rasterized text in a scan, and vectorized text where glyphs are converted to outlines, returns nothing. If a page shows words on screen and extraction returns an empty string, the page is an image.
OCR generates the missing text layer. The OCR Module is a separate add-on module with its own license. Run it first, then extract. OCR text is stored as invisible text, and TextExtractor extracts invisible text by default. The OCR capability page covers engines and setup, so this page does not repeat them.
For the full pipeline from scan to usable text:
Encoding, Ligatures, and Character Edge Cases
A PDF font maps glyph codes to characters. When the mapping is complete, extraction returns the characters you see. When it is missing or wrong, any extractor that reads the text layer hits the same limit: the glyph is on the page, and the character is not recoverable from the file.
TextExtractor normalizes all text to Unicode and expands ligatures by default. The default mapping covers fi, ff, fl, ffi, ffl, ch, cl, ct, ll, ss, fs, st, oe, and OE, so a fi glyph extracts as two letters and search matching stays consistent. Pass the e_no_ligature_exp flag to keep ligature characters as they are.
Hidden and duplicated text get the same treatment. The extractor removes duplicated strings that generators use to fake bold or drop shadows, and it extracts invisible text. Flags change each default:
Extraction Flags in Code
Two more options matter for prose. Passing true for the dehyphen argument of the text call removes hyphens that split a word across two lines, and it has no effect on Tagged PDF files. Right-to-left documents need the extractor set to right-to-left mode before you read the page.
Test with the fonts your documents use. Extract one page from each source system and compare the strings with the rendered page before you scale out.
Language and Platform Support
The Server SDK exposes text extraction through native bindings for C#, Java, Python 3, Node.js, and C++. Each has its own get-started guide:
Step-by-step code in one language
Base text layer extraction:
Windows, Linux, and macOS. Windows support is x64 only (AMD64), and Windows on ARM is not supported.
Smart Data Extraction:
Windows and Linux, x64 only. ARM and 32-bit platforms are not supported, and macOS is not supported.
Deployment:
On-premises server, cloud VM, container, or Kubernetes. The SDK processes documents locally, so no document content leaves your environment.
For step-by-step code in one language, read the walkthroughs:
Extract text from a PDF in Java
Extract text from a PDF in Node.js
Extract text from a PDF in C# and .NET
Evaluation Notes for Your Technical Lead
A single-column text layer is a reasonable job for an open-source library. The commercial case rests on recovering structure from messy layouts, which is where plain text extraction stops.

Deployment model:
A self-hosted library embedded in your application. Document content is never transmitted to Apryse.
Licensing:
The base license covers text layer extraction. Smart Data Extraction and the OCR Module each need an add-on license.
Scope:
Text, word and line positions, document structure, and bounding rectangles. Conversion to Word, Excel, or PowerPoint is a different module.
Ownership:
Your code owns queues, scheduling, retries, and storage. The SDK provides no work queue, scheduler, or batch orchestration.



