Files
V2_micropython/websocket_server/generate_font.py
jeremygan2021 e0776a1839 t
2026-03-02 22:43:04 +08:00

128 lines
5.3 KiB
Python

import struct
import freetype
import os
# Font file and output file
FONT_FILE = "/Users/jeremygan/Desktop/python_dev/epaper2/websocket_server/GB2312.ttf"
OUTPUT_FILE = "/Users/jeremygan/Desktop/python_dev/epaper2/GB2312-16.bin"
# Font size (16x16)
FONT_SIZE = 16
def create_gb2312_font():
# Load the face
try:
face = freetype.Face(FONT_FILE)
except Exception as e:
print(f"Error loading font: {e}")
return
# Set char size
face.set_pixel_sizes(FONT_SIZE, FONT_SIZE)
print(f"Generating GB2312 font file: {OUTPUT_FILE}")
with open(OUTPUT_FILE, 'wb') as f:
# Iterate through GB2312 code points
# Area: 0xA1 - 0xFE (161 - 254) -> 94 areas
# Index: 0xA1 - 0xFE (161 - 254) -> 94 chars per area
count = 0
total_chars = 94 * 94
# Buffer for empty char (32 bytes of 0x00)
empty_char = b'\x00' * 32
for area in range(0xA1, 0xFF):
for index in range(0xA1, 0xFF):
# Construct GB2312 code
gb_code = bytes([area, index])
try:
# Decode to unicode character
char = gb_code.decode('gb2312')
# Load glyph
face.load_char(char, freetype.FT_LOAD_RENDER | freetype.FT_LOAD_TARGET_MONO)
bitmap = face.glyph.bitmap
# Convert bitmap to 32 bytes (16x16 / 8)
# The bitmap.buffer is a flat list of bytes.
# For mono rendering, each byte is 0 or 255? No, it's packed?
# FT_LOAD_TARGET_MONO packs 8 pixels into 1 byte.
# We need to ensure it's 16x16.
# Center the glyph in 16x16 box.
glyph_width = bitmap.width
glyph_rows = bitmap.rows
glyph_pitch = bitmap.pitch
# Create a 16x16 buffer (32 bytes)
char_buffer = bytearray(32)
# Calculate offsets to center
x_off = (FONT_SIZE - glyph_width) // 2
# Vertical alignment is tricky. Let's use bearing Y or just center based on rows.
# A better way is using face.glyph.bitmap_top
# But for fixed height font generation, usually we just center or align baseline.
# Let's try simple centering for now.
y_off = (FONT_SIZE - glyph_rows) // 2
# Adjust y_off if it's too high/low?
# Let's align to baseline approximately.
# Usually baseline is at 12-13px for 16px font.
# face.size.ascender might help but let's stick to bitmap center for simplicity first.
# Copy bitmap to buffer
src_buf = bitmap.buffer
for row in range(glyph_rows):
# Target row
dst_row = row + y_off
if dst_row < 0 or dst_row >= FONT_SIZE:
continue
# Source row bytes
# pitch is bytes per row
src_start = row * glyph_pitch
# We need to copy bits.
# This is getting complicated because FreeType mono bitmap format
# might not match our target format exactly (MSB/LSB).
# Let's iterate pixels.
for col in range(glyph_width):
dst_col = col + x_off
if dst_col < 0 or dst_col >= FONT_SIZE:
continue
# Get pixel from src
byte_idx = src_start + (col >> 3)
bit_idx = 7 - (col & 7)
pixel = (src_buf[byte_idx] >> bit_idx) & 1
if pixel:
# Set pixel in dst
# format: row by row, 2 bytes per row.
# row 0: byte 0, byte 1
# byte 0: bits 0-7 (left to right) -> wait, usually MSB is left.
dst_byte_idx = dst_row * 2 + (dst_col >> 3)
dst_bit_idx = 7 - (dst_col & 7)
char_buffer[dst_byte_idx] |= (1 << dst_bit_idx)
f.write(char_buffer)
count += 1
except Exception:
# Character not found or decode error
f.write(empty_char)
# Progress
if count % 1000 == 0:
print(f"Processed {count} characters...")
print(f"Done! Generated {OUTPUT_FILE} with size {os.path.getsize(OUTPUT_FILE)} bytes.")
if __name__ == "__main__":
create_gb2312_font()