1.0 An Overview of the Photon Font (PHF) File ----------------------------------------- The Photon Font File (which we will refer to as a PHF from this point on), is generated from universally available .bdf files. The utility used to create the PHF is called bdf_2_phf, and ships standard with Photon. There are four distinct components to a PHF. They are as follows: 1. The header component 2. The bitmap component. 3. The metric component 4. The index component The PHF format is also structured in the order listed above. A visual representation is below: --------------------------------- Offset 0 | | | Header Component | | | --------------------------------- | | | Bitmap Component | | | --------------------------------- | | | Metric Component | | | --------------------------------- | | | Index Component | | | --------------------------------- Offset N Each component, with respect to character order, runs from the smallest Unicode value to the largest. For example, if the PHF contains the Unicode range 0x0020 0x00FF, the first element in the Bitmap, Metric, and Index component will correspond to 0x0020, and the second element in each component to 0x0021, and so on. 1.1 THE HEADER COMPONENT -------------------- The header structure contains information relevant to the entire font, and is defined as follows: typedef struct { short Status; /* For a file, MUST be set to 'QW' */ unsigned short Flags; _PointStruct Size; _PointStruct Extent; unsigned short Spare1; unsigned short ImageOffset; unsigned short BPChar; unsigned short WidthTabOffset; unsigned short Spare2[4]; short UnderLinePos; short BaseLinePos; unsigned short AsciiOffset; unsigned short AsciiLength; char Description; } _FontStruct; A _PointStruct is defined as follows: typedef struct { short x, y; } _PointStruct; 1.2 THE INDEX COMPONENT ------------------- Bitmaps for each glyph can be of varying sizes. An offset into the PHF is required in order to locate the desired bitmap. The _FONT_IndexPerChar bit will be high in all currently published PHFs. if(Header.Flags & _FONT_IndexPerChar) { Header.AsciiLength * sizeof(short); } Flags are as follows: #define _FONT_IndexPerChar 0x0100 1.3 THE METRIC COMPONENT -------------------- Depending on the type of PHF (there are currently two), the metric component will be different. The definitions are below. if(Header.Flags & _FONT_WidthPerChar) { Header.AsciiLength * sizeof(short) } else if(Heaader.Flags & _FONT_MetricPerChar) { Header.AsciiLength * sizeof(_FontMetricStruct) } else return(FALSE); A _FontMetricStruct is defined as: typedef struct { _PointStruct Size; /* Bytes per line == (Size.x+7)>>3 */ signed char BaseLinePos; signed char LeftBearing; short Width; } _FontMetricStruct; Flags are as follows: #define _FONT_WidthPerChar 0x0200 #define _FONT_MetricPerChar 0x0400 /* Metrics and Width are exclusive */ 1.4 THE BITMAP COMPONENT -------------------- This component consists of a byte array. Each glyph bitmap is access by seeking to the offset specified in the Index Component, then reading/writing the bitmap. 1.5 EXAMPLE ------- What follows is a simple terminal based program that allows text based editing of a PHF. Also appended, are necessary header files. /* edit.c */ #include#include #include #include #include #include #include "__g_fontfile.h" #define INDENT 2 _FontStruct hdr; short * width = NULL, * ix = NULL; _FontMetricStruct * metric = NULL; char bitmap[1024]; int fd = -1, posx = 0, posy = 0, szx = 0, szy = 0, bitmaplen = 0, bitmapbpl = 0; int FindDef(int from, int dir) { int i = 0; if(dir == 1) { for (i = (from != -1) ? from + 1 : 0; i < hdr.AsciiLength; ++i) if(hdr.Flags & _FONT_WidthPerChar && width[i] != 0) return(i); else if(hdr.Flags & _FONT_MetricPerChar && metric[i].Width != 0) return(i); else return(i); return(from); } else if (dir == -1) { for(i = (from != -1) ? from - 1 : hdr.AsciiLength - 1; i >= 0; --i) if(hdr.Flags & _FONT_WidthPerChar && width[i] != 0) return(i); else if(hdr.Flags & _FONT_MetricPerChar && metric[i].Width != 0) return(i); else return(i); return(from); } return(-1); } void DrawImage(int ch) { int i = 0, x = 0, y = 0; if(hdr.Flags & _FONT_WidthPerChar) { szx = width[ch], szy = hdr.Size.y; } else if(hdr.Flags & _FONT_MetricPerChar) { szx = metric[ch].Size.x, szy = metric[ch].Size.y; } else { /* should never happen at this point */ } lseek(fd, ix[ch], SEEK_SET); read(fd, bitmap, bitmaplen = (bitmapbpl = ((szx + 7) >> 3)) * szy); term_clear(TERM_CLS_SCR); term_printf(0, 0, TERM_HILIGHT, "U+%04X", hdr.AsciiOffset + ch); for(y = 0; y < szy; ++y) for(x = 0; x < bitmapbpl; ++x) for(i = 0; i < 8; ++i) term_printf(INDENT + y, INDENT + x * 8 + i, TERM_NORMAL, (bitmap[y * bitmapbpl + x] & (0x80 >> i)) ? "*" : " "); term_printf(INDENT + szy + 1, 0, TERM_HILIGHT, "BROWSE?"); term_clear(TERM_CLS_EOL); term_flush(); } void SaveImage(int ch) { lseek(fd, ix[ch], SEEK_SET); write(fd, bitmap, bitmaplen); } void main(int argc, char *argv[]) { int ch = 0, bit = 0, quit = 0, edit = 0, dirty = 0; unsigned char byte; if((fd = open(argv[1], O_RDWR)) == -1) return; read(fd, &hdr, sizeof(_FontStruct)); if(hdr.Flags & _FONT_IndexPerChar) { if((ix = malloc(hdr.AsciiLength * sizeof(short))) == NULL) return; lseek(fd, hdr.ImageOffset, SEEK_SET); read(fd, ix, hdr.AsciiLength * sizeof(short)); } if(hdr.Flags & _FONT_WidthPerChar) { if((width = malloc(hdr.AsciiLength * sizeof(short))) == NULL) return; lseek(fd, hdr.WidthTabOffset, SEEK_SET); read(fd, width, hdr.AsciiLength * sizeof(short)); } else if(hdr.Flags & _FONT_MetricPerChar) { if((metric = malloc(hdr.AsciiLength * sizeof(_FontMetricStruct))) == NULL) return; lseek(fd, hdr.WidthTabOffset, SEEK_SET); read(fd, metric, hdr.AsciiLength * sizeof(_FontMetricStruct)); } else { return; } term_load(); term_clear(TERM_CLS_SCR); ch = FindDef(-1, 1); DrawImage(ch); quit = edit = 0; while(!quit) switch(term_key()) { case K_LEFT: if(edit) { if(posx > 0) --posx; term_cur(INDENT + posy, INDENT + posx); } else { ch = FindDef(ch, -1); DrawImage(ch); } break; case K_RIGHT: if(edit) { if(posx < szx - 1) ++posx; term_cur(INDENT + posy, INDENT + posx); } else { ch = FindDef(ch, 1); DrawImage(ch); } break; case K_UP: if(edit) { if(posy > 0) --posy; term_cur(INDENT + posy, INDENT + posx); } else { ch = FindDef(ch, -1); DrawImage(ch); } break; case K_DOWN: if(edit) { if(posy < szy - 1) ++posy; term_cur(INDENT + posy, INDENT + posx); } else { ch = FindDef(ch, 1); DrawImage(ch); } break; case K_ENTER: if(edit = !edit) { dirty = 0; posx = posy = 0; term_printf(INDENT + szy + 1, 0, TERM_HILIGHT, "EDIT?"); term_clear(TERM_CLS_EOL); term_cur(INDENT + posy, INDENT + posx); } else { if(dirty) SaveImage(ch); term_printf(INDENT + szy + 1, 0, TERM_HILIGHT, "BROWSE?"); term_clear(TERM_CLS_EOL); } break; case ' ': if(edit) { bit = posx & 0x7; byte = bitmap[posy * bitmapbpl + (posx >> 3)] ^= (0x80 >> bit); term_printf(INDENT + posy, INDENT + posx, TERM_NORMAL, (byte & (0x80 >> bit)) ? "*" : " "); term_cur(INDENT + posy, INDENT + posx); ++dirty; } break; case '0': if(edit) { bit = posx & 0x7; byte = bitmap[posy * bitmapbpl + (posx >> 3)] &= ~(0x80 >> bit); term_printf(INDENT + posy, INDENT + posx, TERM_NORMAL, (byte & (0x80 >> bit)) ? "*" : " "); term_cur(INDENT + posy, INDENT + posx); ++dirty; } break; case '1': if(edit) { bit = posx & 0x7; byte = bitmap[posy * bitmapbpl + (posx >> 3)] |= (0x80 >> bit); term_printf(INDENT + posy, INDENT + posx, TERM_NORMAL, (byte & (0x80 >> bit)) ? "*" : " "); term_cur(INDENT + posy, INDENT + posx); ++dirty; } break; case K_ESC: case 'q': case 'Q': if(edit) { edit = 0; DrawImage(ch); } else { ++quit; } break; } term_restore(); close(fd); } /* __g_fontfile.h */ /* _GR_FontStruct.Flags definitions */ #define _FONT_TypeMask 0x000F /* Mask for font type */ #define _FONT_Bitmapped 0x0000 /* Font type: Bitmapped */ #define _FONT_IndexPerChar 0x0100 #define _FONT_WidthPerChar 0x0200 #define _FONT_MetricPerChar 0x0400 /* Metrics and Width are exclusive */ #define _FS_Italic 0x0001 #define _FS_Oblique 0x0002 #define _FS_RevItalic 0x0004 #define _FS_Bold 0x0010 typedef struct { short x, y; } _PointStruct; typedef struct { _PointStruct Size; /* Bytes per line == (Size.x+7)>>3 */ signed char BaseLinePos; signed char LeftBearing; short Width; } _FontMetricStruct; typedef struct { short Status; /* For a file, MUST be set to 'QW' */ unsigned short Flags; _PointStruct Size; _PointStruct Extent; unsigned short Spare1; unsigned short ImageOffset; unsigned short BPChar; unsigned short WidthTabOffset; unsigned short Spare2[4]; short UnderLinePos; short BaseLinePos; unsigned short AsciiOffset; unsigned short AsciiLength; char Description; } _FontStruct; 1.5 CAVEATS ABOUT A PHF ------------------- bdf_2_phf ships with Photon. You will want UNICODE BDF files (a MUST). Try www.unicode.org as a starting point. One caveat, PHFs cannot be larger than 64k per file. Here is a script used to create a font, where size had to be manipulated. The -S (start) and -N (amount) switches were modified to get each file <= 64k. If you encounter a font that requires it to be split up, you will have to put it in your extension list (fontcfg). Non-asain BDF files usually do not need to be split up ... MAKEFONTS SCRIPT: #!/bin/sh # Usage: makefonts bdf_filename # # If you change the size, you'll probably have to modify # the ranges to keep the files below 64k apiece. SIZE=16 BDF_FILE=something_big.bdf CMD_BDF2PHF=/usr/photon/bin/bdf_2_phf $CMD_BDF2PHF -S0x20 -N0x1Fe0 -Ouk00-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x2000 -N0xC00 -Ouk20-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x3000 -N0x1000 -Ouk30-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x4000 -N0x1600 -Ouk40-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x5600 -N0x400 -Ouk56-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x5a00 -N0x400 -Ouk5A-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x5e00 -N0x500 -Ouk5E-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x6300 -N0x500 -Ouk63-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x6800 -N0x700 -Ouk68-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x6F00 -N0x500 -Ouk6F-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x7400 -N0x500 -Ouk74-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x7900 -N0x500 -Ouk79-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x7E00 -N0x500 -Ouk7E-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x8300 -N0x500 -Ouk83-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x8800 -N0x600 -Ouk88-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x8E00 -N0x600 -Ouk8E-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x9400 -N0x500 -Ouk94-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0x9900 -N0xA00 -Ouk99-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xa300 -N0xA00 -OukA3-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xad00 -N0x500 -OukAD-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xb200 -N0x500 -OukB2-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xb700 -N0x500 -OukB7-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xbc00 -N0x500 -OukBC-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xc100 -N0x500 -OukC1-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xc600 -N0x500 -OukC6-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xd000 -N0x500 -OukD0-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xd500 -N0x1b00 -OukD5-$SIZE.phf $BDF_FILE $CMD_BDF2PHF -S0xF000 -N0xFE6 -OukF0-$SIZE.phf $BDF_FILE