Home Products Documents links News Events Tech Info

Font File Formats

In all the formats described below, 2-byte quantities are little-endian:
that is, the least significant byte comes first, followed by the
most-significant.  The values are unsigned unless otherwise stated.


IntMetrics / IntMet:
        
        40      Name of font, padded with 
        4       16
        4       16
        1       nlo = low-byte of number of defined characters
        1       version number of file format:
                        0       flags and nhi must be 0
                        1       **** not supported ****
                        2       you can set the flags as described
                                and nchars can be > 255
        1       flags:
                bit 0 set => there is no bbox data (use Outlines)
                bit 1 set => there is no x-offset data
                bit 2 set => there is no y-offset data
                bit 3 set => there is more data after the metrics
                bit 4 reserved (must be 0)
                bit 5 set => character map size precedes map
                bit 6 set => kern characters are 16-bit, else 8-bit
                bit 7 reserved (must be 0)
        1       nhi = high byte of number of defined characters

                n = nlo + 256*nhi

                If flags bit 5 set:
        2       m = character map size (lo,hi) (0 => no map)
                m = 256 if flags bit 5 clear

        m       character mapping (ie. indices into following arrays)
                if not present, index = character code

                Note that since the mapping table is 8-bit, there cannot be
                one if n > 256.

                Tables giving bounding boxes (1/1000th em) of characters:
                If flags bit 0 clear:
        2n      signed x0 2-byte values
        2n      signed y0 2-byte values
        2n      signed x1 2-byte values
        2n      signed y1 2-byte values

                Tables of character widths:
                If flags bit 1 clear:
        2n      signed 2-byte x-offsets after printing each character
                If flags bit 2 clear:
        2n      signed 2-byte y-offsets after printing each character


        To calculate offset to here:

                  nlo = byte at offset 48 in file
                  nhi = byte at offset 51 in file
                flags = byte at offset 49 in file
                    n = nlo + 256*nhi  ^^->Acorn, you mean 50 me thinks....

                offset = 52
                if (flags bit 5 clear) then offset += 256
                                       else offset += 2 + byte(52) + 256*byte(53)
                if (flags bit 0 clear) then offset += 8n
                if (flags bit 1 clear) then offset += 2n
                if (flags bit 2 clear) then offset += 2n

                If flags bit 3 set:

        8       table of 4 2-byte unsigned offsets from start of table:
                    entry 0 = offset to 'miscellaneous' data
                    entry 1 = offset to kern pair data
                    entry 2 = offset to reserved area #1
                    entry 3 = offset to reserved area #2

                The entries must be consecutive in the file, so the end of
                one area coincides with the beginning of the next.  The
                areas are not necessarily word-aligned, and the space at the
                end of each area is reserved (ie. there must not be any
                'dead' space at the end of an area).

        Area 0: Miscellaneous data:

        8       font bounding box in 1/1000th em (signed x0,y0,x1,y1)
        2       default x-offset per char (if flags bit 1 set)
        2       default y-offset per char (if flags bit 2 set)
        2       italic h-offset per em (-1000 * TAN(italic angle))
        1       underline position (signed, in 1/256th of an em)
        1       underline thickness (unsigned, in 1/256th of an em)
        2       CapHeight (1/1000th em, 2-byte signed)
        2       XHeight (1/1000th em, 2-byte signed)
        2       Descender (1/1000th em, 2-byte signed)
        2       Ascender (1/1000th em, 2-byte signed)
        4       reserved field (must be 0)

        Area 1: Kern pair data:

                flags bit 6 clr => character codes are 8-bit
                flags bit 6 set => character codes are 16-bit (lo,hi)

        1 or 2  left-hand letter code                          ]
        1 or 2  right-hand letter code                ]        ]
        2       x-kern amount (if flags bit 1 clear)  ] repeat ] repeat
        2       y-kern amount (if flags bit 2 clear)  ]        ]
        1 or 2  0 => end of list for this letter               ]
        1 or 2  0 => end of kerns

                Or, in pseudo-Backus-Naur notation:

                   ::= * 
         ::=  * 
                ::=   
                  ::= <8-bit character code> if flags bit 6 clear
                           or <16-bit character code> if flags bit 6 set
                ::= 
                           or  if flags bit 1 set
                ::= 
                           or  if flags bit 2 set
                ::= < with code 0>

        Area 2: Reserved (must be null)

        Area 3: Reserved (must be null)


x90y45:

        Index:
                1       point size (not multiplied by 16)
                1       bits per pixel (4)
                1       pixels per inch (x-direction)
                1       pixels per inch (y-direction)
                4       reserved (was checksum) - must be 0
                4       offset of pixel data in file
                4       size of pixel data
                ...     more of the same
                1       0

        Pixel data:
                4       x-size in 1/16ths point * pixels per inch (x)
                4       y-size in 1/16ths point * pixels per inch (y)
                4       pixels per inch (x-direction)
                4       pixels per inch (y-direction)
                1       x0    - maximum bounding box for any character
                1       y0    - bottom-left is inclusive
                1       x1    - top-right is exclusive
                1       y1    - all coordinates are in pixels
                512     2-byte offsets from table start of character data
                        0 => character is not defined
                        (pixel data is limited to 64K per block)

        Character data:

                1       x0      - bounding box
                1       y0
                1       x1-x0
                1       y1-y0
                4*n     4-bpp, consecutive rows bottom->top
                              not aligned until the end


Outlines / Outlines / f9999x9999 / b9999x9999:

        b9999x9999      1-bpp definition
        a9999x9999      4-bpp (anti-aliased) definition
        Outlines        the outline file

              '9999' = pixel size (ie. point size * 16 * dpi / 72)
                       zero-suppressed decimal number

        File header:
                4       "FONT"  - identification word
                1       Bits per pixel: 0 = outlines
                                        1 = 1 bpp
                                        4 = 4 bpp
                1       Version number of file format
                               4: no "don't draw skeleton lines unless smaller than this" byte present
                               5: byte at [table+512] = max pixel size for skeleton lines (0 => always do it)
                               6: byte at [chunk+indexsize] = dependency mask (see below)
                               7: flag word precedes index in chunk (offsets are rel. to index, not chunk)
                               8: file offset array is in a different place
                2       if bpp = 0: design size of font
                        if bpp > 0: flags:
                              bit 0 set => horizontal subpixel placement
                              bit 1 set => vertical subpixel placement
                              bit 6 set => flag word precedes index in chunk (version 7 onwards)
                              bits 2..5, 7 must be 0
                              NB: for outline files, bit 6 is derived from the version number
                                  but if present, its value must suit the version number
                2       x0      - font bounding box (16-bit signed)
                2       y0      - units are pixels or design units
                2       x1-x0   - x0,y0 inclusive, x1,y1 exclusive
                2       y1-y0

                If Version < 8: nchunks = 8

                4       file offset of 0..31 chunk (word-aligned)
                4       file offset of 32..63 chunk
                ...
                4       file offset of 224..255 chunk
                4       file offset of end (ie. size of file)
                        if offset(n+1)=offset(n), then chunk n is null.

                Else (Version >= 8): nchunks = as defined below

                4       file offset of area containing file offsets of chunks
                4       number of defined chunks
                4       ns = number of scaffold index entries (including entry[0] = size)
                4       scaffold flags:
                                bit 0 set => ALL scaffold base chars are 16-bit
                                bit 1 set => these outlines should not be anti-aliased (eg. System.Fixed)
                                bit 2 set => fill using non-zero winding rule, else odd-even.
                                bits 3..31 reserved (must be 0)
                4*5     all reserved (must be 0)

     Table start:
                2       n = size of table/scaffold data

         Bitmaps: (n=10 normally - other values are reserved)
                2       x-size (1/16th point)
                2       x-res (dpi)
                2       y-size (1/16th point)
                2       y-res (dpi)

         Outlines:
           ns*2-2       2-byte offsets to scaffold data:

                        If scaffold flags bit 0 clear:
                          bits 0..14 = offset of scaffold data from table start
                          bit 15 set => base char code is 2 bytes, else 1

                        If scaffold flags bit 0 set:
                          bits 0..15 = offset of scaffold data from table start
                          base char code is always 2 bytes

                        0 => no scaffold data for char

                1       Skeleton threshold pixel size
                        (if file format version >= 5)
                        When rastering the outlines, skeleton lines will
                        only be drawn if either the x-or y- pixel size is
                        less than this value (except if value=0, which means
                        'always draw skeleton lines').
                ?       ... sets of scaffold data (see below)

     Table end: ?       description of contents of file:
                        , 0, "Outlines", 0
                                        "999x999 point at 999x999 dpi", 0
                        padded with zeros until word-aligned

                If Version >= 8:

                4       file offset of chunk 0
                4       file offset of chunk 1
                ...
                4       file offset of chunk (nchunks-1)
                4       file offset of end of file

                All versions:

                        ... word-aligned chunks follow

     Scaffold data:
              1 or 2    char code of 'base' scaffold entry (0 ==> none)
                1       bit n set ==> x-scaffold line n defined in base char
                1       bit n set ==> y-scaffold line n defined in base char
                1       bit n set ==> x-scaffold line n defined locally
                1       bit n set ==> y-scaffold line n defined locally
                        ... local scaffold lines follow
     Scaffold lines:
                2       bits 0..11 = coordinate (signed)
                        bits 12..14 = scaffold link index (0 => none)
                        bit 15 set => 'linear' scaffold link
                1       width (254 ==> L-tangent, 255 ==> R-tangent)

     Chunk data:
                4       flag word (not present before file format version 7):
                              bit 0 set => horizontal subpixel placement
                              bit 1 set => vertical subpixel placement
                              bit 7 set => dependency byte(s) present (see below)
                              bits 2..6 and 8..30 must be 0
                              bit 31 must be 1

                4 * 32  offset from index start to character
                        0 => character is not defined
                           * 4 for vertical placement
                           * 4 for horizontal placement
                        Character index is more tightly bound than vertical
                        placement which is more tightly bound than
                        horizontal placement.

                n      Dependency byte(s) (if outline file, version >= 6).
                        One bit required for each chunk in file.
                        Bit n set => chunk n must be loaded in order to
                        rasterise this chunk.  This is required for
                        composite characters which include characters from
                        other chunks (see below).

                        ... character data follows (word-aligned at end of chunk)

                        Note: All character definitions must follow the
                              index in the order in which they are specified
                              in the index.  This is to allow the font
                              editor to easily determine the size of each
                              character.

     Char data:
                1       flags:
                           bit 0 set => coords are 12-bit, else 8-bit
                           bit 1 set => data is 1-bpp, else 4-bpp
                           bit 2 set => initial pixel is black, else white
                           bit 3 set => data is outline, else bitmap
                           if bit 3 clr: bits 4..7 = 'f' value for char (0 ==> not encoded)
                           if bit 3 set: bit 4 set => composite character
                                         bit 5 set => with an accent as well
                                         bit 6 set => ascii codes within this char are 16-bit, else 8-bit
                                         bit 7 reserved (must be 0)

         if flag bits 3 and 4 set:
                1 or 2     character code of base character
           if flag bit 5 set:
                1 or 2     character code of accent
                2 or 3     x,y offset of accent character

         if flag bits 3 or 4 clear:
                2 or 3     x0, y0  sign-extended 8- or 12- bit coordinates
                2 or 3     xs, ys  width, height (bbox = x0,y0,x0+xs,y0+ys)
                n          data: (depends on type of file)
                             1-bpp uncrunched: rows from bottom->top
                             4-bpp uncrunched: rows from bottom->top
                             1-bpp crunched: list of (packed) run-lengths
                             outlines: list of move/line/curve segments
                           word-aligned at the end of the character data

Outline char format
-------------------

Here the 'pixel bounding box' is actually the bounding box of the outline in
terms of the design size of the font (in the file header).  The data
following the bounding box consists of a series of move/line/curve segments
followed by a terminator and an optional extra set of line segments followed
by another terminator.  When constructing the bitmap from the outlines, the
font manager will fill the first set of line segments to half-way through
the boundary using an even-odd fill, and will thin-stroke the second set of
line segments (if present).  See the documentation on the Draw module for
further details.

If the font is version 8 or greater then it can specifiy that the winding
rule be either non-zero or odd-even, this is to provide compatibility with
other type face formats (see above in scaffold flags).

Each line segment consists of:

        1       bits 0..1 = segment type:
                            0 => terminator (see below)
                            1 => move to x,y
                            2 => line to x,y
                            3 => curve to x1,y1,x2,y2,x3,y3
                bits 2..4 = x-scaffold link
                bits 5..7 = y-scaffold link
                ... coordinates (design units) follow

Terminator:
                bit 2 set => stroke paths follow
                             (same format, but paths are not closed)
                bit 3 set => composite character inclusions follow:

Composite character inclusions:

        1 or 2  character code of character to include (0 => finished)
        2 or 3  x,y offset of this inclusion (design units)

The coordinates are either 8- or 12-bit sign-extended, depending on bit 0 of
the character flags (see above), including the composite character
inclusions.

The character codes in the composite character sections are either 8- or
16-bit (low-byte first), depending on bit 6 of the character flags.

The scaffold links associated with each line segment relate to the last
point specified in the definition of that move/line/curve, and the control
points of a bezier curve have the same links as their nearest endpoint.

Note that if a character includes another, the appropriate bit in the parent
character's chunk dependency flags must be set.  This byte tells the Font
Manager which extra chunk(s) must be loaded in order to rasterise the parent
character's chunk.


1-bpp uncompacted format
------------------------

1 bit per pixel, bit set => paint in foreground colour, in rows from
bottom-left to top-right, not aligned until word-aligned at the end of the
character.


1-bpp compacted data format
---------------------------

The whole character is initially treated as a stream of bits, as for the
uncompacted form.  The bit stream is then scanned row by row, with
consecutive duplicate rows being replaced by a 'repeat count', and alternate
runs of black and white pixels are noted.  The repeat counts and run counts
are then themselves encoded in a set of 4-bit entries.

Bit 2 of the character flags determine whether the initial pixel is black or
white (black = foreground), and bits 4..7 are the value of 'f' (see below).
The character is then represented as a series of packed numbers, which
represent the length of the next run of pixels.  These runs can span more
than one row, and after each run the pixel colour is changed over.  Special
values are used to denote row repeats.

 ==
          0         followed by n-1 zeroes, followed by n+1 nibbles
                    = resulting number + (13-f)*16 + f+1 - 16
   i =    1 .. f    i
   i =  f+1 .. 13   (i-f-1)*16 + next nibble + f + 1
         14         followed by n= = repeat count of n
         15         repeat count of 1 (ie. 1 extra copy of this row)

The optimal value of f lies between 1 and 12, and must be computed
individually for each character, by scanning the data and calculating the
length of the output for each possible value.  The value yielding the
shortest result is then used, unless that is larger than the bitmap itself,
in which case the bitmap is used.

Repeat counts operate on the current row, as understood by the unpacking
algorithm, ie. at the end of the row the repeat count is used to duplicate
the row as many times as necessary.  This effectively means that the repeat
count applies to the row containing the first pixel of the next run to start
up.

Note that rows consisting of entirely white or entirely black pixels cannot
always be represented by using repeat counts, since the run may span more
than one row, so a long run count is used instead.


Encoding files
--------------

An encoding file is a text file which contains a set of identifiers which
indicate which characters appear in which positions in a font.

Each identifier is preceded by a "/", and the characters are numbered from
0, increasing by 1 with each identifier found.

Comments are introduced by "%", and continue until the next control
character.

The following special comment lines are understood by the font manager:

        %%RISCOS_BasedOn 
        %%RISCOS_Alphabet 

where  and  denote positive decimal integers.

Both lines are optional, and they indicate respectively the number of the
base encoding and the alphabet number of this encoding.

If the %%RISCOS_BasedOn line is not present, then the Font Manager assumes
that the target encoding describes the actual positions of the glyphs in an
existing file, the data for which is in:

        .IntMetrics
        .Outlines

where  is null if the %%RISCOS_Alphabet line is omitted.

(In fact the leafnames are shortened to fit in 10 characters, by removing
characters from just before the  suffix).

In this case the IntMetrics and Outlines files are used directly, since
there is a one-to-one correspondence between the positions of the characters
in the datafiles and the positions required in the font.

If the %%RISCOS_BasedOn line IS present, then the Font Manager accesses the
following datafiles:

        .IntMetrics
        .Outlines

and assumes that the positions of the glyphs in the datafiles are as given
by the contents of the base encoding file.

The base encoding is called "/Base", and lives in the Encodings directory
under Font$Path, along with all the other encodings.  Because it is preceded
by a "/", the Font Manager does not return it in the list of encodings
returned by Font_ListFonts.

Note that only one encoding file with a given name can apply to all the
fonts known to the system.  Because of this, a given encoding can only be
either a direct encoding, where the alphabet number is used to reference the
datafiles, or an indirect encoding, where the base encoding number specifies
the datafile names.

Here is the start of a sample base encoding ("/Base0"):

        % /Base0 encoding

        %%RISCOS_Alphabet 0

        /.notdef /.NotDef /.NotDef /.NotDef
        /zero /one /two /three /four /five /six /seven /eight

Here is the start of a sample encoding file ("Latin1"):

        % Latin 1 encoding

        %%RISCOS_BasedOn 0
        %%RISCOS_Alphabet 101

        /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
        /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
        /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
        /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef /.notdef
        /space /exclam /quotedbl /numbersign
        /dollar /percent /ampersand /quotesingle

(Note that the sample /Base0 file is not the same as the released one).

These illustrate several points:

    1.  The %% lines must appear before the first identifier.

    2.  Character 0 in any encoding must be called ".notdef", and represent
        a null character.

    3.  Other null characters in the base encoding must be called ".NotDef",
        to distinguish them from character 0.

    4.  Non-base encoding files wanting to refer to the null character
        should use ".notdef" in all cases.

    5.  The other character names should follow the Adobe PostScript names
        wherever possible.  This is to enable the encoding to refer to Adobe
        character names when included as part of a print job by the
        PostScript printer driver.

    6.  The number of characters desribed by the base encoding can be
        anything from 0 to 768, and should refer to distinct characters
        (apart from the ".NotDef"s).  Other encodings, however, must
        contain exactly 256 characters, which need not be distinct.

poppy@poppyfields.net