Engineering Journal
Pdf Processor
Pdf Processor

Under the Hood: The Three-Tier PDF Extraction Model

2026-06-04

TLDR

PDF.js exposes three distinct document reading APIs: getStructTree() (semantic ground truth), getOperatorList() (geometric paint stream ground truth), and getTextContent() (derived typographic text convenience API). Designing a browser-side extractor as a top-down cascade (Tier 1 $\rightarrow$ Tier 2 $\rightarrow$ Tier 3) enables fast exits on well-tagged documents while reserving expensive spatial heuristics for untagged fallbacks.
Extraction API TierPDF Format SourceMarked Content ID (MCID) SupportPrimary Structural Output
Tier 1: getStructTree()Cross-Reference TreeExplicit Leaf MCIDsExact Table, TR, TD Nodes
Tier 2: getOperatorList()Raw Paint Stream (q/Q/cm)BMC/BDC/EMC StackFull-height Column Vector Rules
Tier 3: getTextContent()Derived convenience APINonePositioned Text Items & Advance Widths

Technical three-tier cascade architecture

// Top-Down Three-Tier PDF Extraction Cascade Engine
export async function extractPdfPageCascading(page, pdfjsPage) {
  // Tier 1: Attempt Semantic Structure Tree Extraction via MCID Join
  const structTree = await pdfjsPage.getStructTree();
  if (structTree && structTree.children?.length > 0) {
    const opList = await pdfjsPage.getOperatorList();
    const mcidMap = buildMcidToTextMap(opList);
    const semanticDoc = parseStructTreeNodes(structTree, mcidMap);
    if (semanticDoc.isComplete) return semanticDoc;
  }

// Tier 2: Attempt Explicit Paint Stream Geometry Extraction const opList = await pdfjsPage.getOperatorList(); const columnRules = findFullHeightVerticalRules(opList, page.viewBox); if (columnRules.length > 0) { return assembleLayoutFromExplicitRules(page, columnRules); }

// Tier 3: Fallback to Spatial Heuristic Extraction const textContent = await pdfjsPage.getTextContent(); const pageScaleS = calculateModeFontBaseline(textContent.items); return executeBipartiteSpatialExtraction(textContent.items, pageScaleS); }

Rule of thumb: Cascade PDF extraction top-down from getStructTree() to getOperatorList() geometry before falling back to spatial getTextContent() heuristics.
Read this post in the full Engineering Journal →