PDF, OCR, and the Deliberate Exceptions

anydoc’s shared model is powerful because many document formats can be normalized into the same structural vocabulary. PDF shows why that path is not universal. This chapter examines the project’s direct PDF route and the boundary between local text extraction and hosted OCR, so readers can choose a path based on capability, completeness, and data handling rather than assuming every format should pass through the same intermediate representation.

Why PDF bypasses the shared model

For the model-backed formats, anydoc parses source structures into blocks, inlines, tables, notes, and assets before the common Markdown serializer takes over. PDF uses a different route: pdf-inspector produces Markdown directly. The public Rust API routes PDF conversion to that frontend, and to_document is unsupported for PDFs because the project does not provide a PDF form of the shared document model.

That is an explicit boundary, not an accidental omission. The repository does not claim that PDF content can be inspected through the same model as an Office package. Instead, it exposes the result that the PDF extraction path can produce and keeps the model contract honest. A caller that needs a Markdown string can use the conversion entry point; a caller that needs the shared Document representation cannot assume that every accepted input has one.

The distinction matters for downstream design. On a Word or OpenDocument input, a consumer can stop at the model and inspect retained assets before choosing how to render them. On a PDF, the documented route returns Markdown directly. If a workflow requires a common intermediate structure across PDFs and office documents, that workflow must account for this difference rather than quietly treating the two paths as equivalent.

It also changes what “preservation” can mean. A model-backed input exposes a place where links, notes, and embedded objects can remain structured before final rendering. The documented PDF route does not make the same promise. That does not make the direct Markdown result unusable; it means a downstream application should not infer model-level access from the fact that both inputs eventually yield Markdown. The output contract is shared at the text boundary, not necessarily at every intermediate state.

A separate path can be the more honest engineering choice when the evidence supports one extraction contract but not another. The important question is not whether the code has fewer branches. It is whether each public branch tells callers what state it owns, what it returns, and which capabilities it lacks. PDF’s direct route makes those limits visible instead of presenting a uniform object whose fields would be uncertain.

The PDF path also treats scanned pages as a completeness problem. Text extraction can succeed for some pages while other pages contain only images. anydoc does not return the searchable pages as if they represented the whole document. It reports a NeedsOcr failure with the 1-indexed pages that still need optical character recognition. The caller can then decide whether to provide another capability or keep the document out of a supposedly complete text corpus.

The page check is deliberately conservative in two stages. An initial PDF inspection can flag pages that look image-heavy or otherwise suspicious.