classes.c10_font
1from typing import TYPE_CHECKING, Optional 2import drawBot 3import colorama 4from loguru import logger 5from icecream import ic 6 7from lib import fonts as libFonts 8 9# Avoid circular import issues, hide from runtime, but keep for type checking 10if TYPE_CHECKING: 11 from .c11_family import KFamily 12 13 14class KFont: 15 """ 16 Represents a single font and provides methods for font analysis and manipulation. 17 18 Usually grouped into `classes.c11_family.KFamily`. 19 """ 20 21 fullName: str 22 """Full name of font: `Stabil Grotesk 400 Regular`""" 23 familyName: str 24 """Family name of font: `Stabil Grotesk`""" 25 styleName: str 26 """Style name of font: `Regular`""" 27 shortName: str 28 """Short name of font: `400 Regular`""" 29 styleNumber: str | None 30 """Style number of font: `400`""" 31 32 def __init__(self, path: str, family: Optional["KFamily"] = None): 33 """ 34 Initialize a KFont instance. 35 36 Args: 37 path: Path to the font file. 38 family: Family this font belongs to (optional). See `classes.c11_family.KFamily`. 39 """ 40 self.path = path 41 """File system path to the font file""" 42 43 if family: 44 self.family = family 45 46 names = libFonts.parseNameObject(path, separate=True) 47 for [name, value] in names._asdict().items(): 48 setattr(self, name, value) 49 50 def __str__(self) -> str: 51 """Return a string representation of the KFont instance.""" 52 return f"{colorama.Fore.BLACK}{colorama.Back.LIGHTGREEN_EX}KFont{colorama.Style.RESET_ALL} {self.fullName}" 53 54 @property 55 def fontType(self): 56 """ 57 Get the font type based on the style number. 58 59 Returns: 60 The font type as determined by `lib.fonts.getFontType`. 61 """ 62 try: 63 return libFonts.getFontType(self.styleNumber) 64 except Exception as e: 65 logger.warning(f"[KFont] Error getting font type: {e}") 66 return None 67 68 @property 69 def version(self) -> str: 70 """Returns the version of the font as a string.""" 71 return libFonts.getFontVersion(self.path) 72 73 def isType(self, criteria: libFonts.FontType) -> bool: 74 """ 75 Check if the font matches given `lib.fonts.FontType` criteria: 76 77 ``` 78 upright \\d0 79 italic \\d5 80 display [^4-6] 81 text [4-6] 82 thin [1-3] 83 thick [7-9] 84 ``` 85 86 Args: 87 criteria: The font type to check (e.g., 'upright', 'italic', etc.). 88 89 Returns: 90 True if the font matches the criteria, False otherwise. 91 """ 92 return criteria in self.fontType 93 94 def getSibling(self) -> Optional["KFont"]: 95 """ 96 Get the sibling font with a related style number. 97 98 Example: 99 `400` => `450` 100 101 Returns: 102 The sibling KFont instance if found, otherwise None. 103 """ 104 prefix = self.styleNumber[0] 105 suffix = "5" if self.isType("upright") else "0" 106 # Adjust to correct length: 40 => 45, 400 => 450 107 adjusted = (prefix + suffix).ljust(len(self.styleNumber), "0") 108 siblingNumber = int(adjusted) 109 try: 110 return self.family.get(criteria=siblingNumber) 111 except Exception as e: 112 logger.warning("[KFont] Error getting sibling: {}", e) 113 return None 114 115 def getWeightClass(self, numeric=False) -> str | int: 116 """ 117 Get the weight class of the font. 118 119 Example: 120 `400` => `4` 121 122 Args: 123 numeric: If True, return as integer; as string otherwise. 124 125 Returns: 126 The weight class as string or integer. 127 """ 128 numberString = self.styleNumber[0] 129 return int(numberString) if numeric else numberString 130 131 def activate(self) -> "KFont": 132 """ 133 Activate this font for use in DrawBot. 134 135 Returns: 136 The KFont instance (self). 137 """ 138 logger.trace("Activating KFont: {}", self.fullName) 139 drawBot.font(self.path) 140 return self 141 142 def hasCharacter(self, character: str) -> bool: 143 """ 144 Check if the font contains a specific glyph. 145 146 Args: 147 glyph: The glyph name to check (e.g., 'A', 'space', 'uniE000'). 148 """ 149 with drawBot.savedState(): 150 self.activate() 151 return drawBot.fontContainsCharacters(character) 152 153 def supportsFeature(self, featureCode: libFonts.FeatureId) -> bool: 154 """ 155 Check if the font supports a specific OpenType feature. 156 157 Args: 158 featureCode: The OpenType feature code to check (e.g., 'ss01', 'liga'). 159 """ 160 return featureCode in drawBot.listOpenTypeFeatures(self.path)
15class KFont: 16 """ 17 Represents a single font and provides methods for font analysis and manipulation. 18 19 Usually grouped into `classes.c11_family.KFamily`. 20 """ 21 22 fullName: str 23 """Full name of font: `Stabil Grotesk 400 Regular`""" 24 familyName: str 25 """Family name of font: `Stabil Grotesk`""" 26 styleName: str 27 """Style name of font: `Regular`""" 28 shortName: str 29 """Short name of font: `400 Regular`""" 30 styleNumber: str | None 31 """Style number of font: `400`""" 32 33 def __init__(self, path: str, family: Optional["KFamily"] = None): 34 """ 35 Initialize a KFont instance. 36 37 Args: 38 path: Path to the font file. 39 family: Family this font belongs to (optional). See `classes.c11_family.KFamily`. 40 """ 41 self.path = path 42 """File system path to the font file""" 43 44 if family: 45 self.family = family 46 47 names = libFonts.parseNameObject(path, separate=True) 48 for [name, value] in names._asdict().items(): 49 setattr(self, name, value) 50 51 def __str__(self) -> str: 52 """Return a string representation of the KFont instance.""" 53 return f"{colorama.Fore.BLACK}{colorama.Back.LIGHTGREEN_EX}KFont{colorama.Style.RESET_ALL} {self.fullName}" 54 55 @property 56 def fontType(self): 57 """ 58 Get the font type based on the style number. 59 60 Returns: 61 The font type as determined by `lib.fonts.getFontType`. 62 """ 63 try: 64 return libFonts.getFontType(self.styleNumber) 65 except Exception as e: 66 logger.warning(f"[KFont] Error getting font type: {e}") 67 return None 68 69 @property 70 def version(self) -> str: 71 """Returns the version of the font as a string.""" 72 return libFonts.getFontVersion(self.path) 73 74 def isType(self, criteria: libFonts.FontType) -> bool: 75 """ 76 Check if the font matches given `lib.fonts.FontType` criteria: 77 78 ``` 79 upright \\d0 80 italic \\d5 81 display [^4-6] 82 text [4-6] 83 thin [1-3] 84 thick [7-9] 85 ``` 86 87 Args: 88 criteria: The font type to check (e.g., 'upright', 'italic', etc.). 89 90 Returns: 91 True if the font matches the criteria, False otherwise. 92 """ 93 return criteria in self.fontType 94 95 def getSibling(self) -> Optional["KFont"]: 96 """ 97 Get the sibling font with a related style number. 98 99 Example: 100 `400` => `450` 101 102 Returns: 103 The sibling KFont instance if found, otherwise None. 104 """ 105 prefix = self.styleNumber[0] 106 suffix = "5" if self.isType("upright") else "0" 107 # Adjust to correct length: 40 => 45, 400 => 450 108 adjusted = (prefix + suffix).ljust(len(self.styleNumber), "0") 109 siblingNumber = int(adjusted) 110 try: 111 return self.family.get(criteria=siblingNumber) 112 except Exception as e: 113 logger.warning("[KFont] Error getting sibling: {}", e) 114 return None 115 116 def getWeightClass(self, numeric=False) -> str | int: 117 """ 118 Get the weight class of the font. 119 120 Example: 121 `400` => `4` 122 123 Args: 124 numeric: If True, return as integer; as string otherwise. 125 126 Returns: 127 The weight class as string or integer. 128 """ 129 numberString = self.styleNumber[0] 130 return int(numberString) if numeric else numberString 131 132 def activate(self) -> "KFont": 133 """ 134 Activate this font for use in DrawBot. 135 136 Returns: 137 The KFont instance (self). 138 """ 139 logger.trace("Activating KFont: {}", self.fullName) 140 drawBot.font(self.path) 141 return self 142 143 def hasCharacter(self, character: str) -> bool: 144 """ 145 Check if the font contains a specific glyph. 146 147 Args: 148 glyph: The glyph name to check (e.g., 'A', 'space', 'uniE000'). 149 """ 150 with drawBot.savedState(): 151 self.activate() 152 return drawBot.fontContainsCharacters(character) 153 154 def supportsFeature(self, featureCode: libFonts.FeatureId) -> bool: 155 """ 156 Check if the font supports a specific OpenType feature. 157 158 Args: 159 featureCode: The OpenType feature code to check (e.g., 'ss01', 'liga'). 160 """ 161 return featureCode in drawBot.listOpenTypeFeatures(self.path)
Represents a single font and provides methods for font analysis and manipulation.
Usually grouped into classes.c11_family.KFamily.
33 def __init__(self, path: str, family: Optional["KFamily"] = None): 34 """ 35 Initialize a KFont instance. 36 37 Args: 38 path: Path to the font file. 39 family: Family this font belongs to (optional). See `classes.c11_family.KFamily`. 40 """ 41 self.path = path 42 """File system path to the font file""" 43 44 if family: 45 self.family = family 46 47 names = libFonts.parseNameObject(path, separate=True) 48 for [name, value] in names._asdict().items(): 49 setattr(self, name, value)
Initialize a KFont instance.
Arguments:
- path: Path to the font file.
- family: Family this font belongs to (optional). See
classes.c11_family.KFamily.
55 @property 56 def fontType(self): 57 """ 58 Get the font type based on the style number. 59 60 Returns: 61 The font type as determined by `lib.fonts.getFontType`. 62 """ 63 try: 64 return libFonts.getFontType(self.styleNumber) 65 except Exception as e: 66 logger.warning(f"[KFont] Error getting font type: {e}") 67 return None
Get the font type based on the style number.
Returns:
The font type as determined by
lib.fonts.getFontType.
69 @property 70 def version(self) -> str: 71 """Returns the version of the font as a string.""" 72 return libFonts.getFontVersion(self.path)
Returns the version of the font as a string.
74 def isType(self, criteria: libFonts.FontType) -> bool: 75 """ 76 Check if the font matches given `lib.fonts.FontType` criteria: 77 78 ``` 79 upright \\d0 80 italic \\d5 81 display [^4-6] 82 text [4-6] 83 thin [1-3] 84 thick [7-9] 85 ``` 86 87 Args: 88 criteria: The font type to check (e.g., 'upright', 'italic', etc.). 89 90 Returns: 91 True if the font matches the criteria, False otherwise. 92 """ 93 return criteria in self.fontType
Check if the font matches given lib.fonts.FontType criteria:
upright \d0
italic \d5
display [^4-6]
text [4-6]
thin [1-3]
thick [7-9]
Arguments:
- criteria: The font type to check (e.g., 'upright', 'italic', etc.).
Returns:
True if the font matches the criteria, False otherwise.
95 def getSibling(self) -> Optional["KFont"]: 96 """ 97 Get the sibling font with a related style number. 98 99 Example: 100 `400` => `450` 101 102 Returns: 103 The sibling KFont instance if found, otherwise None. 104 """ 105 prefix = self.styleNumber[0] 106 suffix = "5" if self.isType("upright") else "0" 107 # Adjust to correct length: 40 => 45, 400 => 450 108 adjusted = (prefix + suffix).ljust(len(self.styleNumber), "0") 109 siblingNumber = int(adjusted) 110 try: 111 return self.family.get(criteria=siblingNumber) 112 except Exception as e: 113 logger.warning("[KFont] Error getting sibling: {}", e) 114 return None
Get the sibling font with a related style number.
Example:
400=>450
Returns:
The sibling KFont instance if found, otherwise None.
116 def getWeightClass(self, numeric=False) -> str | int: 117 """ 118 Get the weight class of the font. 119 120 Example: 121 `400` => `4` 122 123 Args: 124 numeric: If True, return as integer; as string otherwise. 125 126 Returns: 127 The weight class as string or integer. 128 """ 129 numberString = self.styleNumber[0] 130 return int(numberString) if numeric else numberString
Get the weight class of the font.
Example:
400=>4
Arguments:
- numeric: If True, return as integer; as string otherwise.
Returns:
The weight class as string or integer.
132 def activate(self) -> "KFont": 133 """ 134 Activate this font for use in DrawBot. 135 136 Returns: 137 The KFont instance (self). 138 """ 139 logger.trace("Activating KFont: {}", self.fullName) 140 drawBot.font(self.path) 141 return self
Activate this font for use in DrawBot.
Returns:
The KFont instance (self).
143 def hasCharacter(self, character: str) -> bool: 144 """ 145 Check if the font contains a specific glyph. 146 147 Args: 148 glyph: The glyph name to check (e.g., 'A', 'space', 'uniE000'). 149 """ 150 with drawBot.savedState(): 151 self.activate() 152 return drawBot.fontContainsCharacters(character)
Check if the font contains a specific glyph.
Arguments:
- glyph: The glyph name to check (e.g., 'A', 'space', 'uniE000').
154 def supportsFeature(self, featureCode: libFonts.FeatureId) -> bool: 155 """ 156 Check if the font supports a specific OpenType feature. 157 158 Args: 159 featureCode: The OpenType feature code to check (e.g., 'ss01', 'liga'). 160 """ 161 return featureCode in drawBot.listOpenTypeFeatures(self.path)
Check if the font supports a specific OpenType feature.
Arguments:
- featureCode: The OpenType feature code to check (e.g., 'ss01', 'liga').