Pro edition
Classifier — Deep Reference
At a glance
Section titled “At a glance”This page is the contract-level reference for the NextPDF Pro document classifier. The surface is one orchestrator, NextPDF\Pro\Classifier\DocumentClassifier, and its collaborators: StructureAnalyzer, LanguageDetector, and the ClassifierInterface strategy with its default HeuristicClassifier. Results arrive as an immutable ClassificationResult carrying a DocumentType, a confidence in [0.0, 1.0], detected ClassificationFeature values, and an ISO 639-1 language code. Classification is rule-based and deterministic: no model inference, no randomness, no network call, no filesystem access. This page states the public API, the observable behavior contract, and the failure modes.
Availability & licensing
Section titled “Availability & licensing”This capability ships in NextPDF Pro (nextpdf/pro) and activates with a Pro-tier license envelope. A deployment without that entitlement does not load the capability’s classes. Compare editions and get a license.
No runtime capability flag gates this module. The classifier classes are available whenever nextpdf/pro is installed.
Public API surface
Section titled “Public API surface”| Symbol | Parameters | Default behavior | Returns | Throws or fails with | Notes |
|---|---|---|---|---|---|
DocumentClassifier | constructor: StructureAnalyzer, LanguageDetector, ClassifierInterface | Orchestrates structure analysis, strategy classification, and language detection | — | — | final; inject collaborators only for custom strategies |
DocumentClassifier::create() | none | Builds default collaborators with HeuristicClassifier as the strategy | self | — | Deterministic default configuration |
DocumentClassifier::classifyFromText() | $text, $pdfData = '' | Empty $pdfData uses an empty structure; non-empty raw bytes add structural signals | ClassificationResult | Does not throw; sparse input lowers confidence | Language detection always runs on $text |
DocumentClassifier::classifyFromFile() | string $pdfData | Scans content streams, recovers §9.4 text, analyzes structure, classifies | ClassificationResult | Does not throw; unreadable streams reduce recovered text | Bounded byte scan, not a full PDF parse |
ClassifierInterface::classify() | $text, StructureAnalysis $structure | Strategy contract consumed by the orchestrator | ClassificationResult | Implementation-defined | Extension point for custom classification strategies |
ClassifierInterface::supports() | string $contentType | Content-type probe for composite classifiers | bool | — | Receives a MIME type or content descriptor |
HeuristicClassifier | none | Default strategy: keyword dictionaries plus structural heuristics | — | Does not throw | final; supports() accepts application/pdf and text/plain |
StructureAnalyzer::analyze() | string $pdfData | Regex scan of raw bytes; no full PDF parse | StructureAnalysis | Does not throw | Counts pages, images, fonts; detects form and signature fields |
LanguageDetector::detect() | string $text | Trigram-profile match with CJK script-range pre-check | non-empty-string ISO 639-1 code | Does not throw | Falls back to en below the acceptance threshold |
LanguageDetector::detectWithConfidence() | string $text | As detect(), with the confidence exposed | array{language: non-empty-string, confidence: float} | Does not throw | Short text returns en with confidence 0.0 |
ClassificationResult | constructor: $type, $confidence, $features, $language, $metadata = [] | Immutable value object | — | — | final readonly; metadata carries scores and method |
ClassificationResult::isConfident() | float $threshold = 0.7 | Compares confidence against the threshold | bool | — | Documented gate for manual-review routing |
StructureAnalysis | constructor: $pageCount, $imageCount, $fontCount, $hasFormFields, $hasSignatureFields, $imageDensity, $detectedFeatures | Immutable value object produced by StructureAnalyzer | — | — | final readonly; imageDensity is images per page |
DocumentType | string-backed enum, 12 cases | Cases: Invoice, Contract, Form, Report, Letter, Receipt, Legal, Medical, Financial, Technical, Academic, Other | backing values invoice … other | — | label() returns a human-readable name |
ClassificationFeature | string-backed enum, 7 cases | Cases: HasTables, HasHeaders, HasSignatures, HasLogos, HasBarcodes, HasForms, IsScanned | backing values has_tables … is_scanned | — | Structural signals fed into classification |
Entry-point signatures
Section titled “Entry-point signatures”public static function create(): self
public function classifyFromText(string $text, string $pdfData = ''): ClassificationResult
public function classifyFromFile(string $pdfData): ClassificationResultpublic function classify(string $text, StructureAnalysis $structure): ClassificationResult;
public function supports(string $contentType): bool;public function analyze(string $pdfData): StructureAnalysispublic function detect(string $text): string
public function detectWithConfidence(string $text): arraypublic function __construct( public DocumentType $type, public float $confidence, public array $features, public string $language, public array $metadata = [],) {}
public function isConfident(float $threshold = 0.7): boolBehavior contract
Section titled “Behavior contract”Pipeline order
Section titled “Pipeline order”DocumentClassifier runs structure analysis, then strategy classification, then language detection, and assembles a ClassificationResult. The strategy supplies the type, confidence, features, and metadata; the detector supplies the language. classifyFromText() with no PDF bytes substitutes an empty structure: zero pages, zero counts, no features. classifyFromFile() derives both the structure and the text from the same raw bytes.
Heuristic scoring
Section titled “Heuristic scoring”HeuristicClassifier scores lowercased text against per-document-type keyword dictionaries, normalized by text length. The specific dictionaries, weights, and thresholds are implementation detail and are not published. Structural signals then adjust the scores: matching ClassificationFeature values boost their associated types; documents above a page threshold bias away from Letter and Receipt; multi-page documents with headers and tables receive a Report boost; a detected form feature adds a strong Form signal. The highest score wins and maps to a DocumentType. A bounded normalization maps the raw score into [0.0, 1.0]. A sub-minimum score yields DocumentType::Other with a small non-zero confidence floor. The result metadata carries the per-type scores map and method: heuristic. HeuristicClassifier alone reports language en; DocumentClassifier overrides it with the detector output.
Language detection
Section titled “Language detection”A script-range check for CJK text runs before trigram scoring. Hangul dominance selects ko; any kana selects ja; otherwise a sufficient ideograph ratio selects zh. All other text is scored by character-trigram frequency against ten built-in profiles. The possible return values are the ISO 639-1 codes en, zh, ja, ko, de, fr, es, pt, it, and nl. Text below a minimum length returns en with confidence 0.0. A result below the acceptance threshold with a narrow margin also returns en. Confidence reflects the margin between the best and second-best profile scores.
File text recovery
Section titled “File text recovery”classifyFromFile() scans the raw bytes for stream/endstream segments. Each segment is tried as Flate data under a bounded inflation cap; on failure the raw segment bytes are used. When the adjacent stream dictionary declares a PNG predictor in /DecodeParms, the reversal honors the Predictor, Columns, Colors, and BitsPerComponent parameters per ISO 32000-2:2020 §7.4.4.4, using the Filter module’s DecodeParms and PngPredictor classes. Text is then recovered from the §9.4 text-showing operators: literal strings shown with Tj and literal strings inside TJ arrays. The classifier scores recovered text; it does not depend on visual layout.
Structure analysis
Section titled “Structure analysis”StructureAnalyzer::analyze() counts page, image, and font tokens in the raw bytes, detects /AcroForm and signature fields, and derives the image density. Feature detection is heuristic: repeated rectangle drawing suggests tables, large font-size declarations suggest headers, and high image density with few fonts suggests a scanned document. Counts reflect tokens visible in the raw bytes; structures serialized inside compressed object streams are not counted.
Determinism
Section titled “Determinism”The whole pipeline is a pure function of its input bytes. Identical input produces an identical ClassificationResult. There is no model inference, no randomness, no network call, and no filesystem access.
Edge cases & failure modes
Section titled “Edge cases & failure modes”- Empty or near-empty text yields a low-confidence
DocumentType::Otherby design. Branch onisConfident()rather than on the type alone. - No public method of this module throws. Streams that fail decompression are scanned raw; malformed or unsupported predictor parameters fall back to the unfiltered bytes.
- Text recovery matches literal-string
TjandTJforms only. Hexadecimal strings, text inside encrypted content, and operators split across streams are not recovered, which reduces the text available to score. - The decompression cap bounds memory during stream inflation and resists decompression-bomb input. Content beyond the cap is not inflated.
- Image-only or heavily compressed PDFs recover little text; expect low-confidence results and route them to manual review.
- Language detection below the minimum text length returns
enwith confidence0.0; very short strings never produce a non-English result. - The twelve document types and ten language profiles are fixed for this release. Extension is via a custom
ClassifierInterfaceimplementation, not by editing built-in data. - No cryptographic operation occurs in this module, so there is no FIPS-mode-specific behavior.
Conformance
Section titled “Conformance”| Claim | Standard | Clause |
|---|---|---|
File classification recovers text shown with the Tj operator. | ISO 32000-2:2020 | §9.4 |
File classification recovers literal strings inside TJ array operators. | ISO 32000-2:2020 | §9.4 |
PNG-predictor reversal honors the Predictor, Columns, Colors, and BitsPerComponent filter parameters. | ISO 32000-2:2020 | §7.4.4.4 |
Language codes follow ISO 639-1; this is a product-grounded statement of the output format, not a cited conformance claim. All clauses are paraphrased; NextPDF does not reproduce normative text. These are capability statements. Classification is heuristic and best-effort: the module asserts determinism, not accuracy, and callers own the decision threshold.
Development notes
Section titled “Development notes”- Available since
nextpdf/pro2.2.0; current innextpdf/pro3.1.0. - Use
DocumentClassifier::create()for the default pipeline. Inject collaborators only to supply a customClassifierInterfacestrategy. - Treat below-threshold results as uncertain and route them to manual review;
isConfident()with its0.7default is the documented gate. - The module stores nothing, emits no telemetry, and logs no input. If callers persist
metadata, review it against their own data-handling policy first. - Keyword scoring and trigram counting are linear in text length. Structure analysis is linear in PDF byte length under the bounded decompression cap. The page budget is 1000 ms wall time and 64 MB peak memory.
Publication boundary
Section titled “Publication boundary”This page documents externally observable behavior and the supported public API surface only. Internal namespace paths, helper classes, mechanism tables, runbook filenames, and ticket prefixes are out of scope.
See also
Section titled “See also”- Classifier (capability) — install, quick start, and production routing samples.
- Extraction — Deep Reference — the full text-extraction surface for richer input text.
- Filter — Deep Reference —
DecodeParmsandPngPredictor, used during file classification. - Diff — Deep Reference — the sibling byte-level document comparison surface.