128 lines
5.3 KiB
Python
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()
|