Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What are the windows requirements for an OpenType font to be installable?

Niche programming question: I'm developing an OpenType font by byte-crafting it (rather than using design tools like Fontlab or FontForge), and now have a custom OpenType-CFF font that implements a subset of the Basic Latin unicode block (specifically it implements .notdef and the tilde).

The CFF block passes tx -3 validation (http://www.adobe.com/devnet/opentype/afdko.html), the font as a whole passes a round-trip de/recompile through TTX (https://github.com/behdad/fonttools), and Microsoft's "Font Validator" (http://www.microsoft.com/typography/FontValidator.mspx) does not report any errors in the font. Loading it as a custom webfont (both as plain otf in browsers that support otf, and wrapped as WOFF in browsers that don't) styles the implemented glyphs correctly.

However, even with all that apparent correctness, the windows font previewer reports that it is not a valid font file, and window will not let me install it. I've looked high and low for information on what windows requires for a font to be installable, but the internet seems to be filled with how to use fonts as a user, rather than what requirements need to be met as developer.

I'm not quite sure what the best way is to include the code for this question, since it's not quite conventional programming; the generator code is in JavaScript, but that code works perfectly fine and generates a for all intents and purposes (save one) proper font.

If you know how to work with hex editors, then the following is the hex string for the font:

4F 54 54 4F 00 09 00 80 00 03 00 10 43 46 46 20 03 00 B4 92 00 00 02 A4 00 00 00 B3 4F 53 2F 32
30 F6 24 D4 00 00 01 00 00 00 00 60 63 6D 61 70 00 0D 00 B7 00 00 02 50 00 00 00 32 68 65 61 64
61 E4 43 91 00 00 00 9C 00 00 00 36 68 68 65 61 06 96 01 52 00 00 00 D4 00 00 00 24 68 6D 74 78
02 A8 00 00 00 00 03 58 00 00 00 08 6D 61 78 70 00 02 50 00 00 00 00 F8 00 00 00 06 6E 61 6D 65
C6 CC FF EC 00 00 01 60 00 00 00 F0 70 6F 73 74 00 03 00 01 00 00 02 84 00 00 00 20 00 01 00 00
00 01 00 00 1A EA FF 64 5F 0F 3C F5 00 00 04 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 14 FF EC 02 BC 02 A8 00 00 00 08 00 02 00 00 00 00 00 00 00 01 00 00 03 EC FE A8 00 00 02 A8
00 00 00 00 02 A8 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 50 00 00 02 00 00
00 03 00 00 01 90 00 01 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00 20 3D 29 20 00 40
00 7E 00 7E 02 A8 FF EC 01 44 03 EC 01 58 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 7E 00 00
00 00 00 08 00 66 00 01 00 20 00 00 00 01 00 0B 00 00 00 01 00 20 00 00 00 02 00 07 00 21 00 01
00 20 00 00 00 04 00 11 00 36 00 01 00 20 00 00 00 05 00 0B 00 69 00 03 00 01 04 09 00 01 00 16
00 0B 00 03 00 01 04 09 00 02 00 0E 00 28 00 03 00 01 04 09 00 04 00 22 00 47 00 03 00 01 04 09
00 05 00 16 00 74 43 75 73 74 6F 6D 20 46 6F 6E 74 00 43 00 75 00 73 00 74 00 6F 00 6D 00 20 00
46 00 6F 00 6E 00 74 52 65 67 75 6C 61 72 00 52 00 65 00 67 00 75 00 6C 00 61 00 72 43 75 73 74
6F 6D 20 47 6C 79 70 68 20 46 6F 6E 74 00 43 00 75 00 73 00 74 00 6F 00 6D 00 20 00 47 00 6C 00
79 00 70 00 68 00 20 00 46 00 6F 00 6E 00 74 56 65 72 73 69 6F 6E 20 31 2E 30 00 56 00 65 00 72
00 73 00 69 00 6F 00 6E 00 20 00 31 00 2E 00 30 00 00 00 01 00 03 00 01 00 00 00 0C 00 04 00 26
00 00 00 04 00 04 00 01 00 00 00 7E FF FF 00 00 00 7E FF FF FF 83 00 01 00 00 00 00 00 00 00 00
00 01 00 00 00 03 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 00 00 00 00 00 00 00 00 00
00 00 00 00 01 00 04 01 00 01 01 01 0B 63 75 73 74 6F 6D 66 6F 6E 74 00 01 01 01 23 F8 1B 00 F8
1C 02 F8 1D 03 F8 19 04 8C 0D 9F 77 F9 50 F9 3C 05 F7 05 0F F7 08 10 F7 0B 11 9B F7 37 12 00 04
01 01 0C 1D 28 2E 56 65 72 73 69 6F 6E 20 31 2E 30 43 75 73 74 6F 6D 20 47 6C 79 70 68 20 46 6F
6E 74 43 75 73 74 6F 6D 20 46 6F 6E 74 63 75 73 74 6F 6D 00 00 00 01 8A 00 01 01 00 02 01 01 02
27 0E 9F 77 15 8B F9 50 05 F9 3C 8B 05 8B FD 50 05 FD 3C 8B 05 F7 2A F7 2A 15 8B F8 24 05 F8 10
8B 05 8B FC 24 05 0E 8B 8B 06 8B 8B 08 95 0A 95 0B F9 50 14 F9 50 14 00 00 00 00 00 02 A8 00 00

(custom fonts can be made very small =)

But, if actual files and/or TTX output are desirable, they can be found over at https://github.com/Pomax/CFF-glyphlet-fonts/tree/gh-pages/binaries/test, including the TTX xml (direct link for that: https://github.com/Pomax/CFF-glyphlet-fonts/blob/gh-pages/binaries/with%20GSUB/customfont.ttx), which in the interest of a self-contained question is:

<?xml version="1.0" encoding="utf-8"?>
<ttFont sfntVersion="OTTO" ttLibVersion="2.4">

  <GlyphOrder>
    <!-- The 'id' attribute is only for humans; it is ignored when parsed. -->
    <GlyphID id="0" name=".notdef"/>
    <GlyphID id="1" name="custom"/>
  </GlyphOrder>

  <head>
    <!-- Most of this table will be recalculated by the compiler -->
    <tableVersion value="1.0"/>
    <fontRevision value="1.0"/>
    <checkSumAdjustment value="0x1aeaff64"/>
    <magicNumber value="0x5f0f3cf5"/>
    <flags value="00000000 00000000"/>
    <unitsPerEm value="1024"/>
    <created value="Thu Jan 01 00:00:00 1970"/>
    <modified value="Thu Jan 01 00:00:00 1970"/>
    <xMin value="20"/>
    <yMin value="-20"/>
    <xMax value="700"/>
    <yMax value="680"/>
    <macStyle value="00000000 00000000"/>
    <lowestRecPPEM value="8"/>
    <fontDirectionHint value="2"/>
    <indexToLocFormat value="0"/>
    <glyphDataFormat value="0"/>
  </head>

  <hhea>
    <tableVersion value="1.0"/>
    <ascent value="1004"/>
    <descent value="-344"/>
    <lineGap value="0"/>
    <advanceWidthMax value="680"/>
    <minLeftSideBearing value="0"/>
    <minRightSideBearing value="0"/>
    <xMaxExtent value="680"/>
    <caretSlopeRise value="0"/>
    <caretSlopeRun value="0"/>
    <caretOffset value="0"/>
    <reserved0 value="0"/>
    <reserved1 value="0"/>
    <reserved2 value="0"/>
    <reserved3 value="0"/>
    <metricDataFormat value="0"/>
    <numberOfHMetrics value="2"/>
  </hhea>

  <maxp>
    <tableVersion value="0x5000"/>
    <numGlyphs value="2"/>
  </maxp>

  <OS_2>
    <version value="3"/>
    <xAvgCharWidth value="0"/>
    <usWeightClass value="400"/>
    <usWidthClass value="1"/>
    <fsType value="00000000 00000000"/>
    <ySubscriptXSize value="0"/>
    <ySubscriptYSize value="0"/>
    <ySubscriptXOffset value="0"/>
    <ySubscriptYOffset value="0"/>
    <ySuperscriptXSize value="0"/>
    <ySuperscriptYSize value="0"/>
    <ySuperscriptXOffset value="0"/>
    <ySuperscriptYOffset value="0"/>
    <yStrikeoutSize value="0"/>
    <yStrikeoutPosition value="0"/>
    <sFamilyClass value="0"/>
    <panose>
      <bFamilyType value="0"/>
      <bSerifStyle value="0"/>
      <bWeight value="0"/>
      <bProportion value="0"/>
      <bContrast value="0"/>
      <bStrokeVariation value="0"/>
      <bArmStyle value="0"/>
      <bLetterForm value="0"/>
      <bMidline value="0"/>
      <bXHeight value="0"/>
    </panose>
    <ulUnicodeRange1 value="00000000 00000000 00000000 00000001"/>
    <ulUnicodeRange2 value="00000000 00000000 00000000 00000000"/>
    <ulUnicodeRange3 value="00000000 00000000 00000000 00000000"/>
    <ulUnicodeRange4 value="00000000 00000000 00000000 00000000"/>
    <achVendID value=" =) "/>
    <fsSelection value="00000000 01000000"/>
    <fsFirstCharIndex value="126"/>
    <fsLastCharIndex value="126"/>
    <sTypoAscender value="680"/>
    <sTypoDescender value="-20"/>
    <sTypoLineGap value="324"/>
    <usWinAscent value="1004"/>
    <usWinDescent value="344"/>
    <ulCodePageRange1 value="00000000 00000000 00000000 00000001"/>
    <ulCodePageRange2 value="00000000 00000000 00000000 00000000"/>
    <sxHeight value="0"/>
    <sCapHeight value="0"/>
    <usDefaultChar value="0"/>
    <usBreakChar value="126"/>
    <usMaxContex value="0"/>
  </OS_2>

  <name>
    <namerecord nameID="1" platformID="1" platEncID="32" langID="0x0">
      Custom Font
    </namerecord>
    <namerecord nameID="2" platformID="1" platEncID="32" langID="0x0">
      Regular
    </namerecord>
    <namerecord nameID="4" platformID="1" platEncID="32" langID="0x0">
      Custom Glyph Font
    </namerecord>
    <namerecord nameID="5" platformID="1" platEncID="32" langID="0x0">
      Version 1.0
    </namerecord>
    <namerecord nameID="1" platformID="3" platEncID="1" langID="0x409">
      Custom Font
    </namerecord>
    <namerecord nameID="2" platformID="3" platEncID="1" langID="0x409">
      Regular
    </namerecord>
    <namerecord nameID="4" platformID="3" platEncID="1" langID="0x409">
      Custom Glyph Font
    </namerecord>
    <namerecord nameID="5" platformID="3" platEncID="1" langID="0x409">
      Version 1.0
    </namerecord>
  </name>

  <cmap>
    <tableVersion version="0"/>
    <cmap_format_4 platformID="3" platEncID="1" language="0">
      <map code="0x7e" name="custom"/><!-- TILDE -->
    </cmap_format_4>
  </cmap>

  <post>
    <formatType value="3.0"/>
    <italicAngle value="0.0"/>
    <underlinePosition value="0"/>
    <underlineThickness value="0"/>
    <isFixedPitch value="1"/>
    <minMemType42 value="0"/>
    <maxMemType42 value="0"/>
    <minMemType1 value="0"/>
    <maxMemType1 value="0"/>
  </post>

  <CFF>
    <CFFFont name="customfont">
      <version value="Version 1.0"/>
      <FullName value="Custom Glyph Font"/>
      <FamilyName value="Custom Font"/>
      <Weight value="Roman"/>
      <isFixedPitch value="0"/>
      <ItalicAngle value="0"/>
      <UnderlineThickness value="50"/>
      <PaintType value="0"/>
      <CharstringType value="2"/>
      <FontMatrix value="0.001 0 0 0.001 0 0"/>
      <UniqueID value="1"/>
      <FontBBox value="20 -20 700 680"/>
      <StrokeWidth value="0"/>
      <!-- charset is dumped separately as the 'GlyphOrder' element -->
      <Encoding>
        <map code="0x1" name="custom"/>
      </Encoding>
      <Private>
        <BlueValues value="0 0"/>
        <FamilyBlues value="0 0"/>
        <BlueScale value="0.039625"/>
        <BlueShift value="7"/>
        <BlueFuzz value="1"/>
        <StdHW value="10"/>
        <StdVW value="10"/>
        <ForceBold value="0"/>
        <LanguageGroup value="0"/>
        <ExpansionFactor value="0.06"/>
        <initialRandomSeed value="0"/>
        <defaultWidthX value="700"/>
        <nominalWidthX value="0"/>
      </Private>
      <CharStrings>
        <CharString name=".notdef">
          endchar
        </CharString>
        <CharString name="custom">
          20 -20 rmoveto
          0 700 rlineto
          680 0 rlineto
          0 -700 rlineto
          -680 0 rlineto
          150 150 rmoveto
          0 400 rlineto
          380 0 rlineto
          0 -400 rlineto
          endchar
        </CharString>
      </CharStrings>
    </CFFFont>

    <GlobalSubrs>
      <!-- The 'index' attribute is only for humans; it is ignored when parsed. -->
    </GlobalSubrs>
  </CFF>

  <hmtx>
    <mtx name=".notdef" width="0" lsb="0"/>
    <mtx name="custom" width="680" lsb="0"/>
  </hmtx>

</ttFont>

If there are any additional tools that can be used to determine whether or not a font is "done" enough to be installable, or if anyone knows of documentation that explains which criteria a font needs to meet before it can be installed, that information is extremely welcome. And of course, if someone happens to know what my font code is still missing (either as bytecode or as TTX XML), or they see odd/buggy bits, I am also keenly interested in your comments/answers.

like image 771
Mike 'Pomax' Kamermans Avatar asked Feb 15 '14 18:02

Mike 'Pomax' Kamermans


People also ask

Can Windows use OpenType fonts?

OpenType fonts are cross-platform compatible and the same font file can be installed and work on both Macintosh and Windows computers.

Does Windows 10 support OTF fonts?

otf files. You can simply right-click on each of those files and click Install. This will install the font in your Windows 10 repository and be immediately available in all your programs.

Is OTF or TTF better for Windows?

In simpler terms, OTF is the better of the two where designers are concerned due to the additional features. However, for regular daily computer use, the difference between OTF and TTF is not consequential.


1 Answers

As someone on the Typophile forum pointed out, it turns out the "name" table is incomplete as far as Windows is concerned. While the Microsoft Font Validator does not flag any issues with it, the font must list the following name table entries for it to be installable:

1: the regular font name
2: the font subfamily ("Regular", etc)
3: any (seriously, ANY) string to act as a unique font identifier
6: the postscript font name (a subset of true ASCII. Not ANSI)

The font as I had defined it was using NameIDs 1, 2, 4 and 5; while 4 and 5 are in fact required for "validation", they turn out to be utterly irrelevant for preview/installation, whereas 3 and 6 are critical. Who knew (seriously, who knew... if you did, I want to talk to you in chat or on twitter or something to pick your brain =)

(note that 4 and 5 are still required to make the font installable on OSX)

2017 edit: Microsoft's Font Validator was open sourced in 2015, and as MS was (for legal reasons) unable to merge in significant community contributions, a community-maintained fork was set up instead, and is being kept in sync with the changes in the OpenType spec over on https://github.com/HinTak/Font-Validator -- If Font Validator is part of your toolset, you absolutely want to start using this fork instead.

like image 123
Mike 'Pomax' Kamermans Avatar answered Oct 02 '22 17:10

Mike 'Pomax' Kamermans