######################################################################### A New Font Format for GRUB ######################################################################### The PF2 Bitmap Font File Format ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ :Author: Colin D. Bennett :Date: 8 January 2009 .. contents:: Introduction ============ The goal of this format is to provide a bitmap font format that is simple to use, compact, and cleanly supports Unicode. Goals of the GRUB Font Format ----------------------------- * **Simple to read and use.** Since GRUB will only be reading the font files, we are more concerned with making the code to read the font simple than we are with writing the font. * **Compact storage.** The fonts will generally be stored in a small boot partition where GRUB is located, and this may be on a removable storage device such as a CD or USB flash drive where space is more limited than it is on most hard drives. * **Unicode.** GRUB should not have to deal with multiple character encodings. The font should always use Unicode character codes for simple internationalization. Why Another Font Format? ------------------------ There are many existing bitmap font formats that GRUB could use. However, there are aspects of these formats that may make them less than suitable for use in GRUB at this time: =========== ================================================================== Font format Reason format is suboptimal for GRUB =========== ================================================================== BDF Inefficient storage; uses ASCII to describe properties and hexadecimal numbers in ASCII for the bitmap rows. PCF Many format variations such as byte order and bitmap padding (rows padded to byte, word, etc.) would result in more complex code to handle the font format. =========== ================================================================== File Structure ============== A file *section* consists of a 4-byte name, a 32-bit big-endian length (not including the name or length), and then *length* more section-type-specific bytes. The standard file extension for PFF2 font files is ``.pf2``. Section Types ------------- FILE *File type ID* (ASCII string). This must be the first section in the file. It has length 4 and the contents are the four bytes of the ASCII string ``PFF2``. NAME *Font name* (ASCII string). This is the full font name including family, weight, style, and point size. For instance, "Helvetica Bold Italic 14". FAMI *Font family name* (ASCII string). For instance, "Helvetica". This should be included so that intelligent font substitution can take place. WEIG *Font weight* (ASCII string). Valid values are ``bold`` and ``normal``. This should be included so that intelligent font substitution can take place. SLAN *Font slant* (ASCII string). Valid values are ``italic`` and ``normal``. This should be included so that intelligent font substitution can take place. PTSZ *Font point size* (uint16be). MAXW *Maximum character width in pixels* (uint16be). MAXH *Maximum character height in pixels* (uint16be). ASCE *Ascent in pixels* (uint16be). See `Font Metrics`_ for details. DESC *Descent in pixels* (uint16be). See `Font Metrics`_ for details. CHIX *Character index.* The character index begins with a 32-bit big-endian unsigned integer indicating the total size of the section, not including this size value. For each character, there is an instance of the following entry structure: #. **Unicode code point.** (32-bit big-endian integer.) #. **Storage flags.** (byte.) - Bits 2..0: - If equal to 000 binary, then the character data is stored uncompressed beginning at the offset indicated by the character's *offset* value. - If equal to 001 binary, then the character data is stored within a compressed character definition block that begins at the offset within the file indicated by the character's *offset* value. #. **Offset.** (32-bit big-endian integer.) DATA A marker that indicates the remainder of the file is data accessed via the character index (CHIX) section. When reading this font file, the rest of the file can be ignored when scanning the sections. The length should be set to -1 (0xFFFFFFFF). Supported data structures: Character definition Each character definition consists of: #. **Width.** Width of the bitmap in pixels. The bitmap's extents represent the glyph's bounding box. *uint16be*. #. **Height.** Height of the bitmap in pixels. The bitmap's extents represent the glyph's bounding box. *uint16be*. #. **X offset.** The number of pixels to shift the bitmap by horizontally before drawing the character. *int16be*. #. **Y offset.** The number of pixels to shift the bitmap by vertically before drawing the character. *int16be*. #. **Device width.** The number of pixels to advance horizontally from this character's origin to the origin of the next character. *int16be*. #. **Bitmap data.** This is encoded as a string of bits. It is organized as a row-major, top-down, left-to-right bitmap. The most significant bit of each byte is taken to be the leftmost or uppermost bit in the byte. For the sake of compact storage, rows are not padded to byte boundaries (i.e., a single byte may contain bits belonging to multiple rows). The last byte of the bitmap *is* padded with zero bits in the bits positions to the right of the last used bit if the bitmap data does not fill the last byte. The length of the *bitmap data* field is (*width* * *height* + 7) / 8 using integer arithmetic, which is equivalent to ceil(*width* * *height* / 8) using real number arithmetic. It remains to be determined whether bitmap fonts usually make all glyph bitmaps the same height, or if smaller glyphs are stored with bitmaps having a lesser height. In the latter case, the baseline would have to be used to calculate the location the bitmap should be anchored at on screen. Compressed character definition block **(Not yet implemented.)** This contains a set of character definitions which are compressed as a single block within the file. *Compressed character definitions will be implemented at a later date.* **[TODO: Implement compression/decompression using LZMA.]** Font Metrics ============ Ascent. The distance from the baseline to the top of most characters. Note that in some cases characters may extend above the ascent. Descent. The distance from the baseline to the bottom of most characters. Note that in some cases characters may extend below the descent. Leading. The amount of space, in pixels, to leave between the descent of one line of text and the ascent of the next line. This metrics is not specified in the current file format; instead, the font rendering engine calculates a reasonable leading value based on the other font metrics. Horizonal leading. The amount of space, in pixels, to leave horizontally between the left and right edges of two adjacent glyphs. The *device width* field determines the effective leading value that is used to render the font. .. figure:: font_char_metrics.png :alt: Illustration of font metrics on characters. An illustration of how the various font metrics apply to characters. Converting Fonts to PFF2 Format =============================== **Note: A new font converter, grub-mkfont (which is written in C instead of Java), has recently been created. It will take the place of the Java font converter in the near future.** The GRUB font tool is composed of font viewer and font converter programs. It is a Java program and can be built from source using the Ant tool:: $ cd util/fonttool util/fonttool $ ant jar Buildfile: build.xml compile: [mkdir] Created dir: /home/cdb/grub/util/fonttool/build/src [javac] Compiling 15 source files to /home/cdb/grub/util/fonttool/build/src jar: [jar] Building jar: /home/cdb/grub/util/fonttool/build/fonttool.jar BUILD SUCCESSFUL Total time: 2 seconds This results in a JAR file in the ``util/fonttool/build`` directory that contains the compiled class files. To run the font viewer, which can view either PFF2 or BDF fonts:: util/fonttool $ java -cp build/fonttool.jar org.gnu.grub.fonttool.Viewer myfile.bdf To convert a BDF font into PFF2 format, run:: util/fonttool $ java -cp build/fonttool.jar org.gnu.grub.fonttool.Converter --in=font.bdf --out=font.pf2 There is also a script called ``makepf2.sh`` in the ``util/fonttool`` directory as well which allows easy batch conversion of many BDF fonts to PFF2 format at once. .. vim: set filetype=rst sw=3 ts=3 et: