What's happening
You ran OCR on a scanned PDF. The text is now searchable, and you can copy it out. But your fill code (pypdf, pdf-lib, an API) reports zero form fields, and the document still behaves like a flat image when you try to populate it.
OCR and form-field creation are two separate operations. OCR generates a text layer rendered over the rasterized page so the characters are selectable and indexable. It does not add AcroForm widgets, which is what PDF fillers actually write to. Adobe's own documentation describes this directly for the Prepare Form workflow: scanned documents go through OCR first, OCR does not modify the original page content, and the page only changes once form-field annotations are added in a second step. In pypdf, reader.get_fields() returns None on a PDF that only has a text layer, because there is no /AcroForm/Fields array to read yet.
Three ways to fix it
- Add fields with Adobe Acrobat's Prepare Form. After OCR, choose All tools, then Prepare a form, then Create form. Acrobat auto-detects rectangles, underlines, and dingbat boxes and converts them to fillable widgets. It does not detect combo boxes, list boxes, or barcodes, so spot-check the result.
- Use a vision-based field detector via API. If you do not want to open Acrobat for every document, Anvil's Document AI reads the visual layout of a flat or scanned PDF and creates the fillable layer for you, including signer assignment for documents that need signatures.
- Skip fields entirely and stamp text by coordinate. If you only need to write data onto known positions, pypdf and pdf-lib can draw text at x/y coordinates without ever creating widgets. This is the fastest path for bulk fill, but the resulting PDF is still flat and not interactively fillable by a human user.
Sanity check before you blame the tool
If a field detector finds zero fields on a PDF you know has form regions, scan quality is usually the cause. Faint lines, skew, and sub-300 DPI scans confuse both OCR and field detection. Re-scan the original at 300 DPI or higher, or run a deskew pass first, before retrying.
Back to All Questions