From 3be623c296ac8ccb6e39343b1ba68dd18bbf4ce6 Mon Sep 17 00:00:00 2001 From: Konstantin Darutkin Date: Fri, 28 Mar 2025 22:48:00 +0000 Subject: [PATCH] feature(tables): add cmap table format 6 --- docs/glyph-inspector.html | 8 ++++++-- src/encoding.mjs | 2 +- src/tables/cmap.mjs | 17 ++++++++++++++++- test/fonts/PDF-Embedded-Calibri-Subset.ttf | Bin 0 -> 22448 bytes test/tables/cmap.spec.mjs | 16 +++++++++++++++- 5 files changed, 38 insertions(+), 5 deletions(-) create mode 100644 test/fonts/PDF-Embedded-Calibri-Subset.ttf diff --git a/docs/glyph-inspector.html b/docs/glyph-inspector.html index cc49e23e..5b809d2b 100644 --- a/docs/glyph-inspector.html +++ b/docs/glyph-inspector.html @@ -387,8 +387,12 @@

Free Software

hline('yMin', font.tables.head.yMin); hline('Ascender', font.tables.hhea.ascender); hline('Descender', font.tables.hhea.descender); - hline('Typo Ascender', font.tables.os2.sTypoAscender); - hline('Typo Descender', font.tables.os2.sTypoDescender); + + // Some PDF-embedded fonts might not have the OS/2 table + if (font.tables.os2) { + hline('Typo Ascender', font.tables.os2.sTypoAscender); + hline('Typo Descender', font.tables.os2.sTypoDescender); + } } window.redraw = function(options = { withColors: true, withVariations: true }) { diff --git a/src/encoding.mjs b/src/encoding.mjs index 0902b8c8..2f7b874c 100644 --- a/src/encoding.mjs +++ b/src/encoding.mjs @@ -324,7 +324,7 @@ function addGlyphNamesAll(font) { glyph = font.glyphs.get(i); if (font.cffEncoding) { glyph.name = font.cffEncoding.charset[i]; - } else if (font.glyphNames.names) { + } else if (font.glyphNames && font.glyphNames.names) { glyph.name = font.glyphNames.glyphIndexToName(i); } } diff --git a/src/tables/cmap.mjs b/src/tables/cmap.mjs index 6193a056..634762db 100644 --- a/src/tables/cmap.mjs +++ b/src/tables/cmap.mjs @@ -99,6 +99,19 @@ function parseCmapTableFormat4(cmap, p, data, start, offset) { } } +function parseCmapTableFormat6(cmap, p) { + cmap.length = p.parseUShort(); + cmap.language = p.parseUShort(); + + cmap.firstCode = p.parseUShort(); + cmap.entryCount = p.parseUShort(); + cmap.glyphIndexMap = {}; + + for (let i = 0; i < cmap.entryCount; i += 1) { + cmap.glyphIndexMap[cmap.firstCode + i] = p.parseUShort(); + } +} + function parseCmapTableFormat14(cmap, p) { const varSelectorList = {}; @@ -216,6 +229,8 @@ function parseCmapTable(data, start) { parseCmapTableFormat12or13(cmap, p, cmap.format); } else if (cmap.format === 4) { parseCmapTableFormat4(cmap, p, data, start, offset); + } else if (cmap.format === 6) { + parseCmapTableFormat6(cmap, p); } else { throw new Error( 'Only format 0 (platformId 1, encodingId 0), 4, 12 and 14 cmap tables are supported ' + @@ -410,4 +425,4 @@ function makeCmapTable(glyphs) { export default { parse: parseCmapTable, make: makeCmapTable }; -export { parseCmapTableFormat0, parseCmapTableFormat14 }; +export { parseCmapTableFormat0, parseCmapTableFormat6, parseCmapTableFormat14 }; diff --git a/test/fonts/PDF-Embedded-Calibri-Subset.ttf b/test/fonts/PDF-Embedded-Calibri-Subset.ttf new file mode 100644 index 0000000000000000000000000000000000000000..18cae51438aafc2521d99a1e3946a2a0f3286e23 GIT binary patch literal 22448 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 parse(readFileSync(url), opt); @@ -82,4 +82,18 @@ describe('tables/cmap.mjs', function() { const expectedGlyphIds = [1,2,3,4]; assert.deepEqual(glyphIds, expectedGlyphIds); }); + + it('can parse CMAP table format 6', function() { + let font; + assert.doesNotThrow(function() { + font = loadSync('./test/fonts/PDF-Embedded-Calibri-Subset.ttf'); + }); + + // The embedded char IDs for the string "Living Room" in the PDF embedded font + const testString = '!"#"$%&\'(()'; + const glyphIds = font.stringToGlyphIndexes(testString); + + const expectedGlyphIds = [3, 13, 21, 13, 16, 11, 1, 5, 17, 17, 15]; + assert.deepEqual(glyphIds, expectedGlyphIds); + }); }); \ No newline at end of file