Search (using Google):  Web Karig

 

12 March 2004

Making a font

I'd like to be able to work in a VBE mode immediately and not have to rewrite text-mode code later. VBE mode doesn't come with its own system font, so I decided to draw one using the Paint program that came with Windows and then convert the bitmap file into a format I can use more easily.

This is my font. It's very rough, it contains characters that I might or might not keep, and I'll change it before I'm through, but it'll do for now.

(Picture showing all 256 characters [though a lot of them are still blank])

The font will define each character in sixteen bytes — one bit per pixel, eight pixels in a scanline (each character is eight pixels wide), and sixteen scanlines (each character is sixteen pixels high). A font that defines 256 characters will take up 4096 bytes. To get to a specific "glyph" (the sixteen bytes that define a specific character), you multiply that character's ASCII value by sixteen and add that to the address where the font begins.

I wanted the font to be big enough to allow me to squeeze in a decent amount of detail, or a decent amount of whitespace around characters, or both — but I also wanted the font to be small enough that it wouldn't cause the data cache on the processor to be flushed too often. (I'm assuming a data cache size of 4KB.) Probably 90% of the text to be printed on the screen will be lowercase letters, so 90% of the time, the font data is being pulled from a section of the font only 416 (16*26) bytes long.

I also wanted to ensure that the font was readable on my Soyo's tiny screen, so I made it bold and square. I may experiment with a lighter, rounder font later.

Creating the font

I drew the font using Microsoft Paint. I created a black-and-white picture 2048 pixels long by 16 pixels deep. I then drew each character in its proper location — e.g., the proper location for 'A' (character 65) was 520 (8*65) pixels from the left side of the picture. When I finished, I saved the picture as a bitmap (*.BMP) file named "font.bmp". Then I wrote a very quick and dirty C utility to convert the bitmap file into a binary file (named "font.bin") containing the font laid out in the format I want my code to use.

My utility makes the following assumptions:

  • The bitmap to rearrange is named "font.bmp".
  • The file "font.bin" is OK to overwrite.
  • The bitmap is monochrome (meaning that it contains only black and white pixels).
  • The bitmap file has a header exactly 62 bytes long. (It will if you saved it from within Paint as a monochrome file.)
  • The pixel data is arranged into exactly 16 scanlines.
  • Each scanline is 256 bytes (2048 pixels) long.
  • Scanlines are arranged within the bitmap file in reverse order, i.e., the bottommost scanline is listed first in the file.
  • Each byte of pixel data represents a full (eight-pixel-wide) pixel row of a specific single character.
  • The pixels are stored without compression.
  • Characters are drawn in order, with character #0 occupying the leftmost eight columns of pixels, character #1 occupying the next eight columns, etc.

I spent maybe five minutes throwing this together. There is no error checking, so I don't recommend this for general use.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
	/* Open font.bmp for binary read, output font.bin */
	/* Bitmap must be monochrome */
	char* buffer;

	FILE* font = fopen("font.bmp","rb");
	FILE* bin = fopen("font.bin","wb");
	buffer = malloc(4096);
	fread(buffer, 1, 62, font);
	fread(buffer, 1, 4096, font);
	fclose(font);
	for(int i = 0; i < 256; ++i) {
		for(int j = 15; j >= 0; --j) {
			fwrite(buffer+(j*256)+i, 1, 1, bin);
		}
	}
	fclose(bin);
	free(buffer);
	return 0;
}

The format of "font.bin" is simple: The pixel data for each character occupies sixteen contiguous bytes, with the first byte containing the top pixel row, the second containing the row below that, and so on. The data for character #0 begins at offset 0*16; the data for character #1 begins at offset 1*16; etc. So to offset to the data for a specific character, multiply that character's ASCII value by 16 and grab the 16 bytes found there.

Later I'll write a boot sector that loads this font into memory and uses it to print characters to the graphics screen.

Check the index for other entries.