Skip to content
getnextpdf.com

Pro edition

Classifier — Deep Reference

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.

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.

SymbolParametersDefault behaviorReturnsThrows or fails withNotes
DocumentClassifierconstructor: StructureAnalyzer, LanguageDetector, ClassifierInterfaceOrchestrates structure analysis, strategy classification, and language detectionfinal; inject collaborators only for custom strategies
DocumentClassifier::create()noneBuilds default collaborators with HeuristicClassifier as the strategyselfDeterministic default configuration
DocumentClassifier::classifyFromText()$text, $pdfData = ''Empty $pdfData uses an empty structure; non-empty raw bytes add structural signalsClassificationResultDoes not throw; sparse input lowers confidenceLanguage detection always runs on $text
DocumentClassifier::classifyFromFile()string $pdfDataScans content streams, recovers §9.4 text, analyzes structure, classifiesClassificationResultDoes not throw; unreadable streams reduce recovered textBounded byte scan, not a full PDF parse
ClassifierInterface::classify()$text, StructureAnalysis $structureStrategy contract consumed by the orchestratorClassificationResultImplementation-definedExtension point for custom classification strategies
ClassifierInterface::supports()string $contentTypeContent-type probe for composite classifiersboolReceives a MIME type or content descriptor
HeuristicClassifiernoneDefault strategy: keyword dictionaries plus structural heuristicsDoes not throwfinal; supports() accepts application/pdf and text/plain
StructureAnalyzer::analyze()string $pdfDataRegex scan of raw bytes; no full PDF parseStructureAnalysisDoes not throwCounts pages, images, fonts; detects form and signature fields
LanguageDetector::detect()string $textTrigram-profile match with CJK script-range pre-checknon-empty-string ISO 639-1 codeDoes not throwFalls back to en below the acceptance threshold
LanguageDetector::detectWithConfidence()string $textAs detect(), with the confidence exposedarray{language: non-empty-string, confidence: float}Does not throwShort text returns en with confidence 0.0
ClassificationResultconstructor: $type, $confidence, $features, $language, $metadata = []Immutable value objectfinal readonly; metadata carries scores and method
ClassificationResult::isConfident()float $threshold = 0.7Compares confidence against the thresholdboolDocumented gate for manual-review routing
StructureAnalysisconstructor: $pageCount, $imageCount, $fontCount, $hasFormFields, $hasSignatureFields, $imageDensity, $detectedFeaturesImmutable value object produced by StructureAnalyzerfinal readonly; imageDensity is images per page
DocumentTypestring-backed enum, 12 casesCases: Invoice, Contract, Form, Report, Letter, Receipt, Legal, Medical, Financial, Technical, Academic, Otherbacking values invoiceotherlabel() returns a human-readable name
ClassificationFeaturestring-backed enum, 7 casesCases: HasTables, HasHeaders, HasSignatures, HasLogos, HasBarcodes, HasForms, IsScannedbacking values has_tablesis_scannedStructural signals fed into classification
public static function create(): self
public function classifyFromText(string $text, string $pdfData = ''): ClassificationResult
public function classifyFromFile(string $pdfData): ClassificationResult
public function classify(string $text, StructureAnalysis $structure): ClassificationResult;
public function supports(string $contentType): bool;
public function analyze(string $pdfData): StructureAnalysis
public function detect(string $text): string
public function detectWithConfidence(string $text): array
public function __construct(
public DocumentType $type,
public float $confidence,
public array $features,
public string $language,
public array $metadata = [],
) {}
public function isConfident(float $threshold = 0.7): bool

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.

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.

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.

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.

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.

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.

  • Empty or near-empty text yields a low-confidence DocumentType::Other by design. Branch on isConfident() 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 Tj and TJ forms 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 en with confidence 0.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 ClassifierInterface implementation, not by editing built-in data.
  • No cryptographic operation occurs in this module, so there is no FIPS-mode-specific behavior.
ClaimStandardClause
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.

  • Available since nextpdf/pro 2.2.0; current in nextpdf/pro 3.1.0.
  • Use DocumentClassifier::create() for the default pipeline. Inject collaborators only to supply a custom ClassifierInterface strategy.
  • Treat below-threshold results as uncertain and route them to manual review; isConfident() with its 0.7 default 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.

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.