Xerox’s Proprietary Font Format

A dive into Xerox’s 9700 and 5Word FNT font formats.

Some background

Xerox has been in the printer business for quite a while. Longer than some printer related technologies we take for granted, like PostScript and vector fonts.

Back in the 70’s when Xerox was figuring out laser printing, they needed a way to get text onto a page. And in order to do that, they needed a way to represent letters. Xerox’s first laser printer, the Xerox 9700, first appeared in 1977, a whole five years before PostScript and its Type 1 vector fonts. They had to figure something out all on their own. Enter Xerox’s proprietary 9700 bitmap font.

This font format is rarely used today, but to my misfortune I work with this font at my day job where we still have binders of font samples printed and collecting dust on a shelf. Each page of these binders contains the complete character set of a single font, something that can actually be done with fonts this old due to some technical limitations we’ll get into.

One day, while feeding my curiosity by paging through one of these binders, I came across something that made me burst out laughing in my cubicle. A font that consisted of slices of a pie chart. The necessity of such a font requires some background explanation.

DJDE and JSL

Like I mentioned before, the 9700 printer existed years before PostScript, but Xerox still needed a way to get formatted text onto a page. No business would buy a large fancy laser printer that could only print in one style of text in a single point size. Even printing presses could do more than that, so Xerox needed a format to represent data on a page for the printer.

This is where DJDE (Dynamic Job Descriptor Entries) and JSL (Job Source Library) come into play. These two formats combine to describe a print job. The DJDE format contains the variable (dynamic) data for each page, and the JSL defines various settings and configuration options for the job as a whole.

JSL

The Job Source Library contains items like a list of anchor points to start drawing text, paper types, page orientations, and a selection of fonts available for a given job.

DJDE

The Dynamic Job Descriptor Entries are what we call “print files” at my day job. These contain all the text and images that are printed on a page. Each line begins with a command and font information. Commands are either a comment, an indication to move to the next anchor defined in the JSL, or some page specific settings like duplexing.

The rest of the line after the command and font identifier is text printed to the page with the given font. This font must be defined before being used or garbage will print out on the page. Ask me how I know.

Images

One of the command sequences that can be used in the DJDE tells the printer to put an image at the current location instead of writing text. This is commonly used for logos and other imagery that doesn’t change too often. When we get a new logo for a customer one of my coworkers has to go and convert that image to the correct format and make it available to the printer before attempting to print.

This is a problem when some dynamic non-text needs to be printed on the page. A good example of this are barcodes. Simple one dimensional barcodes are rather straight forward as you can just assign a patterns of bars and spaces to letters in a font and be on your way. Even some two dimentional barcodes can use fonts to generate the correct image on a page, like datamatrix barcodes.

The Pie Chart Font

Then comes the pie chart font. A customer at one point wanted a pie chart on their customer statement with slices of the chart being variable in size. Creating an individual image for each pie chart was not an option as the images needed to be “baked in” before running the job. So the solution that a developer came to was to create a set of fonts that can be used to encode a pie chart using the same idea as barcodes.

Pie Slices

Once I discovered these fonts, I needed them. I needed them in a format that I could use. Almost nothing modern knows what this font is or how to read it. So I had a journey ahead of myself.

The Xerox Font Format (.FNT)

There are two formats for this font: 9700 and 5Word. The only difference between these two formats is the character metadata table. The 9700 format uses four words (8 bytes) per entry while the 5Word format uses, you guessed it, five words (10 bytes) per entry.

Headers

There are two headers for this format. One of the headers is optional. If this optional header exists it will be the first 80 bytes of the file. If not, the main header will start at the first byte. I’m going to start with the main header for now.

Main Header

The main header is padded to fill 256 bytes. There’s a few missing pieces in the header that I haven’t been able to figure out yet. They might just be unused filler.

type MainHeader struct {
    Orientation byte
    FontType    byte

    PixelHeight     uint16
    LineSpacing     uint16
    FixedWidth      uint16
    DistanceBelow   uint16
    DistanceAbove   uint16
    DistanceLeading uint16

    _ [2]byte

    LastCharacter uint16
    BitmapSize uint16

    _ [4]byte

    FontName [6]byte
    Revision [2]byte

    _ [2]byte

    Verision [2]byte
    Library  [10]byte

    _ [210]byte

}
Orientation
Value Character Meaning
0x50 P Portrait
0x4C L Landscape
0x49 I Inverted Portrait
0x4A J Inverted Landscape

Changing the orientation of the page has no effect on the font. The font needs to be rotated to match the desired output on the page. See the illustration below as an example.

Orientations]

FontType
Value Character Meaning
0x46 F Fixed
0x50 P Proportional
PixelHeight

Height of the character bounding box in pixels.

LineSpacing

Number of pixels between each baseline.

FixedWidth

Width of a character in pixels. This is ignored if the font is a proportional type.

Optional Header

This header isn’t found in the library of fonts that I have access to, however it is added to any font I either create or modify. I haven’t figured out everything in this header mainly because it can be straight up ignored.

type OptionalHeader struct {
    FileType byte
    FontType byte

    UnknownA  [16]byte
    FontnameA [6]byte // Filename without extension
    FontnameB [6]byte // Filename extension (usually "   FNT")
    UnknownB  [4]byte
    UnknownC  [12]byte

    _ [81]byte

    End byte // always '*' (0x2A)
}

The FileType and FontType fields probably determine a few properties of the rest of the font. I’ve seen differences for 5Word vs 9700 with orientation for FileType and Fixed/Proportional values for FontType. I need to generate a bunch more typefaces for a larger sample size to really narrow down what things actually mean. I’ve seen conflicting values so I’m not really comfortable giving any definates here.

Width Table

Table of character widths. Always 256 bytes long. This is not the width of the data, but the width of the character for kerning purposes (I think).

Character Metadata Table

This table contains the metadata for each character in the font. Non-printing characters, including the control characters from values 0x00 through 0x0F, are present in this table.

Each entry in this table is either 8 or 10 bytes long, depending on the format. Both formats will pad the table to the next 128 entries. The minimum size for this table is 128 entries, or 1024 and 1280 bytes for either the 9700 and 5Word formats respectively.

9700 (4Word)
type CharacterMeta9700 struct {
	BlanksLeft  uint16
	GlyphOffset uint16
	BitmapSize  int16
	CellWidth   uint16
}
5Word
type CharacterMeta5Word struct {
	BlanksLeft  uint16
	GlyphOffset uint16
	Unknown     uint16
	BitmapSize  int16
	CellWidth   uint16
}

Not as much effort has gone into figuring out the 5Word format as the library of fonts I have access to only uses the 9700 format.

BlanksLeft

The high bit of this value (BlanksLeft & 0x8000) denotes weather or not this is as spacing character. If it is set, the given character is spacing and does not have any associated bitmap data.

The rest of the bits are the baseline offset. The name doesn’t make any sense until you realize that the glyphs are all rotated 90 degrees clockwise. This means that the left side of the glyph is the bottom of a portrait font glyph.

Note that the name of this field comes from the font editor program I used to generate samples.

GlyphOffset

This is the byte offset to the bitmap data of the glyph. The offset is relative to the end of the metadata table and is halved. To get the true value of the offset, mutliply this value by two.

BitmapSize

These two bytes contain the packed dimensions of the bitmap, in pixels.

width  = abs(BitmapSize) & 0x1FF
height = abs(BitmapSize >> 9) * 8

The size of the glyph data is (height/8)*width bytes.

CellWidth

This is the width of the bounding box for the glyph. Or in other terms, this value is the horizontal offset of the next glyph’s origin from the current glyph’s orign point.

Unknown (5Word)

I’ve got no idea what this field is. It seems to always be 0xC000 in the files I can generate.

Character Bitmap Data

One bit per pixel (1bpp) image data for each non-spacing character. Characters that have the Spacing flag set do not have their bitmap data saved.

The dimensions found in BitmapSize can be used to determine the number of bytes the glyph bitmap contains.

The glyphs for each character are stored rotated 90 degrees clockwise. Each row in the glyph bitmap data is really a column in the output character’s bitmap.

For example, this is the bitmap data for p:

00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
00000000 00000000 00000000 00000000
11111111 11111111 11111111 11111110
11111111 11111111 11111111 11111110
11111111 11111111 11111111 11111110
11111111 11111111 11111111 11111110
00000000 00011100 00000000 00111000
00000000 00111000 00000000 00011100
00000000 00110000 00000000 00011100
00000000 01110000 00000000 00001110
00000000 01110000 00000000 00001110
00000000 01110000 00000000 00001110
00000000 01110000 00000000 00001110
00000000 01110000 00000000 00001110
00000000 01111000 00000000 00011110
00000000 00111100 00000000 00111100
00000000 00111111 00000000 11111100
00000000 00011111 11111111 11111000
00000000 00001111 11111111 11110000
00000000 00000111 11111111 11100000
00000000 00000000 11111111 00000000

Font Placement

Once rotated 90 degrees counter clockwise, these are the measurements for each glyph:

Glyph Measurements

W Width
H Height
CW CellWidth
B Baseline
BL BlanksLeft
X Line up with previous character’s CellWidth
Y Top of bitmap, see below

Each font has a baseline offsett value (BlanksLeft & 0x7FF). This can be used to place glyphs at the correct height so that all their baselines line up.

MaxHeight = Header.DistanceAbove + Header.DistanceBelow
Y = Character.Height
    - (MaxHeight - Character.BlanksLeft)
    - MainHeader.DistanceAbove

The Piechart Font

Now that we can decode these fonts, we can finally get those piechart fonts that initially sparked this whole journey. The final hurdle is just getting them into an open format so other programs can use them.

The format I’ve chosen for this is BDF (Glyph Bitmap Distribution Format). This is a text-based format that is used in the X Window System.

I still need to iron out the BDF exporting, but it mostly (almost) works. Here is a kinda broken export of the piechart font into BDF: piechart_v0.zip.

The Code

Finally, you can find the code I’ve written to decode these fonts can be found over on GitHub:

https://github.com/zorchenhimer/xerox-fonts

links

I do computer things, i guess