Why PDFs read aloud so badly

Headers, footers, page numbers, and captions live in the same text layer as the prose. Why most read-aloud tools narrate them, and what it takes to stop.

A real layout pass in ONarrator: prose stays in the reading queue while headers, captions, figures, and page numbers are excluded.

In short: A PDF is a page drawing, not a structured document. Useful narration starts by detecting what is prose and what is page furniture.

Open almost any PDF in a read-aloud tool and the same thing happens. Somewhere around the bottom of the first page, the voice says something like:

...the resulting distribution is therefore stable. 4 Preprint. Under review. Figure 2: Overview of the pipeline. arXiv:2601.04412v1 [cs.CL] 12 Jan 2026

Three different things collided there: the end of a sentence, a page footer, a figure caption, and a sidebar watermark. To a listener it is noise. To the software it was all just text, in order.

A PDF has no idea what a paragraph is

This is the part that surprises people. A PDF is not a document in the sense that an EPUB or an HTML page is a document. It is closer to a set of drawing instructions: put this glyph at this coordinate, in this font, at this size. There is no <p>. There is no "this is a heading" and no "this is a footnote". Those distinctions exist only in your eyes.

So when a tool extracts text from a PDF, what it gets back is a stream of glyphs in roughly the order they were drawn, which is often, but not reliably, the order they were meant to be read. A page number sitting alone at the bottom is, structurally, indistinguishable from a sentence. It is text at a position. Nothing marks it as skippable.

That is the whole problem. Everything else follows from it.

What goes wrong, specifically

Four failures show up again and again:

  • Running headers and footers. The paper's title, or the chapter name, repeated at the top of all forty pages. Narrated forty times.
  • Page numbers. A bare number interrupting a sentence that continues across the page break.
  • Figure and table content. Axis labels, legend entries, and cell values read as though they were prose. A table of results becomes a long string of numbers.
  • References and footnotes. Fifteen pages of citations narrated in full, or a superscript marker pulling a footnote into the middle of a sentence.

None of these are edge cases. They are what an academic PDF, a government report, or a scanned book chapter looks like on every single page.

Reading order is a second, separate problem

Even after you decide what to read, you have to decide in what order. Extraction follows the order glyphs were placed in the file, and for a two-column layout that order is frequently wrong. The extractor runs across the page instead of down the column, interleaving two unrelated columns line by line.

Some documents extract in perfect reading order. Some interleave. There is no flag in the file telling you which kind you have.

Treating layout as something to detect

The approach ONarrator takes is to stop guessing from the text and instead look at the page as a picture.

Before narrating, each page is run through a document layout model, the same class of object detector used for finding faces or cars in photographs, trained instead on document regions. It returns typed boxes: this rectangle is body text, this one is a header, this is a figure, this is a caption, this is a formula, this is a table.

Narration then uses those regions as a mask. Text whose glyphs fall inside a header, footer, page-number, figure, caption, or reference region is skipped. Text inside body regions is kept, split into sentences, and queued for speech. Headings get isolated into their own chunks so they are spoken as headings rather than run into the paragraph below.

The result is dull in the best way. The voice reads the prose, and only the prose.

Why the masking is geometric, not textual

A detail worth stating, because it is where a naive implementation breaks: the mask has to be applied using the actual on-page geometry of each glyph, not by matching character ranges.

It is tempting to record "characters 1400-1480 are a footer" and skip that range. But character offsets and visual position are only loosely related in a PDF, and any reflow, re-extraction, or difference in extractor version shifts them. Testing each line's rendered rectangle against the detected regions is stable in a way that offset bookkeeping is not.

Failing open

One design rule matters more than the rest: when layout detection fails, narrate everything.

If the model has not run yet, or errors on a particular page, or the document is one of the odd ones where nothing is confidently classified, the app reads the whole page. A listener who hears an extra page number is mildly annoyed. A listener whose book goes silent because a classifier was uncertain has lost the feature entirely.

So the structure is treated as an enhancement layered on top of a working baseline, never as a precondition for reading. The first time you open a freshly imported PDF it may narrate everything, because the layout pass has not finished; later opens use the cached result.

What is still unsolved

Being honest about the remaining gaps:

  • Multi-column reordering. Detected regions tell you a column exists; using that to fully re-sequence reading order across columns is not done yet.
  • Inline mathematics. Display formulas can be detected and skipped. Maths inline within a sentence is still raw extracted glyphs, and it sounds like it.
  • Scanned PDFs. A page with no text layer has nothing to narrate. That needs OCR, which is a different problem entirely.

The layout problem is not solved. But the difference between narrating the prose and narrating everything on the page is most of the distance between a document you can listen to and one you cannot.