Raster Font File Format

Top  Previous  Next

This topic details font file format used by the LCD object. The font file is a resource file that is added to your Tibbo BASIC/C project. Like all other resource files "attached" to your project, font files are accessible through the romfile object. Use and interpretation of font file data, however, is the responsibility of the  lcd.object. The Romfile object merely stores these files.

Tibbo font files have "TRF" (Tibbo Raster Font) extension. TRF file format was designed with the following considerations in mind:

 

Ability to handle large character sets (such as those required for Chinese language support). Hence, the use of 16-bit character codes.
16-bit character sets usually have large "gaps" (i.e. areas of unused codes). The TRF format offers an efficient way to define which characters are included into the font file and allows to conduct very efficient character search within the file.
Support for proportional fonts. Hence, each character's width is individually defined.
Support for fonts with anti-aliasing. Anti-aliasing is achieved by adjusting the "intensity" (brightness) of individual pixels. In an anti-aliased font, each pixel of character bitmap is represented by 2 or more bits of data. Fonts without anti-aliasing just need 1 data bit/pixel because each pixel can only be ON or OFF. At the time of writing, TiOS supported only fonts with 1 bit/pixel.
Support for vertical and horizontal character bitmap encoding. Displays with lcd.bitsperpixel= 1, 2, or 4 pack 8, 4, or 2 pixels into a single byte of display memory. Problem is, some displays combine the pixels vertically (see drawing A below), and some — horizontally (drawing B). Text output on such displays is more efficient if character bitmaps of the TRF file use the same direction of packing.

 

lcd_bw_byte_grouping

TRF file format

The TRF file consists of four data areas:

 

Data area

Description

Header

Contains various information such as the total number of characters in this font, character height, etc. Also contains the number of code groups in the code groups table (see below).

Code groups table

Contains descriptors of "code groups". Each code group contains information about a range of codes that has no "gaps" (i.e. unused codes in the middle). The font file can have as many code groups as necessary.

Bitmap offset table

Contains addresses (offsets) of all character bitmaps in the TRF file. In combination with the code groups table provides a way to find the bitmap of any specific character.

Bitmaps

Contains all bitmaps of each character included into the font file. The width of each bitmap is defined individually and is stored together with the bitmap.

 

Header format

The header has a fixed length of 16 bytes and stores the following information:

 

Offset*

Bytes

Data

Comment

+0

2

Num_of_chars

Total number of characters in this font file

+2

1

Pixels_per_byte

0- eight pixels/byte (1 bit/pixel, no anti-aliasing); 1- four pixels/byte, 2- two pixels/byte, 3- one pixel/byte. Modes 1, 2, and 3 are currently not supported; these modes are for anti-aliasing and will be supported in the future.

+3

1

Orientation

0- pixels are grouped vertically; 1- pixels are grouped horizontally (irrelevant when pixels_per_byte=3)

+4

1

Height

Maximum character height in this font, in pixels.

+5

9

<Reserved>

Reserved for future use

+14

2

Num_of_groups

Number of entries in the code groups table

*With respect to the beginning of the file

 

Code groups table

This table has variable number of entries. This number is stored in the num_of_groups field of the header. Each code group represents a range of codes that contains no gaps (no unused character codes in the middle). For example, supposing that we have a font that only contains characters '0'-'9' and 'A'-'Z'. This means that this font file will contain two groups of codes: 0030H through 0039H ('0'-'9') and 0041H through 005AH ('A'-'Z').

Each entry in the code groups table is 8 bytes long and has the following format:

Offset*

Bytes

Data

Comment

+0

2

Start_code

The first code in the group

+2

2

Num_codes

Number of individual character codes in this group

+4

4

Bitmap_addr_offset

Address (that falls within the bitmap offset table and is given with respect to the beginning of the file) at which the address of the bitmap of the first character in the code group is stored.

* With respect to the beginning of a particular table entry

 

For the above example the code groups table will have two entries:

 

Start_code

Num_codes

Bitmap_offset

0030H

000AH

00000020H

0041H

001AH

00000048H

 

Here is how the above data was calculated. Start codes are obvious. Group one starts with code 0030H because this is the character code of '0'. The second group starts with the character code of 'A'. It is also easy to fill out the number of codes in each group: 10 (000AH) for '0'-'9' and 26 (001AH) for 'A'-'Z'. Bitmap_addr_offset calculation is explained in the next section.

Bitmap offset table

This table has the same number of entries as the total number of characters included in the font file. Each entry consists of one field — a 32-bit offset of a particular bitmap with respect to the beginning of the font file. Now you can see how we were able to calculate the data for the bitmap_addr_offset field of the code groups table. The header of the font file has a fixed length of 16 bytes. There are two code groups in our example, so the code groups table occupies 8x2=16 bytes. This means that the bitmap offset table starts from address 16+16=32 (0020H). Hence, the first entry in the code groups table points at address 0020H. The first code group contains 10 characters ('0'-'9'). These will "occupy" 10 entries in the bitmap offset table, which results in 10x4=40 bytes. Hence, the bitmap_addr_offset field for the second code group is set to 32+40=72 (0048H).

Bitmaps

Each bitmap starts with a single byte that encodes the width of the bitmap in pixels, followed by the necessary number of bytes representing this bitmap. Depending on the pixels_per_byte field of the header, each byte of data may encode just one or several pixels. Additionally, when using more than 1 pixel-per-byte encoding, the orientation field of the header defines whether pixels are combined horizontally or vertically.

The drawings below illustrate how character bitmaps are stored in the font file. As an example, characters of 10x14 size (in pixels) are used. Drawing A is for one pixel/byte encoding, drawing B — for 8 pixels/byte with vertical orientation, C — for 8 pixels/byte with horizontal orientation. Notice that for cases B and C a portion of some bytes used to store the bitmaps is unused. Offsets of bytes relative to the beginning of the bitmap data are shown with a '+' sign.

Bitmap A takes 140 bytes. The first byte (+0) represents the pixel at the top left corner of the bitmap. Subsequent bytes represent all other pixels and the order is "left-to-right, top-to-bottom".

Bitmap B takes 20 bytes. The first byte encodes 8 vertically arranged pixels at the top left corner of the bitmap. Subsequent bytes represent all other pixel groups and the order is "left-to-right, top-to-bottom". There are 2 rows of bytes, and bits 6 and 7 of each byte in the second row are unused.

Bitmap C takes 28 bytes. The first byte encodes 8 horizontally arranged pixels at the top left corner of the bitmap. Subsequent bytes represent all other pixel groups and the order is "top-to-bottom, left-to-right". There are 2 columns of bytes, and bits 2-7 of each byte in the second column are unused.

 

lcd_char_bitmaps

 

Searching for a character bitmap

Here is how a target character bitmap is found within the font file. Again, we are using the example of the font file that contains characters '0'-'9' and 'A'-'Z'.

Supposing, we need to find the bitmap of character 'C' (code 0043H).

First, we need to see which code group code 004AH belongs to. We read the num_of_groups field of the header to find out how many code groups are contained in the font file. The field tells us that there are two groups.

Next, we start reading the code groups table (located at file offset +00000010H), entry by entry, in order to determine which code group the target character belong to. The first group starts from code 0030H and contains 10 character. Therefore, target character doesn't belong to it. The second group starts from code 0041H and contains 26 characters. The target code is 0043H. Therefore, target character belongs to this second group.

Next, we find the corresponding entry in the bitmap offset table. For this, we do a simple calculation:

 

bitmap_offset + (desired_code - start_code)*4: 00000048H + (0043H-0041H)*4= 00000050H.

 

Next, we read a 32-bit value at file offset 00000050H. This will tell us the file offset at which the target bitmap is stored.

At this file offset, the first byte will be the width of the bitmap in pixels. Based on this width and also height, pixels_per_byte and orientation fields of the header we can calculate the number of bytes in the bitmap. For example, supposing that height = 14, pixels_per_byte = 0 (8 pixels/byte), and orientation = 0 (pixels are grouped vertically). Also, let's suppose that the width of the target character is 10 pixels. In this case the bitmap will occupy 20 bytes, as shown on the drawing B above. Two bits of each byte in the second byte row will be unused.