Files
qianbian/src/ppclock/textbitmap.py
T

66 lines
2.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""倒计时前缀文字位图(证据 analysis/web/timedjs2.js:180-236)。
与 JS 差异:JS 帧有 off-by-one(丢末字节),本实现发完整位图(设备缓冲兼容),见 DECISIONS.md。
"""
from __future__ import annotations
from PIL import Image, ImageDraw
from .templates import _font
GRID_CLOCK = 16 # 时钟界面字格 16px,≤8 单位(中文≤4+英文),>4 拆两包
GRID_CALENDAR = 24 # 日历界面字格 24px,≤4 单位,每字一包
def char_units(text: str) -> float:
"""中文=1 单位,其他=0.5(timedjs2.js charCount 语义)。"""
return sum(1.0 if ord(ch) > 0x2E7F else 0.5 for ch in text)
def render_text_bitmap(text: str, grid: int) -> bytes:
"""单行文本 → 1bpp MSB-first 行主序位图。宽度=units*grid,高度=grid。"""
if grid not in (GRID_CLOCK, GRID_CALENDAR):
raise ValueError("grid 必须是 16 或 24")
units = char_units(text)
if units != int(units):
raise ValueError("中英混排产生 0.5 单位,JS 端会生成非法帧,CLI 拒绝")
w, h = int(units) * grid, grid
if w == 0:
raise ValueError("空文本")
img = Image.new("L", (w, h), 0)
d = ImageDraw.Draw(img)
font = _font(int(grid * 0.875)) # 16px格→14px 字
d.text((w // 2, h // 2), text, font=font, fill=255, anchor="mm")
px = img.load()
out = bytearray()
for y in range(h):
for xb in range(w // 8):
byte = 0
for bit in range(8):
if px[xb * 8 + bit, y] > 128:
byte |= 1 << (7 - bit)
out.append(byte)
return bytes(out)
def prefix_frames(text: str, mode: str) -> list[bytes]:
"""前缀文字 → 帧列表。
clock: ≤4 单位单包 0{n}+位图;>4 两包 04+前128B / 0{n}+余量。
calendar: 每字一包 990{j}+72B。"""
units = char_units(text)
if units != int(units):
raise ValueError("中英混排产生 0.5 单位,不支持")
n = int(units)
if mode == "clock":
if n > 8:
raise ValueError("时钟界面最多 8 单位(纯中文 4 字)")
bmp = render_text_bitmap(text, GRID_CLOCK)
if n <= 4:
return [bytes([n]) + bmp]
return [bytes([0x04]) + bmp[:128], bytes([n]) + bmp[128:]]
if mode == "calendar":
if n > 4:
raise ValueError("日历界面最多 4 字")
bmp = render_text_bitmap(text, GRID_CALENDAR)
return [bytes([0x99, j]) + bmp[j * 72:(j + 1) * 72] for j in range(n)]
raise ValueError("mode 必须是 clock 或 calendar")