With the correct data included in a UFO you can create a hybrid
CID-keyed/name-keyed source file that can be used in most of the
afdko tools that understand CID-keyed fonts like makeotf
, tx
, and mergefonts
.
Some examples:
Convert an existing CID-keyed OTF to CID-keyed UFO
tx -ufo -o cid-keyed.ufo cid-keyed.otf
Subset a CID-keyed UFO using CID ranges with the -g
flag
tx -g /0,/959-/978,/59120-/59130 -ufo -o cid-keyed-subset.ufo cid-keyed.ufo
Create a name-keyed source using -decid
tx -t1 -o name-keyed.pfa -decid -fd 1 cid-keyed.ufo
Merge multiple CID-keyed UFOs into a single UFO
mergefonts merged-cid-keyed.ufo part1.map part1.ufo part2.map part2.ufo part3.map part3.ufo
The following keys are required in lib.plist
to make a UFO CID-keyed
com.adobe.type.ROS
com.adobe.type.postscriptCIDMap
com.adobe.type.postscriptFDArray
The value for this key must be written in the form {Registry}-{Ordering}-{Supplement}. Information about available ROS can be found at https://github.com/adobe-type-tools/cmap-resources
Some typical ROSes are
All except Adobe-Identity-0 have a fixed CID order that must be followed, but
the glyphs in the UFO can be named anything that is legal in the UFO format.
The UFO glyphOrder may also be any order you choose. If you run tx
alone you
will see the order as saved in the UFO, but when converting with tx -t1
or tx -cff
or building an OTF with makeotf
the glyphs will be rearranged into CID order.
The glyph name to CID mapping must be a dict with the UFO glyph names as keys and
their corresponding CID numbers as values. When converting an existing CID-keyed
source (OTF, CFF, Type1) to UFO with a command like tx -ufo -o source.ufo source.otf
the glyph names will default to cidXXXXX
because no names can be
stored in those source formats. If you change the names in the UFO be sure to update
the CID mapping and groups.plist to use the new names.
The FDArray is a list of font dictionaries containing hinting data. All keys are optional and will use default values if not specified, but there must be at least one dict in the array and a corresponding group in groups.plist.
<key>com.adobe.type.postscriptFDArray</key>
<array>
<dict>
</dict>
</array>
An example of one FontDict in Python dumped from Source Han Serif JP ExtraLight
{'FontMatrix': [0.001, 0, 0, 0.001, 0, 0],
'FontName': 'SourceHanSerifJP-ExtraLight-HWidth',
'PaintType': 0,
'PrivateDict': {'ExpansionFactor': 0.06,
'postscriptBlueFuzz': 1,
'postscriptBlueScale': 0.039625,
'postscriptBlueShift': 7,
'postscriptBlueValues': [-18, 0, 521, 538, 746, 764, 794, 794],
'postscriptOtherBlues': [-283, -283, -273, -273, -176, -176],
'postscriptStdHW': [34],
'postscriptStdVW': [50],
'postscriptStemSnapH': [34, 45, 59],
'postscriptStemSnapV': [28, 50, 60]}}]
In addition to the lib.plist keys there must be a groups.plist file
containing one group for each FontDict in com.adobe.type.postscriptFDArray
.
Each group must be named in the following format
FDArraySelect.{required-fdarray-index}.{optional-descriptive-name}
The following keys are equivalent to the parser
FDArraySelect.0.SourceHanSerif-ExtraLight-Alphabetic
FDArraySelect.0
The optional descriptive name is only for user convenience such as when viewing and
creating groups in a font editor. When dumping with tx
or building an OTF
with makeotf
the names for each font dict will come from the FontName
key
in each dict in com.adobe.type.postscriptFDArray
.
Any Python library that supports UFO can handle CID-keyed UFOs since the
CID-specific data is added to the existing lib.plist and groups.plist files.
For example, using fontParts
to make an existing UFO CID-keyed:
from fontParts.world import OpenFont
font = OpenFont('cid-keyed-source.ufo')
# Set the ROS
font.lib['com.adobe.type.ROS'] = 'Adobe-Japan1-7'
# Set up a preliminary CID mapping based on the current glyph order
font.lib['com.adobe.type.postscriptCIDMap'] = {name: i for i, name in enumerate(font.lib['public.glyphOrder'])}
# Set up a basic FDArray until you are ready to add hinting data
fontname = font.info.familyName.replace(" ", "")
font.lib['com.adobe.type.postscriptFDArray'] = [{'FontName': f'{fontname}-FD0'}]
# Create a single FontDict that corresponds to the one in the FDArray above
font.groups[f'FDArraySelect.0.{fontname}-FD0'] = font.glyphOrder
font.save()
Version 1.0 — April 10 2023