From cac74d7cb3d1c04bd43bd4e60a24e85e46357db9 Mon Sep 17 00:00:00 2001 From: Adil Allawi Date: Thu, 15 Sep 2011 23:23:22 +0100 Subject: [PATCH 1/3] Fix OS/2 table to match font yMax and yMin from head table --- fonts.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/fonts.js b/fonts.js index 7d51e2c4b..064702de2 100644 --- a/fonts.js +++ b/fonts.js @@ -833,9 +833,11 @@ var Font = (function Font() { var data = file.getBytes(length); file.pos = previousPosition; - if (tag == 'head') + if (tag == 'head') { // clearing checksum adjustment data[8] = data[9] = data[10] = data[11] = 0; + data[17] |= 0x20; //Set font optimized for cleartype flag + } return { tag: tag, @@ -1008,7 +1010,7 @@ var Font = (function Font() { var header = readOpenTypeHeader(font); var numTables = header.numTables; - var cmap, maxp, hhea, hmtx, vhea, vmtx; + var cmap, maxp, hhea, hmtx, vhea, vmtx, head; var tables = []; for (var i = 0; i < numTables; i++) { var table = readTableEntry(font); @@ -1022,6 +1024,8 @@ var Font = (function Font() { hhea = table; else if (table.tag == 'hmtx') hmtx = table; + else if (table.tag == 'head') + head = table; requiredTables.splice(index, 1); } else { @@ -1048,6 +1052,13 @@ var Font = (function Font() { createOpenTypeHeader(header.version, ttf, numTables); if (requiredTables.indexOf('OS/2') != -1) { + if (typeof(head) != 'undefined') { + var ymax = int16([head.data[42],head.data[43]]); + var ymin = int16([head.data[38],head.data[39]]) - 0x10000; //always negative + properties.ascent = ymax; + properties.descent = ymin; + } + tables.push({ tag: 'OS/2', data: stringToArray(createOS2Table(properties)) From 870de2f7f3ed286603bbf1f19213d996839d2280 Mon Sep 17 00:00:00 2001 From: Adil Allawi Date: Fri, 16 Sep 2011 13:50:11 +0100 Subject: [PATCH 2/3] Add opentype ascender, descender and units-per-em to font properties Prefer font ascender, descender when creating OS/2 table scale PDF ascender and descender in OS/2 table by font units per em if it exists Fix the truetype font header to prevent Windows rejecting a Mac truetype font --- fonts.js | 48 +++++++++++++++++++++++++++++++++++++----------- 1 file changed, 37 insertions(+), 11 deletions(-) diff --git a/fonts.js b/fonts.js index 064702de2..fd7a23bd3 100644 --- a/fonts.js +++ b/fonts.js @@ -12,6 +12,9 @@ var kMaxWaitForFontFace = 1000; // Unicode Private Use Area var kCmapGlyphOffset = 0xE000; +// PDF Glyph Space Units are one Thousandth of a TextSpace Unit except for Type 3 fonts +var kPDFGlyphSpaceUnits = 1000; + // Until hinting is fully supported this constant can be used var kHintingEnabled = false; @@ -534,6 +537,10 @@ var Font = (function Font() { }; function createOpenTypeHeader(sfnt, file, numTables) { + // Windows hates the Mac TrueType sfnt version number + if (sfnt == 'true') + sfnt = string32(0x00010000); + // sfnt version (4 bytes) var header = sfnt; @@ -694,6 +701,24 @@ var Font = (function Font() { } } + var openTypeUnitsPerEm = (typeof (properties.openTypeUnitsPerEm) == 'undefined') ? kPDFGlyphSpaceUnits : properties.openTypeUnitsPerEm; + var typoAscent = properties.ascent; + var typoDescent = properties.descent; + var winAscent = typoAscent; + var winDescent = -typoDescent; + + // if the font already has ascent and descent information then use these values + if (typeof (properties.openTypeAscent) != 'undefined') { + typoAscent = properties.openTypeAscent; + typoDescent = properties.openTypeDescent; + winAscent = properties.openTypeYMax; + winDescent = -properties.openTypeYMin; + } else if (openTypeUnitsPerEm != kPDFGlyphSpaceUnits) { + // if the font units differ to the PDF glyph space units then scale up the values + typoAscent = Math.round(typoAscent * openTypeUnitsPerEm / kPDFGlyphSpaceUnits); + typoDescent = Math.round(typoDescent * openTypeUnitsPerEm / kPDFGlyphSpaceUnits); + } + return '\x00\x03' + // version '\x02\x24' + // xAvgCharWidth '\x01\xF4' + // usWeightClass @@ -722,11 +747,11 @@ var Font = (function Font() { string16(firstCharIndex || properties.firstChar) + // usFirstCharIndex string16(lastCharIndex || properties.lastChar) + // usLastCharIndex - string16(properties.ascent) + // sTypoAscender - string16(properties.descent) + // sTypoDescender + string16(typoAscent) + // sTypoAscender + string16(typoDescent) + // sTypoDescender '\x00\x64' + // sTypoLineGap (7%-10% of the unitsPerEM value) - string16(properties.ascent) + // usWinAscent - string16(-properties.descent) + // usWinDescent + string16(winAscent) + // usWinAscent + string16(winDescent) + // usWinDescent '\x00\x00\x00\x00' + // ulCodePageRange1 (Bits 0-31) '\x00\x00\x00\x00' + // ulCodePageRange2 (Bits 32-63) string16(properties.xHeight) + // sxHeight @@ -1047,18 +1072,19 @@ var Font = (function Font() { virtualOffset: numTables * (4 * 4) }; + //extract some more font properties from the OpenType head and hhea tables + properties.openTypeUnitsPerEm = int16([head.data[18], head.data[19]]); + properties.openTypeYMax = int16([head.data[42], head.data[43]]); + properties.openTypeYMin = int16([head.data[38], head.data[39]]) - 0x10000; //always negative + properties.openTypeAscent = int16([hhea.data[4], hhea.data[5]]); + properties.openTypeDescent = int16([hhea.data[6], hhea.data[7]]) - 0x10000; //always negative + + // The new numbers of tables will be the last one plus the num // of missing tables createOpenTypeHeader(header.version, ttf, numTables); if (requiredTables.indexOf('OS/2') != -1) { - if (typeof(head) != 'undefined') { - var ymax = int16([head.data[42],head.data[43]]); - var ymin = int16([head.data[38],head.data[39]]) - 0x10000; //always negative - properties.ascent = ymax; - properties.descent = ymin; - } - tables.push({ tag: 'OS/2', data: stringToArray(createOS2Table(properties)) From 530d78e0f854505b814d3dcfe10fca82c3ba659b Mon Sep 17 00:00:00 2001 From: Adil Allawi Date: Fri, 16 Sep 2011 23:55:06 +0100 Subject: [PATCH 3/3] Added myself to the license (yay!) Tweaked according to comments in pull request #482 --- LICENSE | 1 + fonts.js | 48 ++++++++++++++++++++++++------------------------ 2 files changed, 25 insertions(+), 24 deletions(-) diff --git a/LICENSE b/LICENSE index d96b927a3..f8a848205 100644 --- a/LICENSE +++ b/LICENSE @@ -8,6 +8,7 @@ Justin D'Arcangelo Yury Delendik Kalervo Kujala + Adil Allawi <@ironymark> Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), diff --git a/fonts.js b/fonts.js index fd7a23bd3..4f95d16f0 100644 --- a/fonts.js +++ b/fonts.js @@ -670,7 +670,9 @@ var Font = (function Font() { format314); }; - function createOS2Table(properties) { + function createOS2Table(properties, override) { + var override = override || {}; + var ulUnicodeRange1 = 0; var ulUnicodeRange2 = 0; var ulUnicodeRange3 = 0; @@ -701,22 +703,19 @@ var Font = (function Font() { } } - var openTypeUnitsPerEm = (typeof (properties.openTypeUnitsPerEm) == 'undefined') ? kPDFGlyphSpaceUnits : properties.openTypeUnitsPerEm; - var typoAscent = properties.ascent; - var typoDescent = properties.descent; - var winAscent = typoAscent; - var winDescent = -typoDescent; + var unitsPerEm = override.unitsPerEm || kPDFGlyphSpaceUnits; + var typoAscent = override.ascent || properties.ascent; + var typoDescent = override.descent || properties.descent; + var winAscent = override.yMax || typoAscent; + var winDescent = -override.yMin || -typoDescent; - // if the font already has ascent and descent information then use these values - if (typeof (properties.openTypeAscent) != 'undefined') { - typoAscent = properties.openTypeAscent; - typoDescent = properties.openTypeDescent; - winAscent = properties.openTypeYMax; - winDescent = -properties.openTypeYMin; - } else if (openTypeUnitsPerEm != kPDFGlyphSpaceUnits) { + // if there is a units per em value but no other override then scale the calculated ascent + if (unitsPerEm != kPDFGlyphSpaceUnits && 'undefined' == typeof(override.ascent)) { // if the font units differ to the PDF glyph space units then scale up the values - typoAscent = Math.round(typoAscent * openTypeUnitsPerEm / kPDFGlyphSpaceUnits); - typoDescent = Math.round(typoDescent * openTypeUnitsPerEm / kPDFGlyphSpaceUnits); + typoAscent = Math.round(typoAscent * unitsPerEm / kPDFGlyphSpaceUnits); + typoDescent = Math.round(typoDescent * unitsPerEm / kPDFGlyphSpaceUnits); + winAscent = typoAscent; + winDescent = -typoDescent; } return '\x00\x03' + // version @@ -1072,22 +1071,23 @@ var Font = (function Font() { virtualOffset: numTables * (4 * 4) }; - //extract some more font properties from the OpenType head and hhea tables - properties.openTypeUnitsPerEm = int16([head.data[18], head.data[19]]); - properties.openTypeYMax = int16([head.data[42], head.data[43]]); - properties.openTypeYMin = int16([head.data[38], head.data[39]]) - 0x10000; //always negative - properties.openTypeAscent = int16([hhea.data[4], hhea.data[5]]); - properties.openTypeDescent = int16([hhea.data[6], hhea.data[7]]) - 0x10000; //always negative - - // The new numbers of tables will be the last one plus the num // of missing tables createOpenTypeHeader(header.version, ttf, numTables); if (requiredTables.indexOf('OS/2') != -1) { + //extract some more font properties from the OpenType head and hhea tables + var override = { + unitsPerEm: int16([head.data[18], head.data[19]]), + yMax: int16([head.data[42], head.data[43]]), + yMin: int16([head.data[38], head.data[39]]) - 0x10000, //always negative + ascent: int16([hhea.data[4], hhea.data[5]]), + descent: int16([hhea.data[6], hhea.data[7]]) - 0x10000 //always negative + } + tables.push({ tag: 'OS/2', - data: stringToArray(createOS2Table(properties)) + data: stringToArray(createOS2Table(properties, override)) }); }