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 <fcntl.h>
#include <stdio.h>
#include <sys/qnxterm.h>
#include <unistd.h>
#include <photon/PhInternal.h>
#include <photon/Pf.h>
#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