Porównaj commity

...

2 Commity

Autor SHA1 Wiadomość Data
Jacques Supcik 3c9ef81fdd add latin15 2023-10-26 01:16:24 +02:00
Jacques Supcik 9453548518 split writer from cli 2023-10-26 01:00:28 +02:00
3 zmienionych plików z 213 dodań i 178 usunięć

Wyświetl plik

@ -34,8 +34,7 @@ from pathlib import Path
import click
import freetype
from .byte_writer import ByteWriter
from .font import Font
from .writer import write_binary_font, write_font
if freetype.version()[0] < 1:
click.echo("freetype version should be >= 1. Please see FONT_TO_PY.md")
@ -49,182 +48,6 @@ UNICODE_PRIVATE_USE_AREA_END = 0xF8FF
VERSION = importlib.metadata.version("micropython-font-to-py")
# Define a global
def var_write(stream, name, value):
stream.write(f"{name} = {value}\n")
STR01 = """# Code generated by font_to_py.
# Font: {font:s}{charset:s}
# Cmd: {cmd:s}
version = '{version:s}'
"""
# Code emitted for charsets spanning a small range of ordinal values
STR02 = """_mvfont = memoryview(_font)
_mvi = memoryview(_index)
ifb = lambda l : l[0] | (l[1] << 8)
def get_ch(ch):
oc = ord(ch)
ioff = 2 * (oc - {min:d} + 1) if oc >= {min:d} and oc <= {max:d} else 0
doff = ifb(_mvi[ioff : ])
width = ifb(_mvfont[doff : ])
"""
# Code emiited for large charsets, assumed by build_arrays() to be sparse.
# Binary search of sorted sparse index.
# Offset into data array is saved after dividing by 8
STRSP = """_mvfont = memoryview(_font)
_mvsp = memoryview(_sparse)
ifb = lambda l : l[0] | (l[1] << 8)
def bs(lst, val):
while True:
m = (len(lst) & ~ 7) >> 1
v = ifb(lst[m:])
if v == val:
return ifb(lst[m + 2:])
if not m:
return 0
lst = lst[m:] if v < val else lst[:m]
def get_ch(ch):
doff = bs(_mvsp, ord(ch)) << 3
width = ifb(_mvfont[doff : ])
"""
# Code emitted for horizontally mapped fonts.
STR02H = """
next_offs = doff + 2 + ((width - 1)//8 + 1) * {height:d}
return _mvfont[doff + 2:next_offs], {height:d}, width
"""
# Code emitted for vertically mapped fonts.
STR02V = """
next_offs = doff + 2 + (({height:d} - 1)//8 + 1) * width
return _mvfont[doff + 2:next_offs], {height:d}, width
"""
# Extra code emitted where -i is specified.
STR03 = '''
def glyphs():
for c in """{}""":
yield c, get_ch(c)
'''
def write_func(stream, name, arg):
stream.write(f"def {name}():\n return {arg}\n\n")
def write_font( # noqa: PLR0913
op_path,
font_path,
height,
monospaced,
hmap,
reverse,
minchar,
maxchar,
defchar,
charset,
iterate,
bitmapped,
):
try:
fnt = Font(
font_path, height, minchar, maxchar, monospaced, defchar, charset, bitmapped
)
except freetype.ft_errors.FT_Exception:
click.echo(f"Can't open {font_path}")
return False
try:
with open(op_path, "w", encoding="utf-8") as stream:
write_data(stream, fnt, font_path, hmap, reverse, iterate, charset)
except OSError:
click.echo(f"Can't open {op_path} for writing")
return False
return True
def write_data( # noqa: PLR0913
stream, fnt, font_path, hmap, reverse, iterate, charset
):
height = fnt.height # Actual height, not target height
minchar = min(fnt.crange)
maxchar = max(fnt.crange)
st = "" if charset == "" else f" Char set: {charset}"
cl = " ".join([str(Path(sys.argv[0]).stem), *sys.argv[1:]])
stream.write(
STR01.format(font=Path(font_path).stem, charset=st, cmd=cl, version=VERSION)
)
write_func(stream, "height", height)
write_func(stream, "baseline", fnt._max_ascent)
write_func(stream, "max_width", fnt.max_width)
write_func(stream, "hmap", hmap)
write_func(stream, "reverse", reverse)
write_func(stream, "monospaced", fnt.monospaced)
write_func(stream, "min_ch", minchar)
write_func(stream, "max_ch", maxchar)
if iterate:
stream.write(STR03.format("".join(sorted(fnt.keys()))))
data, index, sparse = fnt.build_arrays(hmap, reverse)
bw_font = ByteWriter(stream, "_font")
bw_font.odata(data)
bw_font.eot()
if sparse: # build_arrays() has returned a sparse index
bw_sparse = ByteWriter(stream, "_sparse")
bw_sparse.odata(sparse)
bw_sparse.eot()
stream.write(STRSP)
click.echo("Sparse")
else:
bw_index = ByteWriter(stream, "_index")
bw_index.odata(index)
bw_index.eot()
stream.write(STR02.format(min=minchar, max=maxchar))
click.echo("Normal")
if hmap:
stream.write(STR02H.format(height=height))
else:
stream.write(STR02V.format(height=height))
# BINARY OUTPUT
# hmap reverse magic bytes
# 0 0 0x3f 0xe7
# 1 0 0x40 0xe7
# 0 1 0x41 0xe7
# 1 1 0x42 0xe7
def write_binary_font(op_path, font_path, height, hmap, reverse):
try:
fnt = Font(
font_path, height, 32, 126, True, None, ""
) # All chars have same width
except freetype.ft_errors.FT_Exception:
click.echo(f"Can't open {font_path}")
return False
sig = 1 if hmap else 0
if reverse:
sig += 2
try:
with open(op_path, "wb") as stream:
data = fnt.build_binary_array(hmap, reverse, sig)
stream.write(data)
except OSError:
click.echo(f"Can't open {op_path} for writing")
return False
return True
# PARSE COMMAND LINE ARGUMENTS
def quit(msg):
click.echo(msg)
sys.exit(1)

Wyświetl plik

@ -0,0 +1,211 @@
# Some code adapted from Daniel Bader's work at the following URL
# https://dbader.org/blog/monochrome-font-rendering-with-freetype-and-python
# With thanks to Stephen Irons @ironss for various improvements, also to
# @enigmaniac for ideas around handling `bdf` and `pcf` files.
# The MIT License (MIT)
#
# Copyright (c) 2016-2023 Peter Hinch
#
# Permission is hereby granted, free of charge, to any person obtaining a copy
# of this software and associated documentation files (the "Software"), to deal
# in the Software without restriction, including without limitation the rights
# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
# copies of the Software, and to permit persons to whom the Software is
# furnished to do so, subject to the following conditions:
#
# The above copyright notice and this permission notice shall be included in
# all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
# THE SOFTWARE.
import importlib.metadata
import sys
from pathlib import Path
import click
import freetype
from .byte_writer import ByteWriter
from .font import Font
VERSION = importlib.metadata.version("micropython-font-to-py")
# Define a global
def var_write(stream, name, value):
stream.write(f"{name} = {value}\n")
STR01 = """# Code generated by font_to_py.
# Font: {font:s}{charset:s}
# Cmd: {cmd:s}
version = '{version:s}'
"""
# Code emitted for charsets spanning a small range of ordinal values
STR02 = """_mvfont = memoryview(_font)
_mvi = memoryview(_index)
ifb = lambda l : l[0] | (l[1] << 8)
def get_ch(ch):
oc = ord(ch)
ioff = 2 * (oc - {min:d} + 1) if oc >= {min:d} and oc <= {max:d} else 0
doff = ifb(_mvi[ioff : ])
width = ifb(_mvfont[doff : ])
"""
# Code emiited for large charsets, assumed by build_arrays() to be sparse.
# Binary search of sorted sparse index.
# Offset into data array is saved after dividing by 8
STRSP = """_mvfont = memoryview(_font)
_mvsp = memoryview(_sparse)
ifb = lambda l : l[0] | (l[1] << 8)
def bs(lst, val):
while True:
m = (len(lst) & ~ 7) >> 1
v = ifb(lst[m:])
if v == val:
return ifb(lst[m + 2:])
if not m:
return 0
lst = lst[m:] if v < val else lst[:m]
def get_ch(ch):
doff = bs(_mvsp, ord(ch)) << 3
width = ifb(_mvfont[doff : ])
"""
# Code emitted for horizontally mapped fonts.
STR02H = """
next_offs = doff + 2 + ((width - 1)//8 + 1) * {height:d}
return _mvfont[doff + 2:next_offs], {height:d}, width
"""
# Code emitted for vertically mapped fonts.
STR02V = """
next_offs = doff + 2 + (({height:d} - 1)//8 + 1) * width
return _mvfont[doff + 2:next_offs], {height:d}, width
"""
# Extra code emitted where -i is specified.
STR03 = '''
def glyphs():
for c in """{}""":
yield c, get_ch(c)
'''
def write_func(stream, name, arg):
stream.write(f"def {name}():\n return {arg}\n\n")
def write_font( # noqa: PLR0913
op_path,
font_path,
height,
monospaced,
hmap,
reverse,
minchar,
maxchar,
defchar,
charset,
iterate,
bitmapped,
):
try:
fnt = Font(
font_path, height, minchar, maxchar, monospaced, defchar, charset, bitmapped
)
except freetype.ft_errors.FT_Exception:
click.echo(f"Can't open {font_path}")
return False
try:
with open(op_path, "w", encoding="utf-8") as stream:
write_data(stream, fnt, font_path, hmap, reverse, iterate, charset)
except OSError:
click.echo(f"Can't open {op_path} for writing")
return False
return True
def write_data( # noqa: PLR0913
stream, fnt, font_path, hmap, reverse, iterate, charset
):
height = fnt.height # Actual height, not target height
minchar = min(fnt.crange)
maxchar = max(fnt.crange)
st = "" if charset == "" else f" Char set: {charset}"
cl = " ".join([str(Path(sys.argv[0]).stem), *sys.argv[1:]])
stream.write(
STR01.format(font=Path(font_path).stem, charset=st, cmd=cl, version=VERSION)
)
write_func(stream, "height", height)
write_func(stream, "baseline", fnt._max_ascent)
write_func(stream, "max_width", fnt.max_width)
write_func(stream, "hmap", hmap)
write_func(stream, "reverse", reverse)
write_func(stream, "monospaced", fnt.monospaced)
write_func(stream, "min_ch", minchar)
write_func(stream, "max_ch", maxchar)
if iterate:
stream.write(STR03.format("".join(sorted(fnt.keys()))))
data, index, sparse = fnt.build_arrays(hmap, reverse)
bw_font = ByteWriter(stream, "_font")
bw_font.odata(data)
bw_font.eot()
if sparse: # build_arrays() has returned a sparse index
bw_sparse = ByteWriter(stream, "_sparse")
bw_sparse.odata(sparse)
bw_sparse.eot()
stream.write(STRSP)
click.echo("Sparse")
else:
bw_index = ByteWriter(stream, "_index")
bw_index.odata(index)
bw_index.eot()
stream.write(STR02.format(min=minchar, max=maxchar))
click.echo("Normal")
if hmap:
stream.write(STR02H.format(height=height))
else:
stream.write(STR02V.format(height=height))
# BINARY OUTPUT
# hmap reverse magic bytes
# 0 0 0x3f 0xe7
# 1 0 0x40 0xe7
# 0 1 0x41 0xe7
# 1 1 0x42 0xe7
def write_binary_font(op_path, font_path, height, hmap, reverse):
try:
fnt = Font(
font_path, height, 32, 126, True, None, ""
) # All chars have same width
except freetype.ft_errors.FT_Exception:
click.echo(f"Can't open {font_path}")
return False
sig = 1 if hmap else 0
if reverse:
sig += 2
try:
with open(op_path, "wb") as stream:
data = fnt.build_binary_array(hmap, reverse, sig)
stream.write(data)
except OSError:
click.echo(f"Can't open {op_path} for writing")
return False
return True

Wyświetl plik

@ -17,6 +17,7 @@ include = [
{ path = "Chinese_Japanese*", format = ["sdist", "wheel"] },
{ path = "cyrillic", format = ["sdist", "wheel"] },
{ path = "extended", format = ["sdist", "wheel"] },
{ path = "latin15", format = ["sdist", "wheel"] },
]
[tool.poetry.dependencies]