PC Screen Font (kurz: PSF) ist ein einfaches binäres Dateiformat für Bitmap-Zeichensätzen. Es wird vor allem vom Linux-Kernel für die Textkonsole benutzt, ist aber nicht auf diesen Einsatzzweck beschränkt.

Es gibt zwei zueinander inkompatible Formatversionen. Der logische Aufbau ist gleich, aber die Kodierung unterscheidet sich stark.[1]

Version 1

Bearbeiten

PSF Version 1 hatte seine Ursprünge in dem Dateiformat, das H. Peter Anvin 1989 in seinem Font-Editor für MS-DOS benutzt hatte. Seine Fähigkeiten sind begrenzt, entsprechend den Fähigkeiten der VGA-Grafikkarte im Textmodus:

In dieser Version können nur Zeichensätze mit 8 Pixel breiten Zeichen definiert werden. Es werden Zeichensätze mit 256 oder mit 512 Zeichen unterstützt.

Dateien in diesem Format beginnen mit einem 4 Byte großen Header:

PSF1 Header
Offset Größe Bedeutung
0 2 Magic Number 36hex, 04hex
2 1 Font Mode: Bitfeld, das die Eigenschaften des Zeichensatzes definiert, wenn das entsprechende Bit gesetzt ist:

Bit 0: Font enthält 512 Zeichen
Bit 1: Font hat Unicode-Codierungstabelle
Bit 2: Die Codierungstabelle enthält Zeichensequenzen

3 1 Höhe eines Zeichens (=Größe eines Zeichens in der PSF-Datei)

Version 2

Bearbeiten

Dieses Format kann beliebig große Zeichen speichern, auch die Anzahl der Zeichen im Font ist nun frei wählbar.

PSF2 Header
Offset Datentyp Bedeutung
0 uint8_t[4] Magic Number 72hex, B5hex, 4Ahex, 86hex
4 uint32_t Version. (bisher stets 0)
8 uint32_t Größe des Headers (in Byte)
12 uint32_t Flags (derzeit ist nur Bit 0 definiert, welches angibt, ob der Font eine Unicode-Tabelle enthält)
16 uint32_t Anzahl an Zeichen im Font
20 uint32_t Größe eines Zeichens (in Byte)
24 uint32_t Zeichenhöhe (in Pixel)
24 uint32_t Zeichenbreite (in Pixel)

Die 32-Bit-Werte sind im Little-Endian-Format gespeichert.

Zeichendaten

Bearbeiten

Nach dem Header folgen die eigentlichen Zeichendaten. In PSFv1 entspricht jedes Byte genau einer Zeile mit 8 Pixeln. In PSFv2 werden die Zeilen gegebenenfalls von rechts mit Nullbits aufgefüllt, um auf eine ganze Anzahl von Bytes pro Zeile zu kommen.

Beispiel PSFv1

Bearbeiten

Die bei vielen Linux-Distributionen mitgelieferte Font-Datei Uni1-Fixed16.psf beginnt (in Hexadezimaldarstellung) wie folgt:

Offset   | Datenbytes
—————————+——————————————————————————————————————————————————
00000000 | 36 04 03 10 00 00 00 00  3c 42 99 a5 a1 a1 a5 99
00000010 | 42 3c 00 00 00 00 00 00  3c 42 b9 a5 a5 b9 a9 a5
00000020 | 42 3c 00 00 0c 30 00 00  41 41 22 22 14 08 08 08
00000030 | 08 08 00 00 00 00 00 00  18 24 24 42 42 7e 42 42
…

Die ersten zwei Bytes 36 04 sind der PSF1-Header. Das Font Mode-Byte hat den Wert 03hex, das bedeutet: Der Font enthält eine Unicode-Zeichentabelle und Zeichensequenzen. Das darauf folgende Byte hat den Wert 10hex = 16dez und gibt die Höhe der Zeichen in Pixel und in Byte an.

Es folgen daraufhin jeweils 16 Byte pro Zeichen, die die Pixeldaten enthalten:

Zeile | Byte | Pixel
——————+——————+—————————————————
   1  |  00  | · · · · · · · ·
   2  |  00  | · · · · · · · ·
   3  |  00  | · · · · · · · ·
   4  |  00  | · · · · · · · ·
   5  |  3c  | · · █ █ █ █ · ·
   6  |  42  | · █ · · · · █ ·
   7  |  99  | █ · · █ █ · · █
   8  |  a5  | █ · █ · · █ · █
   9  |  a1  | █ · █ · · · · █
  10  |  a1  | █ · █ · · · · █
  11  |  a5  | █ · █ · · █ · █
  12  |  99  | █ · · █ █ · · █
  13  |  42  | · █ · · · · █ ·
  14  |  3c  | · · █ █ █ █ · ·
  15  |  00  | · · · · · · · ·
  16  |  00  | · · · · · · · ·

Der Font Lat7-TerminusBold22x11.psf enthält Zeichen der Größe 11 × 22 Pixel und liegt somit im Format PSFv2 vor:

Offset   | Datenbytes
—————————+——————————————————————————————————————————————————
00000000 | 72 b5 4a 86 00 00 00 00  20 00 00 00 01 00 00 00
00000010 | 00 01 00 00 2c 00 00 00  16 00 00 00 0b 00 00 00
00000020 | 00 00 00 00 00 00 00 00  00 00 c0 c0 61 80 3f 00
00000030 | 61 80 61 80 61 80 61 80  61 80 3f 00 61 80 c0 c0
00000040 | 00 00 00 00 00 00 00 00  00 00 00 00 00 00 00 00
00000050 | 00 00 0c 00 0c 00 0c 00  0c 00 0c 00 0c 00 00 00
…

Die ersten 4 Bytes 72 b5 4a 86 entsprechen dem PSFv2-Header. Die Kopfdaten sind:

  • Version: 0
  • Header-Größe: 32 Bytes (20hex)
  • Flags: 1 (=Font enthält Unicode-Tabelle)
  • Anzahl der Zeichen: 256 (0100hex)
  • Größe eines Zeichens: 44 Byte (2chex)
  • Höhe eines Zeichens: 22 Pixel (16hex)
  • Breite eines Zeichens: 11 Pixel (0bhex)

Anschließend folgen ab Offset 20hex die Pixeldaten, mit jeweils 2 Byte pro Zeile:

Zeile | Bytes | Pixel
——————+———————+————————————————+————————————————
   1  | 00 00 | · · · · · · · · · · · · · · · ·
   2  | 00 00 | · · · · · · · · · · · · · · · ·
   3  | 00 00 | · · · · · · · · · · · · · · · ·
   4  | 00 00 | · · · · · · · · · · · · · · · ·
   5  | 00 00 | · · · · · · · · · · · · · · · ·
   6  | C0 C0 | █ █ · · · · · · █ █ · · · · · ·
   7  | 61 80 | · █ █ · · · · █ █ · · · · · · ·
   8  | 3F 00 | · · █ █ █ █ █ █ · · · · · · · ·
   9  | 61 80 | · █ █ · · · · █ █ · · · · · · ·
  10  | 61 80 | · █ █ · · · · █ █ · · · · · · ·
  11  | 61 80 | · █ █ · · · · █ █ · · · · · · ·
  12  | 61 80 | · █ █ · · · · █ █ · · · · · · ·
  13  | 61 80 | · █ █ · · · · █ █ · · · · · · ·
  14  | 3F 00 | · · █ █ █ █ █ █ · · · · · · · ·
  15  | 61 80 | · █ █ · · · · █ █ · · · · · · ·
  16  | C0 C0 | █ █ · · · · · · █ █ · · · · · ·
  17  | 00 00 | · · · · · · · · · · · · · · · ·
  18  | 00 00 | · · · · · · · · · · · · · · · ·
  19  | 00 00 | · · · · · · · · · · · · · · · ·
  20  | 00 00 | · · · · · · · · · · · · · · · ·
  21  | 00 00 | · · · · · · · · · · · · · · · ·
  22  | 00 00 | · · · · · · · · · · · · · · · ·

Die Pixeldaten sind 44*256 = 11264 Bytes groß, belegen also in der Datei den Bereich von 0020hex bis 2c1fhex, ab Offset 2c20hex beginnen die Unicode-Daten:

Offset   | Datenbytes
—————————+——————————————————————————————————————————————————
…
00002c20 | c2 a4 ff c2 a6 ff c2 a8  ff c2 a9 ff e2 99 a6 e2
00002c30 | 97 88 ef bf bd ff c2 ae  ff c2 af cb 89 ff e2 80
…

Diese bestehen aus Sequenzen von UTF-8-kodierten Zeichen, getrennt durch ein Byte mit dem Wert FFhex, welches in UTF-8 nicht vorkommt. Der Erste Eintrag ist C2 A4, welches die UTF-8-Kodierung für U+00A4 ist, welches das allgemeine Währungszeichen ¤ ist.

Unicode-Zeichentabelle

Bearbeiten

Die Unicode-Zeichentabelle gibt für jedes Zeichen im Font an, für welches Unicode-Zeichen oder Zeichenfolge es stehen soll. Das gestattet es, dass identisch aussehende Unicode-Zeichen (z. B. das lateinische A, das kyrillische А und das griechische Alpha) nur einmal im Font kodiert werden müssen.

Außerdem können Zeichen im Font enthalten sein, die in Unicode keinen eigenen Code haben, sondern nur über eine Sequenz von Unicode-Zeichen dargestellt werden können.

Die Unicode-Werte werden im PSFv1-Format als 16-Bit-Werte kodiert, sodass nur Zeichen aus der Basic Multilingual Plane unterstützt werden. PSFv2 kodiert die Werte in UTF-8 und kann so auch Zeichen jenseits von U+FFFF enthalten.

Einzelnachweise

Bearbeiten
  1. https://www.win.tue.nl/~aeb/linux/kbd/font-formats-1.html