Add /OpenFontFormat
This commit is contained in:
parent
38987a04c6
commit
9b509e6306
2
OpenFontFormat/.gitignore
vendored
Normal file
2
OpenFontFormat/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
examples
|
||||||
|
mypy.ini
|
5960
OpenFontFormat/OpenFont.py
Normal file
5960
OpenFontFormat/OpenFont.py
Normal file
File diff suppressed because it is too large
Load Diff
21
OpenFontFormat/abcde.py
Normal file
21
OpenFontFormat/abcde.py
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
class ABD:
|
||||||
|
"""
|
||||||
|
#### Abstract Base Dataclass
|
||||||
|
|
||||||
|
This will only work on dataclasses
|
||||||
|
"""
|
||||||
|
def __post_init__(self, *args, **kwargs):
|
||||||
|
if ABD in self.__class__.__bases__ or ABD == self.__class__:
|
||||||
|
msg = f"Cannot instantiate an Abstract Base Dataclass: {self.__class__.__name__}"
|
||||||
|
raise TypeError(msg)
|
||||||
|
|
||||||
|
class ABE:
|
||||||
|
"""
|
||||||
|
#### Abstract Base Enum
|
||||||
|
|
||||||
|
This is for classes that will have an Enum subclass them
|
||||||
|
"""
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
if ABE in self.__class__.__bases__ or ABE == self:
|
||||||
|
msg = f"Cannot instantiate an Abstract Base Enum: {self.__class__.__name__}"
|
||||||
|
raise TypeError(msg)
|
49
OpenFontFormat/name.py
Normal file
49
OpenFontFormat/name.py
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
import os
|
||||||
|
|
||||||
|
from OpenFont import FontSpecificNameID, NameID, NameTable_Format_0, OpenFont, PredefinedNameID, TrueTypeOutlines, parse_file
|
||||||
|
|
||||||
|
def search_names(font: OpenFont, nameID: NameID) -> str:
|
||||||
|
assert isinstance(font.naming_table, NameTable_Format_0)
|
||||||
|
|
||||||
|
for nameRecord in font.naming_table.nameRecord:
|
||||||
|
if nameRecord.nameID == nameID:
|
||||||
|
return nameRecord.string
|
||||||
|
|
||||||
|
assert False, f"Name not found: {nameID}"
|
||||||
|
|
||||||
|
def print_font(font: OpenFont):
|
||||||
|
assert isinstance(font.naming_table, NameTable_Format_0)
|
||||||
|
assert isinstance(font.outlines, TrueTypeOutlines)
|
||||||
|
|
||||||
|
name = search_names(font, PredefinedNameID.FULL_NAME)
|
||||||
|
|
||||||
|
print(name, f"({font.maximum_profile.numGlyphs} glyphs, {font.naming_table.count} names)")
|
||||||
|
if font.font_variations:
|
||||||
|
axis_names = [search_names(font, FontSpecificNameID(axis.axisNameID)) for axis in font.font_variations.font_variations.axes]
|
||||||
|
num_instances = font.font_variations.font_variations.instanceCount
|
||||||
|
print(f"\tAxes: [{', '.join(axis_names)}] ({num_instances} instances)")
|
||||||
|
|
||||||
|
path = "examples/"
|
||||||
|
# path = "examples/android_fonts/api_level/30"
|
||||||
|
# path = "examples/android_fonts/api_level/30/NotoNaskhArabic-Bold.ttf"
|
||||||
|
path = "examples/JetBrainsMono-2.304/"
|
||||||
|
if os.path.isfile(path):
|
||||||
|
try:
|
||||||
|
font = parse_file(path)
|
||||||
|
except AssertionError as err:
|
||||||
|
print("Failed:", path)
|
||||||
|
raise err
|
||||||
|
print_font(font)
|
||||||
|
else:
|
||||||
|
for root, dirs, files in os.walk(path):
|
||||||
|
for file in files:
|
||||||
|
_, ext = os.path.splitext(file)
|
||||||
|
match ext:
|
||||||
|
case '.ttf':
|
||||||
|
file_path = os.path.join(root, file)
|
||||||
|
try:
|
||||||
|
font = parse_file(file_path)
|
||||||
|
except AssertionError as err:
|
||||||
|
print("Failed:", file_path)
|
||||||
|
raise err
|
||||||
|
print_font(font)
|
26
OpenFontFormat/read_utils.py
Normal file
26
OpenFontFormat/read_utils.py
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
from typing import BinaryIO
|
||||||
|
|
||||||
|
def read_int(f: BinaryIO, number: int, signed:bool=False) -> int: return int.from_bytes(f.read(number), 'big', signed=signed)
|
||||||
|
|
||||||
|
def read_u64(f: BinaryIO) -> int: return read_int(f, 8)
|
||||||
|
def read_u32(f: BinaryIO) -> int: return read_int(f, 4)
|
||||||
|
def read_u24(f: BinaryIO) -> int: return read_int(f, 3)
|
||||||
|
def read_u16(f: BinaryIO) -> int: return read_int(f, 2)
|
||||||
|
def read_u8(f: BinaryIO) -> int: return read_int(f, 1)
|
||||||
|
|
||||||
|
def read_i32(f: BinaryIO) -> int: return read_int(f, 4, signed=True)
|
||||||
|
def read_i16(f: BinaryIO) -> int: return read_int(f, 2, signed=True)
|
||||||
|
def read_i8(f: BinaryIO) -> int: return read_int(f, 1, signed=True)
|
||||||
|
|
||||||
|
def read_utf8(f: BinaryIO, number: int) -> str: return f.read(number).decode(encoding='utf8')
|
||||||
|
def read_ascii(f: BinaryIO, number: int) -> str: return f.read(number).decode(encoding='ascii')
|
||||||
|
|
||||||
|
def read_fixed_point(f: BinaryIO, preradix_bits: int, postradix_bits:int, *, signed:bool=True) -> float:
|
||||||
|
assert (preradix_bits+postradix_bits)%8 == 0
|
||||||
|
raw = read_int(f, (preradix_bits+postradix_bits)//8, signed=signed)
|
||||||
|
return raw/(1<<(postradix_bits))
|
||||||
|
|
||||||
|
def read_pascal_string(f: BinaryIO) -> str:
|
||||||
|
string_size = read_int(f, 1)
|
||||||
|
pascal_string = read_ascii(f, string_size)
|
||||||
|
return pascal_string
|
Loading…
Reference in New Issue
Block a user