t
This commit is contained in:
127
websocket_server/generate_font.py
Normal file
127
websocket_server/generate_font.py
Normal file
@@ -0,0 +1,127 @@
|
||||
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()
|
||||
Reference in New Issue
Block a user