October 21, 2012
Nowadays the font files in FONTX2 format is often used in hobby electronics projects. This page describes about the background of FONTX and how to use the FONTX files for your projects.
In early '90s, "IBM DOS J4.0/V" called DOS/V was released. The DOS/V consists of PC DOS and additional device drivers to handle Japanese characters (Kanji). It could display Kanji on the display of IBM AT or compatibles without any add-on board. Right image shows the system diagram of DOS/V. The "V" added end of the product name denotes VGA and it means "IBM Japanese DOS version 4.0 for VGA".
The display driver ($DISP.SYS) extends the video BIOS (INT 10h) and it processes the character output request by application program. The character is drawn on the graphic screen instead of character screen, therefore it can display arbitrary fonts including Kanji. This enabled _a few_ English applications to handle Japanese without any modification. The reason of only a few applications is that the most of DOS applications bypass the video BIOS and write characters into the VRAM directly. The display driver also supports virtual VRAM to minimize cost of development and porting the applications, however, supporting the Japanese was not easy because of handling of double byte character that not exist in alphabet bloc.
The font driver ($FONT.SYS) manages the Kanji font. It loads the font files to the memory on start up and it works as a font server via system BIOS (INT 15h). The font data amounted to 200K bytes is placed on EMB memory, so that it does not consume conventional momory but the DOS/V requires 80286 or higher.
At that time, NEC PC-9800 series PCs that supports hardware Kanji character screen was occupying the business PC market in Japan. The new entry of DOS/V architecture into the mature architecture as Japanese business PC was a big topic. Some magazines related to DOS/V started to issue, and DOS/V drivers with new functions were released by hackers in succession.
As for the display drivers, it supported some type of display sub-systems in addition to the regular VGA. Most of them supported SVGA and the graphics accelerator for wide character screen with fast drawing. Some drivers supported CGA for pocket PCs. IBM also followed these implementations and released add-on drivers as "DOS/V EXTENSION" package. With it, the mean of "V" has been redefined from VGA to Variable. Also I was developping some display drivers as one of the DOS/V freaks :-)
As for the font drivers, there were some expansions, reload font and change it on the fly, selectable font buffer memory other than EMB, such as EMS memory, conventional memory and hardware specific bank memory, to enable support of XT based pocket PCs. The number of font drivers released was not many as display drivers. The FONTX was a set of font driver and font converter tools released first and gets the major font driver as freeware. As the result, all DOS/V font files that has been released as freeware are in FONTX format.
A few years later, the time went to Windows age and MS-DOS age with DOS/V archtecture has closed. The number of software resources and DOS/V fonts have been passed into oblivion. However, after middle of '00s, the use of 32-bit microcontrollers and graphic display modules have spread even to hobby electronics projects. With this trend, FONTX files came to be used to output Kanji characters into the graphic LCD module. The FONTX is a bitmap font format suitable for such use because the file format is opened and many free font files are found on the internet. Therfore the FONTX became to be noticed again. But in only electronics projects as a minor world.
The FONTX file is, unlike BDF file, in binary form shown below. There are two type of font file, single byte code font and double byte code font. The font type is identified by code flag. The single byte code font file has 256 font images. The double byte font uses valid code range table to store only some thousands of Shift_JIS code fonts out of 65536. The font image is stored in order of listed in the code range table.
Offset | Size | Description |
---|---|---|
0 | 6 | File signature("FONTX2") |
6 | 8 | Font name |
14 | 1 | Font width WF(dot) |
15 | 1 | Font height HF(dot) |
16 | 1 | Code flag (0:ANK) |
17 | *1 | Font image (*1:Font size * 256) |
Offset | Size | Description | |
---|---|---|---|
0 | 6 | File signature("FONTX2") | |
6 | 8 | Font name | |
14 | 1 | Font width WF (dots) | |
15 | 1 | Font height HF (dots) | |
16 | 1 | Code flag (1:Shift JIS) | |
17 | 1 | Number of code blocks NB | |
18 | 2 | Block 1 start | Code block table (little endian) |
20 | 2 | Block 1 end | |
… | … | … | |
14+4*NB | 2 | Block NB start | |
16+4*NB | 2 | Block NB end | |
18+4*NB | *2 | Font image (*2:Font size * total number of codes) |
The image shown below is the font image stored on the file. The font face is in left-justified if the font width is not equal to multiple of 8.
The font size becomes (WF + 7) / 8 * HF [bytes]. The offset where the top of font image data from top of the file are:
To edit the FONTX file, a font editor supports the FONTX format is required. However the FONTX editor for Windows had not been developped because the FONTX was already not needed in Windows age, so that I built a simple FONTX editor.
This is an example to get the font image in the FONTX file stored on the memory. The two arguments specifies pointer to the FONTX data and character code. If the code is not found in the font data, it returns a NULL.
const uint8_t* get_font ( /* Returns pointer to the font image (NULL:invalid code) */ const uint8_t* font, /* Pointer to the FONTX file on the memory */ uint16_t code /* Character code */ ) { unsigned int nc, bc, sb, eb; uint32_t fsz; const uint8_t *cblk; fsz = (font[14] + 7) / 8 * font[15]; /* Get font size */ if (font[16] == 0) { /* Single byte code font */ if (code < 0x100) return &font[17 + code * fsz]; } else { /* Double byte code font */ cblk = &font[18]; nc = 0; /* Code block table */ bc = font[17]; while (bc--) { sb = cblk[0] + cblk[1] * 0x100; /* Get range of the code block */ eb = cblk[2] + cblk[3] * 0x100; if (code >= sb && code <= eb) { /* Check if in the code block */ nc += code - sb; /* Number of codes from top of the block */ return &font[18 + 4 * font[17] + nc * fsz]; } nc += eb - sb + 1; /* Number of codes in the previous blocks */ cblk += 4; /* Next code block */ } } return 0; /* Invalid code */ }