Introduction

Type 1 is Adobe’s original scalable font format, predating TrueType and OpenType. Type 1 fonts consist of two files: a .pfb (Printer Font Binary) file containing the encrypted font program, and an .afm (Adobe Font Metrics) file with kerning and metrics data. Despite being superseded by OpenType, Type 1 fonts remain prevalent in publishing workflows, PostScript pipelines, and archival documents.

Aspose.Font FOSS for Python provides direct access to Type 1 internals through Type1Font, Type1FontData, Type1Serializer, and Type1Interpreter. You can load PFB or PFA files via FontLoader.open, inspect the embedded font program metadata, interpret charstrings to glyph paths, and serialize fonts back to PFB or PFA format.

The library is published on PyPI as aspose-font and licensed under the MIT License. It has no mandatory commercial dependencies and runs on standard Python 3.


Key Features

Loading Type 1 Fonts

Use FontLoader.open to load a PFB or PFA file. The returned object exposes both the standard Font interface and Type 1-specific functionality through the Type1Font class:

from aspose_font import FontLoader

loaded = FontLoader.open("fonts/Courier.pfb")

print(loaded.font_name)    # e.g. "Courier"
print(loaded.font_family)  # e.g. "Courier"
print(loaded.num_glyphs)   # number of defined glyphs
print(loaded.font_style)   # style string, e.g. "Regular"

FontLoader.open detects the Type 1 format automatically from the file header. PFB and PFA files are both supported.


Loading AFM Metrics

Type 1 fonts ship their metrics in a separate .afm file. The Type1Font class exposes a load_afm(path) method that attaches the AFM data to the loaded font object, enabling kern pair lookups via get_kern_pairs().

Without the AFM file, get_kern_pairs() returns an empty list because kern data lives in the AFM file, not in the PFB program itself. The load_afm method accepts a file path string pointing to the companion .afm file.


Accessing Type1FontData Metadata

The Type1FontData class exposes the font program dictionary embedded in the Type 1 file. It includes metrics, bounding box, encoding vector, charstrings, and subroutines:

from aspose_font.type1.data import Type1FontData

# Type1FontData is the font program dictionary parsed from the PFB
# Access its properties to inspect the raw PostScript font data

Type1FontData properties:

  • font_name (str) — PostScript name of the font
  • full_name (str) — full human-readable name
  • family_name (str) — font family
  • weight (str) — weight string (e.g. "Medium")
  • italic_angle (float) — italic angle in degrees
  • is_fixed_pitch (bool) — true for monospace fonts
  • font_bbox (tuple[int, int, int, int]) — bounding box (llx, lly, urx, ury)
  • underline_position (int) — underline position in font units
  • underline_thickness (int) — underline stroke thickness
  • encoding (list[str]) — 256-slot encoding vector (PostScript glyph names)
  • charstrings (dict[str, bytes]) — glyph name → charstring bytes mapping
  • subrs (list[bytes]) — subroutine byte strings used by the charstring engine
  • len_iv (int) — lenIV encryption parameter

Interpreting Charstrings

Type1Interpreter decodes Type 1 charstring programs into GlyphPath outlines. Pass the raw charstring bytes from Type1FontData.charstrings to interpret:

from aspose_font.type1.interpreter import Type1Interpreter

interpreter = Type1Interpreter()
charstring = b"\x0e"  # seac or other charstring bytes

glyph_path, stack_depth = interpreter.interpret(charstring)
for cmd in glyph_path.commands:
    print(cmd)

interpret returns a (GlyphPath, int) tuple. The GlyphPath contains the drawing commands for the glyph outline. The integer is the final stack depth after execution, which is useful for debugging malformed charstrings.


Serializing to PFB and PFA

Type1Serializer converts a loaded Type 1 font back to binary PFB or text PFA format. Both methods accept any Font instance and return raw bytes:

from aspose_font import FontLoader
from aspose_font.type1.serializer import Type1Serializer

loaded = FontLoader.open("fonts/Courier.pfb")

# Serialize to PFB (binary) format
pfb_bytes = Type1Serializer.serialize_pfb(loaded)
with open("output/Courier_copy.pfb", "wb") as fh:
    fh.write(pfb_bytes)

# Serialize to PFA (text) format
pfa_bytes = Type1Serializer.serialize_pfa(loaded)
with open("output/Courier_copy.pfa", "wb") as fh:
    fh.write(pfa_bytes)

print(f"PFB: {len(pfb_bytes)} bytes")
print(f"PFA: {len(pfa_bytes)} bytes")

Font Metrics

Metrics and encoding are accessible through the standard Font interface:

from aspose_font import FontLoader

loaded = FontLoader.open("fonts/Courier.pfb")

metrics = loaded.metrics
print(f"Units per em  : {metrics.units_per_em}")
print(f"Ascender      : {metrics.ascender}")
print(f"Descender     : {metrics.descender}")
print(f"Underline pos : {metrics.underline_position}")
print(f"Underline tck : {metrics.underline_thickness}")

Quick Start

Install the library:

.venv/bin/pip install aspose-font

Load a PFB font and inspect it:

from aspose_font import FontLoader
from aspose_font.type1.serializer import Type1Serializer

loaded = FontLoader.open("Courier.pfb")

print(f"Font name : {loaded.font_name}")
print(f"Family    : {loaded.font_family}")
print(f"Style     : {loaded.font_style}")
print(f"Glyphs    : {loaded.num_glyphs}")

metrics = loaded.metrics
print(f"UPM       : {metrics.units_per_em}")

# Round-trip: serialize back to PFB
pfb_bytes = Type1Serializer.serialize_pfb(loaded)
print(f"Serialized: {len(pfb_bytes)} bytes")

Supported Formats

FormatExtensionReadWrite
TTF.ttf
OTF.otf
EOT.eot
CFF.cff
TYPE1.pfb/.pfa
WOFF.woff
WOFF2.woff2

Type 1 fonts are loaded via FontLoader.open and serialized via Type1Serializer.


Open Source & Licensing

Aspose.Font FOSS for Python is released under the MIT License. You can use it in personal, commercial, and open-source projects at no cost. The source code is available on GitHub and the package is distributed via PyPI as aspose-font.


Getting Started