stabilizing, user experience
use class for glyph availability use isinstance instead of type better user experience when export directory does not exist
This commit is contained in:
parent
777644e509
commit
335ab1face
4 changed files with 279 additions and 129 deletions
108
common/Font.py
108
common/Font.py
|
@ -1,5 +1,6 @@
|
|||
from typing import Dict
|
||||
from pathlib import Path
|
||||
from typing import NamedTuple
|
||||
|
||||
# convenience dictionary for translating names to glyph ids
|
||||
# note: overwritten/extended by the content of "glypNamesToUnicode.txt"
|
||||
|
@ -160,6 +161,7 @@ class Font:
|
|||
self.faces = faces
|
||||
|
||||
|
||||
|
||||
def register_font(font_name, face_name, glyphs_in_fontfile, filepath):
|
||||
if not fonts.keys().__contains__(font_name):
|
||||
fonts[font_name] = Font({})
|
||||
|
@ -177,6 +179,34 @@ def register_font(font_name, face_name, glyphs_in_fontfile, filepath):
|
|||
fonts[font_name].faces[face_name].filepaths.append(filepath)
|
||||
|
||||
|
||||
def get_font(font_name):
|
||||
if not fonts.keys().__contains__(font_name):
|
||||
print(f"ABC3D::get_font: font name({font_name}) not found")
|
||||
print(fonts.keys())
|
||||
return None
|
||||
return fonts[font_name]
|
||||
|
||||
|
||||
def get_font_face(font_name, face_name):
|
||||
font = get_font(font_name)
|
||||
if font is None:
|
||||
return None
|
||||
if not font.faces.keys().__contains__(face_name):
|
||||
print(
|
||||
f"ABC3D::get_font_face (font: {font_name}): face name({face_name}) not found"
|
||||
)
|
||||
print(font.faces.keys())
|
||||
return None
|
||||
return font.faces[face_name]
|
||||
|
||||
|
||||
def get_font_face_filepaths(font_name, face_name):
|
||||
face = get_font_face(font_name, face_name)
|
||||
if not face:
|
||||
return None
|
||||
return face.filepaths
|
||||
|
||||
|
||||
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
|
||||
|
@ -203,6 +233,38 @@ def add_glyph(font_name, face_name, glyph_id, glyph_object):
|
|||
fonts[font_name].faces[face_name].loaded_glyphs.append(glyph_id)
|
||||
|
||||
|
||||
def get_glyphs(font_name, face_name, glyph_id):
|
||||
"""get_glyphs returns an array of glyphs of a FontFace
|
||||
|
||||
: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 a list of the glyph objects, or an empty list if none exists
|
||||
:rtype: `List`
|
||||
"""
|
||||
|
||||
face = get_font_face(font_name, face_name)
|
||||
if face is None:
|
||||
print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) not found")
|
||||
print(fonts[font_name].faces.keys())
|
||||
return []
|
||||
|
||||
glyphs_for_id = face.glyphs.get(glyph_id)
|
||||
if glyphs_for_id is None:
|
||||
print(
|
||||
f"ABC3D::get_glyph: font({font_name}) face({face_name}) glyph({glyph_id}) not found"
|
||||
)
|
||||
if glyph_id not in fonts[font_name].faces[face_name].missing_glyphs:
|
||||
fonts[font_name].faces[face_name].missing_glyphs.append(glyph_id)
|
||||
return []
|
||||
|
||||
return glyphs_for_id
|
||||
|
||||
|
||||
def get_glyph(font_name, face_name, glyph_id, alternate=0):
|
||||
"""add_glyph adds a glyph to a FontFace
|
||||
it creates the :class:`Font` and :class:`FontFace` if it does not exist yet
|
||||
|
@ -218,25 +280,22 @@ def get_glyph(font_name, face_name, glyph_id, alternate=0):
|
|||
:rtype: `Object`
|
||||
"""
|
||||
|
||||
if not fonts.keys().__contains__(font_name):
|
||||
# print(f"ABC3D::get_glyph: font name({font_name}) not found")
|
||||
# print(fonts.keys())
|
||||
glyphs = get_glyphs(font_name, face_name, glyph_id)
|
||||
|
||||
if len(glyphs) <= alternate or len(glyphs) == 0:
|
||||
print(
|
||||
f"ABC3D::get_glyph: font({font_name}) face({face_name}) glyph({glyph_id})[{alternate}] not found"
|
||||
)
|
||||
return None
|
||||
|
||||
face = fonts[font_name].faces.get(face_name)
|
||||
if face is None:
|
||||
# print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) not found")
|
||||
# print(fonts[font_name].faces.keys())
|
||||
return None
|
||||
return glyphs[alternate]
|
||||
|
||||
glyphs_for_id = face.glyphs.get(glyph_id)
|
||||
if glyphs_for_id is None or len(glyphs_for_id) <= alternate:
|
||||
# print(f"ABC3D::get_glyph: font({font_name}) face({face_name}) glyph({glyph_id})[{alternate}] not found")
|
||||
if glyph_id not in fonts[font_name].faces[face_name].missing_glyphs:
|
||||
fonts[font_name].faces[face_name].missing_glyphs.append(glyph_id)
|
||||
return None
|
||||
|
||||
return fonts[font_name].faces[face_name].glyphs.get(glyph_id)[alternate]
|
||||
class GlyphsAvailability(NamedTuple):
|
||||
loaded: str
|
||||
missing: str
|
||||
unloaded: str
|
||||
filepaths: list[str]
|
||||
|
||||
|
||||
def test_glyphs_availability(font_name, face_name, text):
|
||||
|
@ -245,24 +304,24 @@ def test_glyphs_availability(font_name, face_name, text):
|
|||
not fonts.keys().__contains__(font_name)
|
||||
or fonts[font_name].faces.get(face_name) is None
|
||||
):
|
||||
return "", "", text # <loaded>, <missing>, <maybe>
|
||||
return GlyphsAvailability("", "", "", [])
|
||||
|
||||
loaded = []
|
||||
missing = []
|
||||
maybe = []
|
||||
unloaded = []
|
||||
for c in text:
|
||||
if c in fonts[font_name].faces[face_name].loaded_glyphs:
|
||||
loaded.append(c)
|
||||
elif c in fonts[font_name].faces[face_name].glyphs_in_fontfile:
|
||||
maybe.append(c)
|
||||
unloaded.append(c)
|
||||
else:
|
||||
if c not in fonts[font_name].faces[face_name].missing_glyphs:
|
||||
fonts[font_name].faces[face_name].missing_glyphs.append(c)
|
||||
missing.append(c)
|
||||
return (
|
||||
return GlyphsAvailability(
|
||||
"".join(loaded),
|
||||
"".join(missing),
|
||||
"".join(maybe),
|
||||
"".join(unloaded),
|
||||
fonts[font_name].faces[face_name].filepaths,
|
||||
)
|
||||
|
||||
|
@ -288,15 +347,10 @@ def test_availability(font_name, face_name, text):
|
|||
return MISSING_FONT
|
||||
if fonts[font_name].faces.get(face_name) is None:
|
||||
return MISSING_FACE
|
||||
loaded, missing, maybe, filepaths = test_glyphs_availability(
|
||||
availability: GlyphsAvailability = test_glyphs_availability(
|
||||
font_name, face_name, text
|
||||
)
|
||||
return {
|
||||
"loaded": loaded,
|
||||
"missing": missing,
|
||||
"maybe": maybe,
|
||||
"filepaths": filepaths,
|
||||
}
|
||||
return availability
|
||||
|
||||
|
||||
# holds all fonts
|
||||
|
|
|
@ -89,6 +89,26 @@ def printerr(*args, **kwargs):
|
|||
def removeNonAlphabetic(s):
|
||||
return "".join([i for i in s if i.isalpha()])
|
||||
|
||||
import pathlib
|
||||
import os
|
||||
|
||||
def can_create_path(path_str : str):
|
||||
path = pathlib.Path(path_str).absolute().resolve()
|
||||
|
||||
while True: # this looks dangerours, but it actually is not
|
||||
if path.exists():
|
||||
if os.access(path, os.W_OK):
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
elif path == path.parent:
|
||||
# should never be reached, because root exists
|
||||
# but if it doesn't.. well then we can't
|
||||
return False
|
||||
|
||||
path = path.parent
|
||||
|
||||
|
||||
|
||||
# # Evaluate a bezier curve for the parameter 0<=t<=1 along its length
|
||||
# def evaluateBezierPoint(p1, h1, h2, p2, t):
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue