Add get_name, get_full_name, get_glyph_index, and glyph_count functions

This commit is contained in:
germax26 2024-09-15 16:22:01 +10:00
parent 61aef094df
commit 0f0711ef2b
Signed by: germax26
SSH Key Fingerprint: SHA256:N3w+8798IMWBt7SYH8G1C0iJlIa2HIIcRCXwILT5FvM

View File

@ -445,7 +445,10 @@ def parse_cmap_subtable(f: BinaryIO, platformID: PlatformID) -> CmapSubtable:
assert False, format assert False, format
class EncodingID(ABE): pass class EncodingID(ABE):
@abstractmethod
def get_code_point(self, char: str) -> Optional[int]:
assert False, f"Unimplemented: get_code_point for {repr(self)}"
class UnicodeEncodingID(EncodingID, Enum): class UnicodeEncodingID(EncodingID, Enum):
Unicode_1_0 = 0 Unicode_1_0 = 0
@ -456,6 +459,14 @@ class UnicodeEncodingID(EncodingID, Enum):
UnicodeVariationSequences = 5 UnicodeVariationSequences = 5
UnicodeFull = 6 UnicodeFull = 6
def __str__(self) -> str:
return self._name_
def get_code_point(self, char: str) -> int | None:
return ord(char) # TODO: Actually validate that the codepoint is within range of these different versions of Unicode Encoding
match self:
case _: assert False, self
class MacintoshEncodingID(EncodingID, Enum): class MacintoshEncodingID(EncodingID, Enum):
Roman = 0 Roman = 0
@ -478,6 +489,15 @@ class WindowsEncodingID(EncodingID, Enum):
def __str__(self) -> str: def __str__(self) -> str:
return self._name_ return self._name_
def get_code_point(self, char: str) -> int | None:
match self:
case self.UnicodeBMP:
code_point = ord(char)
if 0 <= code_point <= 0xFFFF: return code_point
return None
case self.UnicodeFull: return ord(char)
case _: assert False, self
@dataclass @dataclass
class CustomEncodingID(EncodingID): class CustomEncodingID(EncodingID):
encodingID: int encodingID: int
@ -6261,3 +6281,44 @@ def parse_open_font_file(f: BinaryIO) -> OpenFontFile:
def open_font_file(file_path: str) -> OpenFontFile: # as in `open (verb) font file (noun)`, not OpenFontFile def open_font_file(file_path: str) -> OpenFontFile: # as in `open (verb) font file (noun)`, not OpenFontFile
with open(file_path, 'rb') as f: with open(file_path, 'rb') as f:
return parse_open_font_file(f) return parse_open_font_file(f)
def get_name(font: OpenFontFile, 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 get_full_name(font: OpenFontFile) -> str:
return get_name(font, PredefinedNameID.FULL_NAME)
def get_glyph_index(font: OpenFontFile, char: str) -> int:
for encoding_record in font.character_to_glyph_mapping.encodingRecords:
code_point = encoding_record.encodingID.get_code_point(char)
if code_point is not None:
match encoding_record.subtable:
case CmapSubtable_Format_4(
segCountX2=segCountX2,
endCode=end_code,
startCode=start_code,
idDelta=id_delta,
idRangeOffset=id_range_offset,
glyphIdArray=glyph_id_array):
for i, (start, end) in enumerate(zip(start_code, end_code)):
if start <= code_point <= end:
if start == end == 0xFFFF: return 0
if id_range_offset[i] == 0: return (id_delta[i]+code_point)%0xFFFF
index = glyph_id_array[code_point-start+id_range_offset[i]//2+i-segCountX2//2]
if index == 0: return 0
return (index+id_delta[i])%0xFFFF
case CmapSubtable_Format_12(groups=groups):
for group in groups:
if group.startCharCode <= code_point <= group.endCharCode:
assert False, (group, code_point)
case _: assert False, encoding_record.subtable.__class__
return 0
def glyph_count(font: OpenFontFile) -> int:
return font.maximum_profile.numGlyphs