font3d_blender_addon/common/Font.py

176 lines
5.4 KiB
Python
Raw Normal View History

2024-05-21 18:00:49 +02:00
from typing import TypedDict
from typing import Dict
from dataclasses import dataclass
from pathlib import Path
2024-05-21 18:00:49 +02:00
# convenience dictionary for translating names to glyph ids
# note: overwritten/extended by the content of "glypNamesToUnicode.txt"
# when addon is registered in __init__.py
2024-05-21 18:00:49 +02:00
name_to_glyph_d = {
"zero": "0",
"one": "1",
"two": "2",
"three": "3",
"four": "4",
"five": "5",
"six": "6",
"seven": "7",
"eight": "8",
"nine": "9",
"ampersand": "&",
"backslash": "\\",
"colon": ":",
"comma": ",",
"equal": "=",
"exclam": "!",
"hyphen": "-",
"minus": "",
"parenleft": "(",
"parenright": "(",
"period": ".",
"plus": "+",
"question": "?",
"quotedblleft": "",
"quotedblright": "",
"semicolon": ";",
"slash": "/",
2024-07-10 16:08:03 +02:00
"space": " ",
2024-05-21 18:00:49 +02:00
}
known_misspellings = {
# simple misspelling
"excent" : "accent",
"overdot" : "dotaccent",
"diaresis": "dieresis",
"diaeresis": "dieresis",
# character does not exist.. maybe something else
"Odoubleacute": "Ohungarumlaut",
"Udoubleacute": "Uhungarumlaut",
"Wcaron": "Wcircumflex",
"Neng": "Nlongrightleg",
"Lgrave": "Lacute",
# currency stuff
"doller": "dollar",
"euro": "Euro",
"yuan": "yen", # https://en.wikipedia.org/wiki/Yen_and_yuan_sign
"pound": "sterling",
# whoopsie
"__": "_",
}
def fix_glyph_name_misspellings(name):
for misspelling in known_misspellings:
if misspelling in name:
return name.replace(misspelling,
known_misspellings[misspelling])
return name
def name_to_glyph(name):
if len(name) == 1:
return name
if name in name_to_glyph_d:
return name_to_glyph_d[name]
else:
return None
def generate_name_to_glyph_d():
d = {}
with open(f"{Path(__file__).parent}/glyphNamesToUnicode.txt") as f:
for line in f:
if line[0] == '#':
continue
(name, hexstr) = line.split(' ')
val = chr(int(hexstr, base=16))
d[name] = val
return d
2024-05-21 18:00:49 +02:00
class FontFace:
"""FontFace is a class holding glyphs
:param glyphs: dictionary of glyphs, defaults to ``{}``
:type glyphs: dict, optional
"""
def __init__(self, glyphs = {}):
self.glyphs = glyphs
class Font:
"""Font holds the faces and various metadata for a font
:param faces: dictionary of faces, defaults to ``Dict[str, FontFace]``
:type faces: Dict[str, FontFace]
"""
def __init__(self, faces = Dict[str, FontFace]):
self.faces = faces
# TODO: better class structure?
# TODO: get fonts and faces directly
def add_glyph(font_name, face_name, glyph_id, glyph_object):
""" add_glyph adds a glyph to a FontFace
it creates the :class:`Font` and :class:`FontFace` if it does not exist yet
:param font_name: The Font you want to add the glyph to
:type font_name: str
:param face_name: The FontFace you want to add the glyph to
:type face_name: str
:param glyph_id: The glyph_id you want this glyph to be stored under
:type glyph_id: str
:param glyph_object: The object containing the glyph
:type glyph_object: `Object`
"""
if not fonts.keys().__contains__(font_name):
fonts[font_name] = Font({})
2024-06-27 14:56:43 +02:00
# print("is it has been added", fonts.keys())
2024-05-21 18:00:49 +02:00
if fonts[font_name].faces.get(face_name) == None:
fonts[font_name].faces[face_name] = FontFace({})
2024-06-27 14:56:43 +02:00
# print("is it has been added faces", fonts[font_name].faces[face_name])
2024-05-21 18:00:49 +02:00
if fonts[font_name].faces[face_name].glyphs.get(glyph_id) == None:
fonts[font_name].faces[face_name].glyphs[glyph_id] = []
2024-06-27 14:56:43 +02:00
# print("is it has been added glyph", fonts[font_name].faces[face_name].glyphs[glyph_id])
2024-05-21 18:00:49 +02:00
fonts[font_name].faces[face_name].glyphs.get(glyph_id).append(glyph_object)
def get_glyph(font_name, face_name, glyph_id, alternate=0):
2024-05-21 18:00:49 +02:00
""" add_glyph adds a glyph to a FontFace
it creates the :class:`Font` and :class:`FontFace` if it does not exist yet
:param font_name: The :class:`Font` you want to get the glyph from
:type font_name: str
:param face_name: The :class:`FontFace` you want to get the glyph from
:type face_name: str
:param glyph_id: The ``glyph_id`` from the glyph you want
:type glyph_id: str
...
:return: returns the glyph object, or ``None`` if it does not exist
:rtype: `Object`
"""
2024-07-01 14:39:07 +02:00
# print(fonts)
2024-05-21 18:00:49 +02:00
if not fonts.keys().__contains__(font_name):
2024-08-14 11:26:19 +02:00
print(f"ABC3D::get_glyph: font name({font_name}) not found")
2024-05-21 18:00:49 +02:00
print(fonts.keys())
return None
face = fonts[font_name].faces.get(face_name)
if face == None:
2024-08-14 11:26:19 +02:00
print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) not found")
2024-05-21 18:00:49 +02:00
print(fonts[font_name].faces.keys())
return None
glyphs_for_id = face.glyphs.get(glyph_id)
if glyphs_for_id == None or len(glyphs_for_id) <= alternate:
2024-08-14 11:26:19 +02:00
print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) glyph({glyph_id})[{alternate}] not found")
2024-05-21 18:00:49 +02:00
return None
return fonts[font_name].faces[face_name].glyphs.get(glyph_id)[alternate]
2024-05-21 18:00:49 +02:00
2024-05-28 14:11:32 +02:00
def get_loaded_fonts():
return fonts.keys()
2024-05-21 18:00:49 +02:00
# holds all fonts
fonts = {}