Engineering Journal
Pdf Processor
Pdf Processor

Extracting Bold, Italic, and Underline from PDFs Without Guessing

2026-05-15

TLDR

Regex matching PostScript font names (e.g. /bold/i.test(fontName)) fails when PDFs contain subset prefixes (ABCDEF+Font12) or synthetic styling. Authoritative font styling requires querying page.commonObjs for true .bold and .italic boolean properties, checking matrix transform shear components (transform[2] > 0.01) for synthetic italic rendering, and pairing horizontal vector segments (~0.35 * fontSize) to detect underlines.
Typographic StylePrimary Metadata SourceFallback / Synthetic CheckHTML Output Tag
Boldpage.commonObjs.get(fontName).boldCleaned PostScript name regex<strong>
Italicpage.commonObjs.get(fontName).italicMatrix Shear Math.abs(transform[2]) > 0.01<em>
UnderlineVector Line Segment PairingVertical proximity math ($\le 0.35 \times \text{fontSize}$)<u>

Technical implementation

// Extract authoritative font styles using page.commonObjs and transform shear matrix
export function buildFontStyleMap(page, textContentItems) {
  const fontStyleMap = {};
  const uniqueFontNames = [...new Set(textContentItems.map(item => item.fontName).filter(Boolean))];

for (const fontName of uniqueFontNames) { const fontObj = page.commonObjs.get(fontName); const cleanedName = (fontObj?.name || fontName).replace(/^[A-Z]{6}\+/, '');

fontStyleMap[fontName] = { bold: !!fontObj?.bold || /bold|heavy|black/i.test(cleanedName), italic: !!fontObj?.italic || /italic|oblique|slanted/i.test(cleanedName) }; }

return fontStyleMap; }

// Evaluate synthetic italic slanting and format HTML inline wrappers export function wrapInlineStyles(textString, textItemStyle, transformMatrix) { let html = escapeHtml(textString); // Synthetic Italic check via horizontal shear matrix component (transform[2]) const isSyntheticItalic = Math.abs(transformMatrix[2]) > 0.01; const isItalic = textItemStyle.italic || isSyntheticItalic;

if (textItemStyle.underlined) html = &lt;u&gt;${html}&lt;/u&gt;; if (isItalic) html = &lt;em&gt;${html}&lt;/em&gt;; if (textItemStyle.bold) html = &lt;strong&gt;${html}&lt;/strong&gt;;

return html; }

Rule of thumb: Read .bold and .italic properties from page.commonObjs, using matrix shear components (transform[2]) to detect synthetic slant rendering.
Read this post in the full Engineering Journal →