0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
The format
Example #1: Inside BMF
Example #2: tablo attributes
For this example, let addSpace
= 1, sizeOver
= –8.
The initial [x, y] of the layout is not the top-left corner of
the first char's bitmap, it lies on the baseline. It should be the layout
routine to add (usually negative) font's sizeOver to the y-coordinate.
In the picture, the blue line is the base line, the blue cursor is the initial
position to plot the text, the red cursor, being sizeOver
pixels
down from the base line, indicate cursor position before outputing each
character of the text. Finally, to get to the actual top-left corners of
each bitmap, we need to add the (relX, relY)
vector from each
character's tablo.
| F | j | : | Q |
width | 4 | 4 | 1 | 8 |
height | 8 | 9 | 4 | 9 |
relX | 0 | –2 | 1 | 0 |
relY | 0 | 2 | 2 | 0 |
shift | 4 | 2 | 3 | 8 |
Working with the format
Pseudocode for loading a font
filename = "font.bmf";
file = fopen(filename, "rb");
buffer = fread(file, 17);
version = buffer[4];
if (substr(buffer, 0, 4) != "\xE1\xE6\xD5\x1A" || (version != 0x11 && version != 0x12)) {
exit('Not a BMF, version 1.1 or 1.2');
}
lineHeight = buffer[5];
sizeOver = buffer[6];
sizeUnder = buffer[7];
addSpace = buffer[8];
sizeInner = buffer[9];
usedColors = buffer[10];
highestColor = buffer[11];
alphaBits = buffer[12];
extraPalettes = buffer[13];
reserved = buffer[14];
numColors = buffer[16];
palette = fread(file, numColors * 3);
for (i = 1; i <= numColors * 3; i++) {
palette[i] *= 4; // stretch 0..63 values to 0..255
}
titleLength = fread(file, 1);
title = fread(file, titleLength);
asciiChars = fread(file, 2);
for (i = 0; i < asciiChars; i++) {
whichChar = fread(file, 1);
tablo[whichChar] = fread(file, 5);
if (bitmapSize = tablo[whichChar][0] * tablo[whichChar][1]) {
tablo[whichChar][5] = fread(file, bitmapSize);
}
}
if (version >= 0x12) { // next goes for version 1.2+ only
unicodeChars = fread(file, 4);
for (i = 0; i < unicodeChars; i++) {
whichChar = fread(file, 4);
tablo[whichChar] = fread(file, 5);
if (bitmapSize = tablo[whichChar][0] * tablo[whichChar][1]) {
tablo[whichChar][5] = fread(file, bitmapSize);
}
}
numKerningPairs = fread(file, 4);
kerningPairs = [];
for (i = 0; i < numKerningPairs; i++) {
fread(file, kerningPair, 10);
kerningPairs []= kerningPair;
}
}
fclose(file);
Pseudocode for layout/output
text = "EXAMPLE ABC";
originalX = cursorX = 30;
cursorY = 20;
lineBreaksEnabled = true;
for (index = 0; index < strlen(text); index++) { // for each character..
whichChar = ord(text[index]);
if (lineBreaksEnabled && (whichChar == 13)) { // line break
cursorY += font.lineHeight;
cursorX = originalX;
continue;
}
charWidth = font.tablo[whichChar][0];
charHeight = font.tablo[whichChar][1];
charRelX = font.tablo[whichChar][2];
charRelY = font.tablo[whichChar][3];
charShift = font.tablo[whichChar][4];
charBitmap = font.tablo[whichChar][5];
for (bitmapY = 0; bitmapY < charHeight; bitmapY++) { // for each bitmap row..
for (bitmapX = 0; bitmapX < charWidth; bitmapX++) { // for each bitmap column..
colorAttribute = charBitmap[bitmapY * charWidth + bitmapX];
if (colorAttribute) { // leave color attribute 0 as transparent
setPixel(
cursorX + charRelX + bitmapX, // x
cursorY + font.sizeOver + charRelY + bitmapY, // y
font.palette[colorAttribute]
);
}
}
}
cursorX += charShift + font.addSpace; // update cursor position
if (version >= 0x12 && index < strlen(text) - 1) {
cursorX += font.kerningPairs[whichChar, ord(text[index + 1])];
}
}