Xteink-X4-crosspoint-reader/docs/cjk-fonts.md
aber0724 895fe470c6 feat: Add CJK UI font support and complete I18N implementation
## Major Features

### 1. CJK UI Font System
- Implemented external font loading system for CJK characters
- Added Source Han Sans (思源黑体) as base font for UI rendering
- Support for multiple font sizes (20pt, 22pt, 24pt)
- Font selection UI for both reader and UI fonts
- Automatic fallback to built-in fonts when external fonts unavailable
- External UI font now renders ALL characters (including ASCII) for consistent style
- Proportional spacing for external fonts (variable width per character)

### 2. Complete I18N Implementation
- Added comprehensive internationalization system
- Support for English, Chinese Simplified, and Japanese
- Translated all UI strings across the entire application
- Language selection UI in settings with native language names
  - English displayed as "English"
  - Chinese displayed as "简体中文"
  - Japanese displayed as "日本語"
- Dynamic language switching without restart

### 3. Bug Fixes

#### Rendering Race Conditions
- Fixed race condition where parent and child Activity rendering tasks run simultaneously
- Added 500ms delay in child Activity displayTaskLoop() to wait for parent rendering completion
- Unified displayTaskLoop() logic: `if (updateRequired && !subActivity)`
- Prevents duplicate RED RAM writes and incomplete screen refreshes

**Affected Activities:**
- CategorySettingsActivity: Unified displayTaskLoop check logic
- KOReaderSettingsActivity: Added 500ms delay before first render
- CalibreSettingsActivity: Added 500ms delay before first render
- FontSelectActivity: Added 500ms delay before first render
- ClearCacheActivity: Added 500ms delay and subActivity check
- LanguageSelectActivity: Added 500ms delay in displayTaskLoop (not onEnter)

#### Button Response Issues
- Fixed CrossPointWebServer exit button requiring long press
- Added MappedInputManager::update() method
- Call update() before wasPressed() in tight HTTP processing loop
- Button presses during loop are now properly detected

#### ClearCache Crash
- Fixed FreeRTOS mutex deadlock when exiting ClearCache activity
- Added isExiting flag to prevent operations during exit
- Added clearCacheTaskHandle tracking
- Wait for clearCache task completion before deleting mutex

#### External UI Font Rendering
- Fixed ASCII characters not using external UI font (was using built-in EPD font)
- Fixed character spacing too wide (now uses proportional spacing via getGlyphMetrics)

## Technical Details

**Files Added:**
- lib/ExternalFont/: External font loading system
- lib/I18n/: Internationalization system
- lib/GfxRenderer/cjk_ui_font*.h: Pre-rendered CJK font data
- scripts/generate_cjk_ui_font.py: Font generation script
- src/activities/settings/FontSelectActivity.*: Font selection UI
- src/activities/settings/LanguageSelectActivity.*: Language selection UI
- docs/cjk-fonts.md: CJK font documentation
- docs/i18n.md: I18N documentation

**Files Modified:**
- lib/GfxRenderer/: Added CJK font rendering support with proportional spacing
- src/activities/: I18N integration across all activities
- src/MappedInputManager.*: Added update() method
- src/CrossPointSettings.cpp: Added language and font settings

**Memory Usage:**
- Flash: 94.7% (6204434 bytes / 6553600 bytes)
- RAM: 66.4% (217556 bytes / 327680 bytes)

## Testing Notes

All rendering race conditions and button response issues have been fixed and tested.
ClearCache no longer crashes when exiting.
File transfer page now responds to short press on exit button.
External UI font now renders all characters with proper proportional spacing.
Language selection page displays language names in their native scripts.

Co-authored-by: Claude (Anthropic AI Assistant)
2026-01-23 16:54:56 +09:00

6.6 KiB

CJK Font Support

This guide explains how to use Chinese, Japanese, and Korean (CJK) fonts on your CrossPoint Reader.

Overview

CrossPoint Reader supports external CJK fonts for both:

  • UI Font - Used for menus, settings, and system interface
  • Reader Font - Used for reading ebook content

The device includes a built-in CJK UI font (Source Han Sans subset) for basic interface rendering, and supports loading custom external fonts from the SD card.

Prerequisites

  • CrossPoint Reader device with firmware version supporting CJK fonts
  • SD card with available space for font files
  • TrueType font files (.ttf) converted to the CrossPoint font format

Font File Format

CrossPoint Reader uses a custom binary font format optimized for e-ink displays. Font files must be placed in the /fonts/ directory on the SD card.

File Naming Convention

Font files must follow this naming pattern:

{FontName}_{Size}_{Width}x{Height}.bin

Examples:

  • SourceHanSansCN-Medium_20_20x20.bin
  • KingHwaOldSong_38_33x39.bin
  • Yozai-Medium_36_31x31.bin

Font File Structure

The binary font file contains:

  1. Header (variable length)

    • Font name (null-terminated string)
    • Font size (uint8_t)
    • Character width (uint8_t)
    • Character height (uint8_t)
    • Bytes per character (uint16_t)
  2. Character Data

    • Sequential bitmap data for each character
    • Characters are stored in Unicode order
    • Each character uses width * height / 8 bytes (1-bit per pixel)

Generating Font Files

Use the provided Python script to convert TrueType fonts:

python scripts/generate_cjk_ui_font.py \
    --font /path/to/font.ttf \
    --size 20 \
    --output /path/to/output.bin

Script Options

Option Description
--font Path to TrueType font file (.ttf)
--size Font size in points
--output Output binary file path
--chars (Optional) Custom character set file

Character Set

By default, the script generates fonts for:

  • Basic ASCII characters (0x20-0x7E)
  • Common CJK characters (GB2312 subset)
  • Japanese Hiragana and Katakana
  • Common punctuation marks

Installing Fonts

  1. Create the fonts directory (if it doesn't exist):

    /fonts/
    
  2. Copy font files to the /fonts/ directory on your SD card

  3. Restart the device or go to Settings to scan for new fonts


Selecting Fonts

UI Font

  1. Go to SettingsDisplay
  2. Select External UI Font
  3. Choose from available fonts or select Built-in (Disabled) to use the default font

Reader Font

  1. Go to SettingsReader
  2. Select External Reader Font
  3. Choose from available fonts or select Built-in (Disabled) to use the default font

Built-in CJK UI Font

The firmware includes a pre-rendered subset of Source Han Sans (思源黑体) for UI rendering. This font covers:

  • All ASCII characters
  • Common Chinese characters used in the UI
  • Japanese Hiragana and Katakana
  • Common punctuation marks

The built-in font is automatically used when:

  • No external UI font is selected
  • The external font file is missing or corrupted

External UI Font Features

When an external UI font is selected:

Full Character Coverage

  • All characters (including ASCII letters, numbers, and punctuation) are rendered using the external font
  • This ensures consistent visual style across the entire UI
  • If a character is missing from the external font, the system falls back to built-in fonts

Proportional Spacing

  • External fonts use proportional spacing (variable width)
  • Each character advances by its actual width, not a fixed width
  • This makes English text look more natural with proper letter spacing
  • CJK characters still use their full width as designed

For UI (Small sizes, 18-24pt)

Font Description License
Source Han Sans Clean, modern sans-serif OFL
Noto Sans CJK Google's CJK font family OFL
WenQuanYi Micro Hei Compact Chinese font GPL

For Reading (Larger sizes, 28-40pt)

Font Description License
Source Han Serif Traditional serif style OFL
Noto Serif CJK Google's serif CJK font OFL
FangSong Classic Chinese style Varies

Memory Considerations

External fonts consume RAM when loaded. Consider these guidelines:

Font Size Approx. Memory Usage
20pt ~50KB per 1000 characters
28pt ~100KB per 1000 characters
36pt ~160KB per 1000 characters

Tips:

  • Use smaller font sizes for UI (18-24pt)
  • Larger fonts (32pt+) are better for reader content
  • Only one UI font and one reader font are loaded at a time

Troubleshooting

Font not appearing in selection list

  1. Check the file is in /fonts/ directory
  2. Verify the filename follows the naming convention
  3. Ensure the file is not corrupted (try regenerating)

Characters displaying as boxes or question marks

  1. The character may not be included in the font
  2. Try a font with broader character coverage
  3. Check if the font file was generated correctly

Device running slowly after selecting font

  1. The font file may be too large
  2. Try a smaller font size
  3. Reduce the character set when generating the font

Font looks blurry or pixelated

  1. E-ink displays work best with specific font sizes
  2. Try sizes that are multiples of the display's native resolution
  3. Ensure anti-aliasing is disabled for 1-bit rendering

Technical Details

Font Manager API

The FontManager class provides:

// Scan for available fonts
FontMgr.scanFonts();

// Get font count
int count = FontMgr.getFontCount();

// Get font info
const FontInfo* info = FontMgr.getFontInfo(index);

// Select reader font (-1 to disable)
FontMgr.selectFont(index);

// Select UI font (-1 to disable)
FontMgr.selectUiFont(index);

// Check if external font is enabled
bool enabled = FontMgr.isExternalFontEnabled();

Font Info Structure

struct FontInfo {
    char name[32];      // Font name
    uint8_t size;       // Font size in points
    uint8_t width;      // Character width in pixels
    uint8_t height;     // Character height in pixels
    uint16_t bytesPerChar; // Bytes per character
    char path[64];      // Full path to font file
};