Extracting Bold, Italic, and Underline from PDFs Without Guessing
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 Style | Primary Metadata Source | Fallback / Synthetic Check | HTML Output Tag |
|---|---|---|---|
| Bold | page.commonObjs.get(fontName).bold | Cleaned PostScript name regex | <strong> |
| Italic | page.commonObjs.get(fontName).italic | Matrix Shear Math.abs(transform[2]) > 0.01 | <em> |
| Underline | Vector Line Segment Pairing | Vertical 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 = <u>${html}</u>; if (isItalic) html = <em>${html}</em>; if (textItemStyle.bold) html = <strong>${html}</strong>;
return html; }
Rule of thumb: Read.boldand.italicproperties frompage.commonObjs, using matrix shear components (transform[2]) to detect synthetic slant rendering.