Edit Raw OpenType Table Hex Data in FontForge

Editing raw OpenType table hexadecimal data in FontForge allows font developers and typographers to manipulate low-level binary structures, repair broken metadata, or inject custom OpenType tables directly into a font. This guide covers how to access and modify raw OpenType table bytes using both FontForge’s graphical user interface for arbitrary tables and its built-in Python scripting console for direct binary manipulation.

Method 1: Using the FontForge GUI for Custom/Arbitrary Tables

FontForge provides a graphical interface to view and edit binary data for unparsed or custom OpenType tables.

  1. Open the Font File: Launch FontForge and open your font (.otf or .ttf) via File > Open.
  2. Access Font Info: Navigate to Element > Font Info (or press Ctrl+Shift+F on Linux/Windows, Cmd+Shift+F on macOS).
  3. Locate the OpenType Tables Section: In the left sidebar of the Font Info dialog, expand or select the OpenType or Tables category.
  4. Select or Add a Table:
    • If modifying an existing uninterpreted table, select it from the list.
    • If adding a new raw table, click Add, then enter the four-character OpenType table tag (e.g., cust, feat).
  5. Edit the Hex Data: In the raw data field, FontForge displays the byte stream formatted as hexadecimal strings or allows you to view raw ASCII/hex representations. Modify the hex pairs directly within the field.
  6. Apply and Save: Click OK to commit the changes to the database. Generate the updated font by selecting File > Generate Fonts.

Method 2: Using the Built-In Python Console (All OpenType Tables)

Because FontForge automatically parses standard tables (such as name, OS/2, cmap, and head) into specific GUI fields, the most reliable and direct way to read and write arbitrary raw hex data for any table is via FontForge’s integrated Python engine.

Step 1: Open the Python Scripting Window

In FontForge, navigate to File > Execute Script or open the interactive console via Window > Open Python Window.

Step 2: Read Existing Table Data as Hexadecimal

To view the raw hex dump of any table (for example, the OS/2 table), execute:

import fontforge

# Reference the active font
font = fontforge.activeFont()

# Specify the 4-byte table tag
tag = "OS/2"

# Read the raw binary data
raw_bytes = font.getTableData(tag)

# Convert to a readable hexadecimal string
hex_data = raw_bytes.hex()
print(f"Current {tag} Hex Data:\n{hex_data}")

Step 3: Modify and Inject the Raw Hex Data

After altering your hexadecimal string in an external text editor or directly in the script, write the bytes back to the table using setTableData:

import fontforge

font = fontforge.activeFont()
tag = "OS/2"

# Define your modified hex string (ensure length is even)
modified_hex = "000401f4000500000000..."  # Replace with complete, edited hex string

# Convert the hex string back to binary data
new_bytes = bytes.fromhex(modified_hex)

# Overwrite the table with the new byte sequence
font.setTableData(tag, new_bytes)
print(f"Table '{tag}' updated successfully.")

Step 4: Export the Font

Once the table is set, export the font from the GUI via File > Generate Fonts or by running:

font.generate("output_font.otf")

Important Considerations When Editing Hex Data

  • Endianness: OpenType specifications enforce big-endian (network byte order) format for multi-byte values. Ensure any manual integer or offset edits adhere to this order.
  • Table Length and Padding: All OpenType tables must begin on a 4-byte boundary. While FontForge automatically handles table padding during font generation, the internal internal offsets within your modified hex data must remain accurate to prevent corruption.
  • Checksum Recalculation: When saving or generating fonts, FontForge recalculates table-level and global checksums (such as checkSumAdjustment in the head table), ensuring the generated binary file remains compliant with standard OpenType rasterizers.