Jazz Jackrabbit Font Format
The fonts in Jazz Jackrabbit are 8-bit sequential fonts with variable widths and heights per symbol. They are stored in two different ways; the normal fonts, with .0FN extension, are compressed, but one font file, FONTS.000, is in a different format, which does not use compression. Some font symbols are stored in non-font files; for example, the bonus font is stored in BONUS.000, together with the bonus sprites.
The standard .0FN files (FONT2, FONTBIG, FONTINY, FONTMN1 and FONTMN2) are compressed 8-bit fonts. They use palette index 0 as transparent colour.
The files start with a 23 byte header:
|0x00||Char||Identifier1||Literal string "Digital Dimensions".|
|0x12||BYTE||Identifier2||Always byte 0x1A.|
|0x14||BYTE||LineHeight||Line height. This is not a restriction on how high the symbols can be, but a value used to determine how many pixels to go down to paint a next line of this font.|
|0x15||UINT16LE||Unknown3||Always two 00-bytes.|
Note that in situations where text is drawn on arbitrary positions on the screen, the line height setting will not be used. Also, in several places in the game, the space width will either be overridden by a fixed value, or expanded or reduced by a specific set amount. A good place to see both values at work as intended is in the full-text pages of the "Instructions" section of the game.
The fonts do not contain any information concerning the space between symbols. Some scenes, like the score screen and start-of-level "GET READY" text, have all symbol widths padded up to the next multiple of four pixels. This may be a side effect of the fact a lot of sprites, including the ones in FONTS.000, are stored in a way that forces their width to a multiple of 4 pixels. Note that when symbols get padded, this padding does not seem to apply to the space width.
The remainder of the font is filled up with the symbols. Each symbol consists of a little-endian word indicating the uncompressed size of the symbol data, followed by the compressed block. This block is in the Jazz Jackrabbit RLE compression format, which means it starts with an indicator of how long the compressed data is.
|0x00||UINT16LE||UncompressedLength||Length of the uncompressed data.|
|0x02||UINT16LE||CompressedLength||Length of the compressed data that follows. This can be used to know how much to skip to get to the next symbol block.|
|0x04||BYTE[CompressedLength]||CompressedData||Actual compressed data. Note that the Jazz Jackrabbit RLE data format normally includes the preceding CompressedLength block.|
An UncompressedLength of 0 indicates that the symbol is not present at all. In that case, no compressed block (length + data) will be present behind it. These dummy entries are not treated as 0×0 symbols, but are substituted by the space width from the header, even if an explicit symbol for the space is set (see "Symbol order").
Once uncompressed, the data has the following format:
|0x00||UINT16LE||Width||Width of the symbol data|
|0x02||UINT16LE||Height||Height of the symbol data|
|0x04||BYTE[Width*Height]||ImageData||The actual image data, in 8 bit per pixel format.|
The font can not handle images that have 0 as one or both dimensions; they will cause corruptions in the game. Since empty dummy symbols are substituted by the space width, adding completely empty symbols is not possible, except by setting the space width in the header to 0, and writing the space symbol as explicit image (see "Symbol order").
Since the Jazz Jackrabbit RLE compression contains both an explicit data length for the compressed content, and an explicit command to stop the decompression, it is trivial to write a value in the CompressedLength field that is larger than the actual compressed length, and fill up the extra space with other data. The game will only use the CompressedLength value to find the next block of data, and will never check if that is actually where the decompression ended.
As seen in the next section, the 116-125 tile range in the font doesn't map to anything, meaning these images can also be used to store information that is ignored by the game.
Unlike most fonts, the order of the symbols in the Jazz Jackrabbit fonts doesn't match any classic text encoding, meaning they act more like sprite files, in that regard. The usage of the exact symbols varies per font, but the game uses an exact mapping to translate bytes to font indices. This is what the font indices map to:
- 00-25: Upper case characters A-Z.
- 26-51: Lower case characters a-z.
- 52-61: Numbers 0-9.
<>- Open square bracket, close square bracket, less-than sign, greater-than sign.
- 66-99: These symbols map to bytes beyond ASCII range. The exact byte order for this range is: 0x81, 0x80, 0x82-0x96, 0x9A, 0x97-0x99, 0x9B, 0xA0-0xA5.
,.?-+=!#%&();:'"- Comma, period, question mark, minus, plus, equals, exclamation mark, number sign, percentage, ampersand, open bracket, close bracket, semicolon, colon, single quote, double quote.
- 116-125: Never used. These don't map to any byte values.
- 126: If present, and not an empty dummy entry, this is used akin to the Unicode Replacement character, as replacement for any bytes that don't map to characters. Do note that the space character is considered such an unsupported character, so in practice, it could be said that this is the space symbol, and all unsupported characters are mapped to the space.
Adding more symbols to the font is possible, but has no use, and will crash the game if too many are present, so for all practical purpose, the maximum amount of symbols in these font files is 127.
The following bytes don't have a place mapped in the Jazz fonts:
- 0x00-0x1F: All byte values below the space
- 0x20: Space symbol
- 0x24: Dollar
- 0x2A: Asterisk
- 0x2F: Forward slash
- 0x40: At sign
- 0x5C: Backslash
- 0x5E: Circumflex accent
- 0x5F: Underscore
- 0x60: Grave accent
- 0x7B: Left curly bracket
- 0x7C: Vertical line
- 0x7D: Right curly bracket
- 0x7E: Tilde
- 0x7F: Delete symbol (sometimes shown as
⌂in DOS ASCII)
- 0x9C-0x9F: Extended ASCII symbols
- 0xA6-0xFF: All further extended ASCII symbols
If any of these values are encountered, they are shown as the replacement symbol at index 126. In practice, if #126 is considered to be the "explicit space symbol", it could be said that all unknown bytes are mapped to the space character.
To easily interpret the data and see for each font symbol position which byte it corresponds to, this table can be used. The 00 entries in the 0x75-0x7D range should be ignored, since these indices in the font don't seem to map to anything. As mentioned, technically the symbol at 126 is a general replacement symbol, and not actually the space character.
41, 42, 43, 44, 45, 46, 47, 48, 49, 4A, 4B, 4C, 4D, 4E, 4F, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 5A, 61, 62, 63, 64, 65, 66, 67, 68, 69, 6A, 6B, 6C, 6D, 6E, 6F, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 7A, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 5B, 5D, 3C, 3E, 81, 80, 82, 83, 84, 85, 86, 87, 88, 89, 8A, 8B, 8C, 8D, 8E, 8F, 90, 91, 92, 93, 94, 95, 96, 9A, 97, 98, 99, 9B, A0, A1, A2, A3, A4, A5, 2C, 2E, 3F, 2D, 2B, 3D, 21, 23, 25, 26, 28, 29, 3B, 3A, 27, 22, 7E, 00, 00, 00, 00, 00, 00, 00, 00, 00, 20
Like the 0FN fonts, this font is an 8-bit sequential font with variable dimensions per symbol. However, the way it is stored is completely different. It has no identifying text at the start, it contains the number of symbols, and it is uncompressed. The actual image data is also interpreted completely differently, working with four slices of graphics that alternate pixel columns to build up the full image.
This font seems to use palette index 254 as transparent colour.
The file starts with a UINT16LE indicating the amount of symbols in the font (which should be 37). This is followed directly by the symbol data blocks.
The symbol data is built up in a peculiar way: the data contains four images that each have the data for 1/4th of the image, as alternating columns. This means the first image 'slice' will fill up columns 0, 4, 8, etc, the second will fill 1, 5, 9, etc, the third fill 2, 6, 10, etc and the fourth completes the image with columns 3, 7, 11, etc. This means all symbols in this font type will have a width that is divisible by four.
The symbol data has the following structure:
|0x00||UINT16LE||SliceWidth||Width of one slice of the symbol graphics. This matches the full symbol width divided by 4.|
|0x02||UINT16LE||Height||Height of the symbol graphics.|
|0x04||UINT16LE||SliceSize||Size of one slice. Matches |
|0x06||BYTE[SliceSize]||Slices||The graphics slices. Four blocks of SliceSize|
Like the 0FN type, the font is built more like a sprite file than like a real font, containing a set of frames in an order that doesn't match any real text encoding. The order of the symbols is the following:
- 00-25: Upper case characters A-Z.
- 26-35: Numbers 0-9.
- 36: Dollar sign.
This contains the bonus level font and sprites. It is not a font file per se but a graphics file.
The following tools are able to work with files in this format.
|Name||Platform||View images in this format?||Convert/export to another file/format?||Import from another file/format?||Access hidden data?||Edit metadata?||Notes|
|Westwood Font Editor||Windows||Yes||Yes||Yes||N/A||N/A||Can handle both the compressed fonts and FONTS.000. Rearranges the symbols as necessary and generates the space entry as needed. Allows setting the line height in compressed fonts when saving.|
|Engie File Converter||Windows||Yes||Yes||Yes||N/A||N/A||Can handle both the compressed fonts and FONTS.000, as tileset. Allows setting the space width and line height in compressed fonts when saving.|