Files
2023-09-15 23:39:50 +02:00

123 lines
3.6 KiB
Python

# coding=utf-8
from esphome import core
import esphome.config_validation as cv
import esphome.codegen as cg
from esphome.const import CONF_ID, CONF_GLYPHS, CONF_DATA
from esphome.core import CORE, HexInt
import logging
#from esphome.py_compat import sort_by_cmp
_LOGGER = logging.getLogger(__name__)
DOMAIN = "font"
DEPENDENCIES = ['display']
MULTI_CONF = True
font_ns = cg.esphome_ns.namespace("font")
Font = font_ns.class_("Font")
Glyph = font_ns.class_("Glyph")
GlyphData = font_ns.struct("GlyphData")
def validate_data(value):
r = type(value)()
for k, v in value.items():
if isinstance(k, str):
try:
k = int(k)
except ValueError:
if len(k.encode()) > 1:
_LOGGER.warning(f"multi byte character: '{k}'")
continue
k = ord(k.encode())
if k>=0 and k<=9:
k += ord('0')
r[k] = v
return type(value)(sorted(r.items()))
CONF_RAW_DATA_ID = 'raw_data_id'
CONF_RAW_GLYPH_ID = "raw_glyph_id"
BIT0_DEFAULT = '0 '
RASTERFONT_SCHEMA = cv.Schema({
cv.Required(CONF_ID): cv.declare_id(Font),
cv.Required(CONF_DATA): validate_data,
cv.Optional(CONF_GLYPHS): cv.string_strict,
cv.Optional('bit0', default=BIT0_DEFAULT): cv.string_strict,
cv.GenerateID(CONF_RAW_DATA_ID): cv.declare_id(cg.uint8),
cv.GenerateID(CONF_RAW_GLYPH_ID): cv.declare_id(GlyphData),
})
CONFIG_SCHEMA = cv.All(RASTERFONT_SCHEMA)
def string_to_int(s, bit0):
b = ''.join(map(lambda x: '0' if x in bit0 else '1', s+'0'*((8-len(s) % 8) % 8)))
r = [int(b[i:i+8], 2) for i in range(0, len(b), 8)]
return r
def int_to_cchar(i):
if i >= 32 and i <= 126:
return '"%c"' % i
else:
return '"\\x%02x"' % i
def to_code(config):
glyph_args = {}
data = []
include_glyphs = config.get(CONF_GLYPHS, None)
bit0 = config.get('bit0')
for glyph, gconfig in config[CONF_DATA].items():
if include_glyphs and glyph not in include_glyphs: continue
height = 0
maxwidth = 0
offset_x = gconfig.get('offset_x', 0)
offset_y = gconfig.get('offset_y', 0)
rows = gconfig.get('bitmap', [])
if isinstance(rows, str):
rows = rows.split('\n')
while rows[-1] == '': rows.pop()
for row in rows:
maxwidth = max(maxwidth, len(row))
width = gconfig.get('width', maxwidth)
glyph_data = []
for row in rows:
height += 1
glyph_data += string_to_int(row + '0'*(maxwidth-len(row)), bit0)
width8 = ((width + 7) // 8) * 8
glyph_args[glyph] = (len(data), offset_x, offset_y, width, height)
data += glyph_data
rhs = [HexInt(x) for x in data]
prog_arr = cg.progmem_array(config[CONF_RAW_DATA_ID], rhs)
glyph_initializer = []
for glyph in config[CONF_DATA].keys():
glyph_initializer.append(
cg.StructInitializer(
GlyphData,
("a_char", cg.RawExpression(int_to_cchar(glyph))),
(
"data",
cg.RawExpression(str(prog_arr) + " + " + str(glyph_args[glyph][0])),
),
("offset_x", glyph_args[glyph][1]),
("offset_y", glyph_args[glyph][2]),
("width", glyph_args[glyph][3]),
("height", glyph_args[glyph][4]),
)
)
glyphs = cg.static_const_array(config[CONF_RAW_GLYPH_ID], glyph_initializer)
cg.new_Pvariable(
config[CONF_ID], glyphs, len(glyph_initializer), 0, 0
)