Detect Scanned PDF Document
A scanned document is a page image with no text objects, so text extraction returns nothing useful and OCR is the right tool instead. Counting font objects is a fast way to tell the two apart without decoding any content: a document that draws text has to embed or reference fonts, and a page image does not.
Doing it
objTypes, err := pdfReader.Inspect()
if err != nil {
return err
}
fontObjs, ok := objTypes["Font"]
if !ok || fontObjs < 2 {
fmt.Println("SCANNED!")
} else {
fmt.Println("not scanned (has text objects)")
}The threshold is two, not one. A single Font object usually belongs to a scanner’s own
label or a stamped page number rather than to document text, so treating one font as
“scanned” catches the common case of a scan with a burnt-in header.
Inspect reads the cross reference table and looks at the Type and Subtype of each
dictionary, so the cost is proportional to the number of objects rather than the size of
the page content. See inspect PDF objects for what else the
histogram contains.
Limitations
This is a heuristic on the object graph, not a measurement of extractable text. It gets two cases wrong in opposite directions.
A searchable scan - a page image with an invisible OCR text layer behind it, which is what most scanning software produces now - has fonts, so it is reported as not scanned. That is arguably the right answer, since extraction will work, but the page is still an image.
A document with a handful of fonts and no visible text, such as a vector drawing that carries an unused font resource, is reported as not scanned even though extraction returns nothing.
If you need certainty rather than a screen, extract the text and check whether the result is empty. That costs a full parse of every page, which is exactly what this check exists to avoid, so the usual arrangement is to run this first and fall back to extraction on the files it flags.
Sample input

Run the example
detectScanned opens each file named on the command line, prints its page count, and
classifies it. It never returns a scanned or not-scanned value to the caller, so adapt
it if you want the verdict programmatically.
git clone https://github.com/unidoc/unipdf-examples.git
cd unipdf-examples/analysis
go run pdf_detect_scanned.go input.pdfIf this is your first time using UniPDF, follow the getting started guide to create an API key and set up your development environment.
View the full source
Sample output
sample.pdf (1 pages) - SCANNED!