[net.text] Xerox 2700 laser printer font format

cudac@daisy.warwick.UUCP (Tim Clark) (11/12/85)

About a year ago I issued an item to net.text giving what I had discovered
about Xerox 2700 down-line-load font files (Xerox are reluctant to release
details). I also asked if anyone could fill in the gaps in my findings. I
received a couple of replies, and by further work have got an almost complete
description of the files - enough to do serious work with them. Below are the
details of the format.

The Xerox 2700 comes in a number of other guises e.g.: the EPS 1200
(Electronic Printing Systems, a UK firm), and as the DEC LN01 (with some
changes).

Numbers below are decimal unless otherwise stated, or preceded
by 0x for hex. The term 'word' is used to describe a 16-bit entity.

1. The binary file vs the down-load file
----------------------------------------
The Xerox fonts are down line loaded as a series of characters in the range
question mark to tilde. These have ASCII values 63 to 126. Take 63 off the
decimal value of each character, yielding a value in the range 0 to 63. The
resulting 6-bit quantities are taken four at a time to yield three 8-bit
quantities. The result of storing these in sequence is the binary
representation required.

2. Format of the binary file
----------------------------
The file consists of five sections:

        1. The header block
        2. A table of uncertain purpose!
        3. The look-up table
        4. The bit patterns of the characters
        5. The trailer

3. The header block
-------------------
This is 24 words long

My include file defining the structure follows:-

/****************************************************************************/
/*                                                                          */
/*	Structures defining the format of Xerox 2700 (EPS 1200)             */
/*	laser printer font files.                                           */
/*                                                                          */
/*      Note: these structures only match the format of the external        */
/*      file when used on PDP-11s, VAXes, or other machines with the        */
/*      same size data types and same byte ordering.                        */
/*                                                                          */
/*	The structures are based on investigative work done by the          */
/*	author, and include help from sources at least one of whom 	    */
/*	wishes to remain anonymous. This help is gratefully		    */
/*	acknowledged.							    */
/*									    */
/*	Tim Clark  Computer Unit  University of Warwick  June 1985          */
/****************************************************************************/

struct xheader {        /* The font header - 24 (16 bit) words */
	unsigned short magic;		/* should be 0xaaaa		*/
	unsigned char rev;		/* revision number - unused	*/
	unsigned char flags;		/* font type flags (see below)  */
	unsigned short lo_length;       /* length of file in bytes lsb  */
	char fname[20];			/* font name in ascii		*/
	unsigned char ulinedepth;	/* posn of underline below base */
	unsigned char ulinesize;	/* thickness of underline	*/
        unsigned char hi_length;        /* length of file in bytes msb  */
	unsigned char strike_through;	/* unused ?                     */
	unsigned char superdist;	/* superscript distance		*/
	unsigned char subdist;		/* subscript distance		*/
	short descend;			/* maximum descender		*/
	short ascend;			/* maximum ascender		*/
	short fheight;			/* font height - 1		*/
	unsigned char lowchar;		/* first defined character	*/
	unsigned char highchar;		/* last defined character	*/
	char partno[5];			/* part number - unused		*/
	char nulls[3];			/* reserved - set to null	*/
};

/* Font type flags */
#define	PORTRAIT	0		/* length is the larger dimension */
#define LANDSCAPE	1		/* width is the larger dimension */
#define FIXED_SP	0		/* fixed pitch */
#define PROP_SP		2		/* proportional spacing */
#define SHORT_FONT      0		/* font fits into 0xffff bytes */
#define LONG_FONT	4		/* font is more than 0xffff bytes */

A note on the length of the file: earlier versions of the 2700 (and I think
always the LN01) use the msb (most significant byte) of the length for
other purposes, and restrict themselves to files no bigger than 0xffff. For
other versions take the lsb (least significant bytes) and add in the msb to
get a 24-bit quantity.

4. The table of uncertain purpose
---------------------------------
256 bytes long

  This follows immediately after the header block.

The meaning of this table is unknown, it is entirely zero in most of the
fonts we have, and mostly zero in the remainder. My guess is the
information in here is one byte per character in the font, and somehow
qualifies the information for that character. I've set it to all zeros in
my work without ill effect.

5. The look-up table
--------------------

  This follows immediately after the qualification table. It consists of
4-word entries, one per character in the font, and is terminated by an
entry of all zeroes. The look up table is used by subtracting 32 from the
value of the ASCII character, and using that as an index. Thus space is index
0, exclamation mark is index 1, double quote 2, etc.

struct xchardesc {      /* The "look up table" for each character.
                           Each is 4 (16 bit words). */

	unsigned short nbyte; 	/* the length of the pattern in bytes       */

        unsigned short lo_loc;  /* the lowest 16 bits of the location of    */
                                /* the pattern, expressed as a 24-bit       */
                                /* quantity, which is the offset into the   */
                                /* font file                                */

        unsigned char hi_loc;   /* the highest 8 bits of the pattern        */
                                /* location offset (0xff equivalent to 0)   */

        unsigned char blocking; /* if "blocking" is zero then there is no   */
                                /* pattern information. Otherwise the value */
                                /* 63-blocking gives the number of bytes in */
                                /* each row of the character pattern        */

        char orgy;  		/* in two's complement. How much the        */
                                /* character is above (or if -ve, below)    */
                                /* the baseline (portrait) or from the      */
                                /* typing position (landscape). Units are   */
                                /* DOUBLE rasters.                          */

	unsigned char width;    /* the amount to move the typing position   */
                                /* on after drawing this character, in      */
                                /* units of rasters.                        */
	};


6. The bit patterns of the characters
-------------------------------------

After the look up table are the patterns themselves, these are interpreted
according to the information in the look up table. Each entry must be an even
number of bytes (i.e. a whole number of words) long.

7. The trailer
--------------

After the last indexed character pattern the file is padded out with words of
value [5555].

8. Example
----------

Take the following 10 point portrait font as an example.

The 24 word header is as follows in hex

 aaaa 0402 2916 6f4b 6d73 736f 3031 502d
 2020 2020 2020 2020 2020 0404 040f 0000
 000a 0024 0032 bd20 3252 3432 3931 2020

word 0 is 0xaaa, word 2 is the length of the (binary) file, 0x2916 or
10518 bytes.

The table "of unknown purpose" is all zeros, and the look-up table
starts with:

[ 0002 0620 3DFF 1200 ]

This indicates that the space character (ASCII SP value 32 - 32 = 0) has a
pattern of length 2 bytes, starting at byte 0x620 or 1568. The value 0x3D
shows that is comprised of rows two bytes wide. The important thing here,
is that it should advance the typing position by 0x12 or 18 rasters, and it is
drawn on the baseline with no offset (0x00).

Looking into the file at offset 1568, we find (not suprisingly!) 0x0000, i.e.
the pattern drawn is blank.

Looking further down the look-up table at the 33rd entry (ASCII A
value 65 - 32 = 33) we get:

hex:  0074 106A 3BFF 1E00

This means the pattern is of length 0x0074 or 116 bytes, starting at byte
0x106A or 4202. The value 0x3B shows that it is comprised of rows four
bytes wide. It advances the typing position by 0x1E or 30 rasters, and is
drawn on the baseline with no offset 0x00.

Looking into the file at offset 4202, and taking four bytes per row we get:

e0000000 ***
f8000000 *****
ff000000 ********
ffc00000 **********
fff80000 *************
1ffe0000    ************
07ffc000      *************
01fff000        *************
01fffe00        ****************
01e7ff80        ****  ************
01e1ffe0        ****    ************
01e03ff8        ****       ***********
01e007fc        ****          *********
01e001fc        ****            *******
01e0007c        ****              *****
01e001fc        ****            *******
01e007fc        ****          *********
01e03ff8        ****       ***********
01e1ffe0        ****    ************
01e7ff80        ****  ************
01fffe00        ****************
01fff000        *************
07ffc000      *************
1ffe0000    ************
fff80000 *************
ffc00000 **********
ff000000 ********
f8000000 *****
e0000000 ***

                        -----------------------

I have some programs which convert between Xerox format and bsd
vfont(5) format, and allow one to view a xerox font file. We do our
work on the vfont files, using bsd fed(1), and then convert back to xerox
format. It has the disadvantage that it doesn't cope with large files (due to
the restrictions of vfont). However, they've been very useful in making
alterations to the fonts, and also enabling us to use some of the
Berkeley supplied fonts on our 2700. Though remember that you need a 15 point
vfont (at 200 dots per inch) to make a 10 point xerox font (at 300 dots per
inch). I'm posting the programs to the moderator of mod.sources, as
we can't afford the cost of transatlantic mail in dealing with multiple
request for the software outside Europe.

Tim Clark, Computer Unit, University of Warwick, Coventry, UK   CV4 7AL
phone: +44 203 523224
mail:  uucp:  ihnp4!cfg!ukc!warwick!cudac
       Arpa:  cudac%daisy.warwick.ac.uk@ucl-cs
       JNT:   cudac@uk.ac.warwick.daisy