Pdf Processor
Under the Hood: Rebuilding a Stacked Fraction the Text Layer Never Gave You
TLDR
PDF text streams break display math equations into disjointed text items across multiple baseline offsets, omitting fraction bars entirely (which exist as vector lines in operator lists). Porting PDFium C++ math heuristics to JavaScript run-granularity uses a single core metric: comparing each atom's vertical offset ($\Delta Y$) against the local math axis scaled by body font size.| Atom Typographic Position | Vertical Offset Threshold ($\Delta Y$) | Structural Math Output |
|---|---|---|
| Numerator Territory | $\Delta Y > +0.34 \times \text{fontSize}$ | \frac{numerator}{...} |
| Denominator Territory | $\Delta Y < -0.30 \times \text{fontSize}$ | \frac{...}{denominator} |
| Sub / Superscript | $ | \Delta Y |
Technical math reconstruction engine
// Evaluate relative atom Y-offset from dominant local math axis
export function classifyMathAtomOffset(atom, localMathAxisY, baseFontSizePt) {
const dy = atom.yCenter - localMathAxisY;
if (dy > 0.34 * baseFontSizePt) { return 'NUMERATOR'; } else if (dy < -0.30 * baseFontSizePt) { return 'DENOMINATOR'; } else if (atom.fontSizePt < 0.85 * baseFontSizePt) { return dy > 0 ? 'SUPERSCRIPT' : 'SUBSCRIPT'; }
return 'ON_AXIS'; }
// Distinguish overlapping overset annotations from trailing scripts export function isOversetAnnotation(atom, baseOperand) { // Oversets overlap base operand's X-range; scripts start at/after right edge const overlapThreshold = baseOperand.xMin + 0.3 * (baseOperand.xMax - baseOperand.xMin); return atom.xMin < overlapThreshold; }
<!-- Formatted Math Paragraph Output -->
<p data-math=""><span class="pdf-math">$x \overset{\text{maps to}}{\rightarrow} y = f_n(x) = \left(1+\frac{1}{x^n}\right)^n$</span></p>
Rule of thumb: Reconstruct 2D math layout by evaluating atom Y-offsets relative to local math axes, separating stretch delimiters from base font size metrics.
Read this post in the full Engineering Journal →