afdko

CID-keyed UFOs in afdko

Introduction

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

afdko tx -ufo -o cid-keyed.ufo cid-keyed.otf

Subset a CID-keyed UFO using CID ranges with the -g flag

afdko tx -g /0,/959-/978,/59120-/59130 -ufo -o cid-keyed-subset.ufo cid-keyed.ufo

Create a name-keyed source using -decid

afdko tx -t1 -o name-keyed.pfa -decid -fd 1 cid-keyed.ufo

Merge multiple CID-keyed UFOs into a single UFO

afdko mergefonts merged-cid-keyed.ufo part1.map part1.ufo part2.map part2.ufo part3.map part3.ufo

Requirements

The following keys are required in lib.plist to make a UFO CID-keyed

The postscriptFDArray key is only required if you define more than one hint dictionary

com.adobe.type.ROS

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 afdko tx alone you will see the order as saved in the UFO, but when converting with afdko tx -t1 or afdko tx -cff or building an OTF with afdko makeotf the glyphs will be rearranged into CID order.

com.adobe.type.postscriptCIDMap

The glyph name to CID mapping must be a dict with the UFO glyph names as keys and their corresponding CID numbers as integer values. When converting an existing CID-keyed source (OTF, CFF, Type1) to UFO with a command like afdko 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.

com.adobe.type.postscriptFDArray

The FDArray is a list of font dictionaries containing hinting data for groups of glyphs. 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]}}]

Note: If you only require one set of values for hinting data it should be provided in the fontinfo.plist as described in the UFO Specification

FDArraySelect groups in groups.plist

If com.adobe.type.postscriptFDArray is defined then 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

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.

Using Python with CID-keyed UFOs

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'])}

# ---------Optional Steps For Hint Data---------

# Set up a a single 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()

Document Version History

Version 1.0 — April 10 2023

Version 1.1 — April 10 2025