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