Font System
Bitmap font rendering and generation in guideXOS
Overview
guideXOS uses a custom bitmap font system for rendering text throughout the operating system. Unlike TrueType or OpenType fonts, bitmap fonts store each character as a pre-rendered image in a PNG file, providing fast, predictable rendering without requiring complex font rasterization.
Key Features
- ? PNG-based storage - Characters stored as transparent images
- ? Grid layout - Fixed cell size for each character
- ? Variable width support - Automatic trimming of empty columns
- ? Alpha blending - Smooth edges via PNG transparency
- ? Multiple sizes - Each size requires a separate font file
- ? Easy generation - Python script to create fonts from system fonts
Font File Structure
guideXOS fonts are stored as PNG images with a specific grid-based layout:
Grid Specifications
| Property | Value | Description |
|---|---|---|
| Cell Size | FontSize × FontSize | Each character occupies a square cell |
| Grid Layout | Left-to-right, top-to-bottom | Characters arranged in rows |
| Characters Per Row | 13 (default) | Configurable in generation script |
| Image Format | PNG with alpha channel | RGBA format required |
| Background | Transparent (alpha = 0) | Non-transparent pixels are rendered |
Example: 18px Font Grid
Font Size: 18px
Cell Size: 18px × 18px
Chars Per Row: 13
Total Characters: 95 (space through ~)
Image Dimensions: 234px × 144px (13 cols × 8 rows)
Rows Needed: ?95 / 13? = 8 rows
Roboto 12pt Font (20px Grid)
The default system font used by WindowManager is Roboto 12pt with these specifications:
| Property | Value |
|---|---|
| File Name | roboto_12pt_regular.png |
| Grid Cell Size | 20px × 20px |
| Font Size | 20px |
| Fixed Width Mode | Enabled |
| Character Width | 15px (fixed) |
| Padding | -5px |
| Location | Ramdisk/Fonts/roboto/ |
The 20px grid provides optimal spacing for the Roboto font at 12pt size, ensuring characters have adequate padding and maintain readability at typical screen resolutions. The fixed width of 15px creates a pleasant monospace-like appearance for UI elements.
Character Set (Charset)
The charset string defines the order of characters in the font image. This string MUST match exactly between the font generation script and all C# code that uses the font.
Standard Charset
!"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~
Character breakdown:
- Position 0: Space character (U+0020) - CRITICAL: Must be first!
- Positions 1-94: Printable ASCII characters (! through ~)
- Total: 95 characters
- Range: ASCII 32 (space) through ASCII 126 (~)
The charset MUST start with a space character. If you omit the leading space,
all character lookups will be off by one position, causing '%' to render as 'g', '>' to render
as '?', and other visual glitches. This was a common bug that has been fixed - see
Docs/CHARSET_FIX_SUMMARY.md for details.
Where Charset is Used
| File | Location | Purpose |
|---|---|---|
generate_font.py |
CHARSET constant | Defines character order in generated PNG |
WindowManager.cs |
Initialize() method | System font initialization |
DisplayOptions.cs |
ApplyFont() method | User-selected font loading |
Program.cs |
CustomCharset string | Alternative font loading |
Generating New Fonts
guideXOS includes a Python script that generates bitmap font PNGs from system TrueType fonts.
Prerequisites
- Python 3.x installed
- Pillow (PIL) library:
pip install pillow - System fonts installed (DejaVu, Consolas, Courier, etc.)
Step 1: Configure the Script
Edit Scripts/generate_font.py to adjust font generation parameters:
# Configuration in generate_font.py
FONT_SIZE = 18 # Font size to render (affects quality)
CHAR_WIDTH = 18 # Width of each grid cell
CHAR_HEIGHT = 18 # Height of each grid cell
CHARS_PER_ROW = 13 # Number of characters per row
BG_COLOR = (0, 0, 0, 0) # Transparent background (RGBA)
FG_COLOR = (255, 255, 255, 255) # White text (RGBA)
Step 2: Run the Generator
# Generate with default name (defaultfont.png)
python Scripts/generate_font.py
# Generate with custom name
python Scripts/generate_font.py myfont_18px.png
Step 3: Copy to Ramdisk
# Windows
copy defaultfont.png Ramdisk\Fonts\
# Linux/Mac
cp defaultfont.png Ramdisk/Fonts/
Step 4: Rebuild ISO
# Windows
ForceRebuildISO.bat
# Linux/Mac
./rebuild.sh
Creating Different Font Sizes
To create multiple sizes of the same font:
# Edit generate_font.py - change these values:
FONT_SIZE = 12
CHAR_WIDTH = 12
CHAR_HEIGHT = 12
# Run generator
python Scripts/generate_font.py roboto_12px.png
# Repeat for 16px
FONT_SIZE = 16
CHAR_WIDTH = 16
CHAR_HEIGHT = 16
python Scripts/generate_font.py roboto_16px.png
# Repeat for 20px
FONT_SIZE = 20
CHAR_WIDTH = 20
CHAR_HEIGHT = 20
python Scripts/generate_font.py roboto_20px.png
# Copy all to Ramdisk
copy *.png Ramdisk\Fonts\
For 12pt fonts: Use 18-20px grid
For 14pt fonts: Use 20-22px grid
For 16pt fonts: Use 22-24px grid
For 18pt fonts: Use 24-28px grid
The grid should be slightly larger than the font size to provide adequate spacing.
Using Fonts in Code
Fonts are loaded and used through the IFont class in Kernel/Misc/IFont.cs.
Loading a Font
<code>// Load font PNG
PNG fontImage = new PNG(File.ReadAllBytes("Fonts/roboto_12pt_regular.png"));
// Define charset (MUST match generation script)
string charset = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
// Create font instance
IFont font = new IFont(
fontImage, // PNG image
charset, // Character order
20, // Grid cell size (FontSize)
true, // Use fixed width mode?
15, // Fixed character width (if fixed mode)
-5 // Padding adjustment
);</code>
Drawing Text
// Draw a single character
int advanceWidth = font.DrawChar(graphics, x, y, 'A');
x += advanceWidth; // Move cursor forward
// Draw a string
font.DrawString(x, y, "Hello, World!");
// Draw string with clipping
font.DrawString(x, y, "Long text...", maxWidth, maxHeight);
Font Parameters Explained
| Parameter | Type | Description |
|---|---|---|
image |
Image | PNG image containing the font characters |
charset |
string | Character order string (must match PNG layout) |
size |
int | Grid cell size (FontSize) - width and height of each cell |
fixedWidth |
bool | If true, all characters use CharWidth; if false, auto-trim empty columns |
fixedCharWidth |
int | Fixed width for all characters (only if fixedWidth = true) |
padding |
int | Horizontal spacing adjustment between characters (can be negative) |
Variable vs Fixed Width
Variable Width (proportional):
fixedWidth = false- Each character's width is calculated by trimming empty columns
- Space character uses
FontSize / 2 - More natural appearance for body text
- Example: "i" is narrower than "W"
Fixed Width (monospace):
fixedWidth = true- All characters use
CharWidth - Space character uses
CharWidth / 2 - Useful for UI elements, tables, code display
- Example: All characters have identical width
Advanced Features
Font Variants (Bold, Italic)
The font system supports style variants through the SetVariants() method:
// Load different style variants
IFont normalFont = new IFont(normalPNG, charset, 20);
IFont boldFont = new IFont(boldPNG, charset, 20);
IFont italicFont = new IFont(italicPNG, charset, 20);
IFont boldItalicFont = new IFont(boldItalicPNG, charset, 20);
// Set variants on the normal font
normalFont.SetVariants(boldFont, italicFont, boldItalicFont);
// Get a specific variant
IFont variant = normalFont.GetVariant(FontStyle.Bold);
Measuring Text Width
// Measure string width (if MeasureString method exists)
int width = font.MeasureString("Hello");
// Manually calculate character width
int index = charset.IndexOf('A');
// Use font.CharWidth or calculate based on mode
Character Rendering Details
The DrawChar method in IFont.cs:
- Lookup: Finds character index in charset string
- Calculate Position: Determines row/column in grid based on index
- Extract Pixels: Copies character cell from font image
- Trim Width: (Variable width only) Scans for rightmost non-transparent pixel
- Render: Draws non-transparent pixels to screen with alpha blending
- Return Width: Returns the advance width for cursor positioning
Custom Font Loader Example
<code>public static IFont LoadCustomFont(string path, int size) {
try {
byte[] data = File.ReadAllBytes(path);
var img = new PNG(data);
string charset = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
return new IFont(img, charset, size, false, 0, 0);
} catch {
Console.WriteLine("Failed to load font: " + path);
return null;
}
}</code>
Troubleshooting
Wrong Characters Appear
Symptom:
"CPU 50%" shows as "CPUg50%" or characters are shifted by one position
Cause:
Charset mismatch between Python script and C# code. Most commonly, the leading space is missing.
Solution:
- Verify charset in
generate_font.pystarts with a space - Verify charset in C# code starts with a space
- Regenerate font PNG with corrected charset
- Rebuild guideXOS ISO
Missing or Garbled Characters
Possible Causes:
- Font PNG is corrupted or not a valid PNG file
- Font file path is incorrect
- Grid dimensions don't match FontSize parameter
- Not enough rows in the font image for all characters
Solutions:
- Verify PNG file opens correctly in an image viewer
- Check file path in
File.ReadAllBytes()call - Recalculate image dimensions: width = chars_per_row × size, height = rows × size
- Regenerate font with correct parameters
Font Doesn't Load
Check these items:
- Font PNG exists in
Ramdisk/Fonts/directory - File name matches exactly (case-sensitive on some systems)
- PNG has correct format (RGBA, not indexed color)
- ISO was rebuilt after adding the font file
- Check console output for error messages
Text is Too Small/Large
Solution:
Generate a new font file with different FONT_SIZE, CHAR_WIDTH,
and CHAR_HEIGHT parameters. Remember that each size requires a separate font file.
Characters Have Jagged Edges
Cause:
TrueType font rendering quality in the Python script, or PNG doesn't have proper alpha channel
Solutions:
- Increase
FONT_SIZEin generate_font.py for better quality - Try different TrueType font source
- Ensure PNG uses RGBA format with alpha channel
- Use a higher-quality system font as the source
Enable diagnostic output in WindowManager.cs by uncommenting
font.DiagnoseFont(); to see character mapping information in the console.