classes.c15_kern_table
1from loguru import logger 2from fontTools.ttLib import TTFont 3 4 5class KKernTable: 6 def __init__(self, fontPath: str): 7 self.fontPath = fontPath 8 self.font = TTFont(fontPath) 9 self.kerningPairs = self.prepareKerningTable() 10 11 def prepareKerningTable(self): 12 """Prepare kerning data structure for quick lookup.""" 13 kerning = {} 14 if "GPOS" not in self.font: 15 print("No GPOS table found") 16 self.kerningPairs = kerning 17 return 18 19 gpos = self.font["GPOS"].table 20 for lookup in gpos.LookupList.Lookup: 21 if lookup.LookupType == 2: # Pair Adjustment 22 for subtable in lookup.SubTable: 23 # Format 1: PairSet 24 if ( 25 hasattr(subtable, "Format") 26 and subtable.Format == 1 27 and hasattr(subtable, "PairSet") 28 ): 29 left_glyphs = subtable.Coverage.glyphs 30 for idx, left in enumerate(left_glyphs): 31 pairSet = subtable.PairSet[idx] 32 for pairValueRecord in pairSet.PairValueRecord: 33 right = pairValueRecord.SecondGlyph 34 value = pairValueRecord.Value1.XAdvance or 0 35 kerning[(left, right)] = value 36 # Format 2: Class-based 37 elif ( 38 hasattr(subtable, "Format") 39 and subtable.Format == 2 40 and hasattr(subtable, "Class1Record") 41 ): 42 classDef1 = subtable.ClassDef1.classDefs 43 classDef2 = subtable.ClassDef2.classDefs 44 class1Records = subtable.Class1Record 45 for left, class1 in classDef1.items(): 46 for right, class2 in classDef2.items(): 47 valueRecord = class1Records[class1].Class2Record[class2] 48 if valueRecord.Value1 and valueRecord.Value1.XAdvance: 49 value = valueRecord.Value1.XAdvance 50 kerning[(left, right)] = value 51 return kerning 52 53 def findKerningForPair(self, left: str, right: str) -> int | None: 54 """Quickly look up kerning value for a given glyph pair.""" 55 return self.kerningPairs.get((left, right)) 56 57 def findKerningForString(self, text: str) -> int | None: 58 if len(text) > 2: 59 logger.warning( 60 f"Input string '{text}' has more than 2 characters. Only the first two will be considered." 61 ) 62 63 if len(text) >= 2: 64 return self.findKerningForPair(text[0], text[1]) 65 else: 66 return None
class
KKernTable:
6class KKernTable: 7 def __init__(self, fontPath: str): 8 self.fontPath = fontPath 9 self.font = TTFont(fontPath) 10 self.kerningPairs = self.prepareKerningTable() 11 12 def prepareKerningTable(self): 13 """Prepare kerning data structure for quick lookup.""" 14 kerning = {} 15 if "GPOS" not in self.font: 16 print("No GPOS table found") 17 self.kerningPairs = kerning 18 return 19 20 gpos = self.font["GPOS"].table 21 for lookup in gpos.LookupList.Lookup: 22 if lookup.LookupType == 2: # Pair Adjustment 23 for subtable in lookup.SubTable: 24 # Format 1: PairSet 25 if ( 26 hasattr(subtable, "Format") 27 and subtable.Format == 1 28 and hasattr(subtable, "PairSet") 29 ): 30 left_glyphs = subtable.Coverage.glyphs 31 for idx, left in enumerate(left_glyphs): 32 pairSet = subtable.PairSet[idx] 33 for pairValueRecord in pairSet.PairValueRecord: 34 right = pairValueRecord.SecondGlyph 35 value = pairValueRecord.Value1.XAdvance or 0 36 kerning[(left, right)] = value 37 # Format 2: Class-based 38 elif ( 39 hasattr(subtable, "Format") 40 and subtable.Format == 2 41 and hasattr(subtable, "Class1Record") 42 ): 43 classDef1 = subtable.ClassDef1.classDefs 44 classDef2 = subtable.ClassDef2.classDefs 45 class1Records = subtable.Class1Record 46 for left, class1 in classDef1.items(): 47 for right, class2 in classDef2.items(): 48 valueRecord = class1Records[class1].Class2Record[class2] 49 if valueRecord.Value1 and valueRecord.Value1.XAdvance: 50 value = valueRecord.Value1.XAdvance 51 kerning[(left, right)] = value 52 return kerning 53 54 def findKerningForPair(self, left: str, right: str) -> int | None: 55 """Quickly look up kerning value for a given glyph pair.""" 56 return self.kerningPairs.get((left, right)) 57 58 def findKerningForString(self, text: str) -> int | None: 59 if len(text) > 2: 60 logger.warning( 61 f"Input string '{text}' has more than 2 characters. Only the first two will be considered." 62 ) 63 64 if len(text) >= 2: 65 return self.findKerningForPair(text[0], text[1]) 66 else: 67 return None
def
prepareKerningTable(self):
12 def prepareKerningTable(self): 13 """Prepare kerning data structure for quick lookup.""" 14 kerning = {} 15 if "GPOS" not in self.font: 16 print("No GPOS table found") 17 self.kerningPairs = kerning 18 return 19 20 gpos = self.font["GPOS"].table 21 for lookup in gpos.LookupList.Lookup: 22 if lookup.LookupType == 2: # Pair Adjustment 23 for subtable in lookup.SubTable: 24 # Format 1: PairSet 25 if ( 26 hasattr(subtable, "Format") 27 and subtable.Format == 1 28 and hasattr(subtable, "PairSet") 29 ): 30 left_glyphs = subtable.Coverage.glyphs 31 for idx, left in enumerate(left_glyphs): 32 pairSet = subtable.PairSet[idx] 33 for pairValueRecord in pairSet.PairValueRecord: 34 right = pairValueRecord.SecondGlyph 35 value = pairValueRecord.Value1.XAdvance or 0 36 kerning[(left, right)] = value 37 # Format 2: Class-based 38 elif ( 39 hasattr(subtable, "Format") 40 and subtable.Format == 2 41 and hasattr(subtable, "Class1Record") 42 ): 43 classDef1 = subtable.ClassDef1.classDefs 44 classDef2 = subtable.ClassDef2.classDefs 45 class1Records = subtable.Class1Record 46 for left, class1 in classDef1.items(): 47 for right, class2 in classDef2.items(): 48 valueRecord = class1Records[class1].Class2Record[class2] 49 if valueRecord.Value1 and valueRecord.Value1.XAdvance: 50 value = valueRecord.Value1.XAdvance 51 kerning[(left, right)] = value 52 return kerning
Prepare kerning data structure for quick lookup.
def
findKerningForPair(self, left: str, right: str) -> int | None:
54 def findKerningForPair(self, left: str, right: str) -> int | None: 55 """Quickly look up kerning value for a given glyph pair.""" 56 return self.kerningPairs.get((left, right))
Quickly look up kerning value for a given glyph pair.
def
findKerningForString(self, text: str) -> int | None:
58 def findKerningForString(self, text: str) -> int | None: 59 if len(text) > 2: 60 logger.warning( 61 f"Input string '{text}' has more than 2 characters. Only the first two will be considered." 62 ) 63 64 if len(text) >= 2: 65 return self.findKerningForPair(text[0], text[1]) 66 else: 67 return None