Font that can be used for validating baseline alignments. sajidanwar.com/misc/baseline-diagnostic-font/
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

Add ascent/descent and baselines for vertical text layout

+28 -12
dist/BaselineDiagnostic.ttf

This is a binary file and will not be displayed.

dist/BaselineDiagnosticAlphabeticZero.ttf

This is a binary file and will not be displayed.

+24 -12
font.py
··· 8 8 from fontTools.ttLib import TTFont, getTableClass, newTable 9 9 from fontTools.ttLib.tables import otTables 10 10 11 - EM_ASCENT = 800 12 - EM_DESCENT = 200 13 - EM_SIZE = EM_ASCENT + EM_DESCENT 14 11 BORDER_WIDTH = 12 15 12 16 13 ··· 145 142 draw_dashed_line(pen, y, start, end, stroke_width=stroke_width) 146 143 147 144 148 - def draw_baseline(pen, font, y, label, style="solid", stroke_width=8): 145 + def draw_baseline(pen, font, y, em_size, label, style="solid", stroke_width=8): 149 146 if label: 150 147 drawn_text = draw_text_centered( 151 - pen, font, label, EM_SIZE / 2, y, font_size=50, scale_y=1, letter_gap=0 148 + pen, font, label, em_size / 2, y, font_size=50, scale_y=1, letter_gap=0 152 149 ) 153 150 draw_line( 154 151 pen, ··· 164 161 stroke_width=stroke_width, 165 162 y=y, 166 163 start=drawn_text.x + drawn_text.width + BORDER_WIDTH, 167 - end=EM_SIZE - BORDER_WIDTH, 164 + end=em_size - BORDER_WIDTH, 168 165 ) 169 166 else: 170 167 draw_line( ··· 173 170 stroke_width=stroke_width, 174 171 y=y, 175 172 start=BORDER_WIDTH, 176 - end=EM_SIZE - BORDER_WIDTH, 173 + end=em_size - BORDER_WIDTH, 177 174 ) 178 175 179 176 180 177 def build_baselines_font(font_name: str, out_path: str, baselines: List[FontBaseline]): 178 + ascent = next(baseline.position for baseline in baselines if baseline.id == 'ascent') 179 + descent = next(baseline.position for baseline in baselines if baseline.id == 'descent') 180 + em_size = ascent - descent 181 + 182 + if not ascent or not descent: 183 + raise ValueError(f"Required ascent / descent but got {ascent} / {descent}") 184 + 181 185 empty_glyph_pen = TTGlyphPen(None) 182 - draw_bordered_rectangle(empty_glyph_pen, 0, -EM_DESCENT, EM_SIZE, EM_ASCENT, BORDER_WIDTH) 186 + draw_bordered_rectangle(empty_glyph_pen, 0, descent, em_size, ascent, BORDER_WIDTH) 183 187 184 188 diag_glyph_pen = TTGlyphPen(None) 185 - draw_bordered_rectangle(diag_glyph_pen, 0, -EM_DESCENT, EM_SIZE, EM_ASCENT, BORDER_WIDTH) 189 + draw_bordered_rectangle(diag_glyph_pen, 0, descent, em_size, ascent, BORDER_WIDTH) 186 190 label_font = TTFont("./support/noto/NotoSansMono-Bold.ttf") 187 191 for baseline in baselines: 188 192 if baseline.style: ··· 190 194 diag_glyph_pen, 191 195 label_font, 192 196 baseline.position, 197 + em_size, 193 198 baseline.label, 194 199 style=baseline.style.stroke_style, 195 200 stroke_width=baseline.style.stroke_width, 196 201 ) 197 202 198 - fb = FontBuilder(EM_SIZE, isTTF=True) 203 + fb = FontBuilder(em_size, isTTF=True) 199 204 fb.setupGlyphOrder([".notdef", "X"]) 200 205 fb.setupCharacterMap({ ord("X"): "X" }) 201 206 fb.setupGlyf({ ··· 205 210 206 211 os2_values = dict((base.name, base.position) for base in baselines if base.table == "OS/2") 207 212 hhea_values = dict((base.name, base.position) for base in baselines if base.table == "hhea") 213 + vhea_values = dict((base.name, base.position) for base in baselines if base.table == "vhea") 208 214 209 215 style_name = "Regular" 210 216 fb.setupPost() ··· 217 223 "psName": f"{font_name}-{style_name}", 218 224 "version": "Version 1.0", 219 225 }) 220 - fb.setupHorizontalMetrics({".notdef": (EM_SIZE, 0), "X": (EM_SIZE, 0)}) 226 + fb.setupHorizontalMetrics({".notdef": (em_size, 0), "X": (em_size, 0)}) 221 227 fb.setupOS2(**os2_values) 222 228 fb.setupHorizontalHeader(**hhea_values) 223 - fb.setupHead(unitsPerEm=EM_SIZE) 229 + fb.setupVerticalHeader(**vhea_values) 230 + fb.setupHead(unitsPerEm=em_size) 224 231 225 232 font = fb.font 226 233 bases = list(sorted(filter(lambda base: base.table == "BASE", baselines), key=lambda base: base.name)) ··· 232 239 base_table.HorizAxis.BaseTagList = otTables.BaseTagList() 233 240 base_table.HorizAxis.BaseTagList.BaselineTag = base_names 234 241 base_table.HorizAxis.BaseScriptList = otTables.BaseScriptList() 242 + base_table.VertAxis = otTables.Axis() 243 + base_table.VertAxis.BaseTagList = otTables.BaseTagList() 244 + base_table.VertAxis.BaseTagList.BaselineTag = base_names 245 + base_table.VertAxis.BaseScriptList = otTables.BaseScriptList() 235 246 236 247 base_coords = [] 237 248 for base in bases: ··· 247 258 base_script.BaseScript.BaseValues.DefaultIndex = base_names.index("romn") 248 259 base_script.BaseScript.BaseValues.BaseCoord = base_coords 249 260 base_table.HorizAxis.BaseScriptList.BaseScriptRecord = [base_script] 261 + base_table.VertAxis.BaseScriptList.BaseScriptRecord = [base_script] 250 262 font["BASE"] = newTable("BASE") 251 263 font["BASE"].table = base_table 252 264
+4
main.py
··· 14 14 baselines=[ 15 15 FontBaseline("ascent", 800, "OS/2", "sTypoAscender", None, None), 16 16 FontBaseline("ascent", 800, "hhea", "ascent", None, None), 17 + FontBaseline("ascent", 800, "vhea", "ascent", None, None), 17 18 FontBaseline("ideographic-over", 750, "BASE", "idtp", "IDEOGRAPHIC-OVER", FontBaselineStyle.SOLID), 18 19 FontBaseline("hanging", 650, "BASE", "hang", "HANGING", FontBaselineStyle.SOLID), 19 20 FontBaseline("cap-height", 550, "OS/2", "sCapHeight", "CAP-HEIGHT", FontBaselineStyle.SOLID), ··· 27 28 FontBaseline("ideographic-under", -50, "BASE", "ideo", "IDEOGRAPHIC-UNDER", FontBaselineStyle.SOLID), 28 29 FontBaseline("descent", -200, "OS/2", "sTypoDescender", None, None), 29 30 FontBaseline("descent", -200, "hhea", "descent", None, None), 31 + FontBaseline("descent", -200, "vhea", "descent", None, None), 30 32 ] 31 33 )) 32 34 fonts.append(Font( ··· 37 39 baselines=[ 38 40 FontBaseline("ascent", 800, "OS/2", "sTypoAscender", None, None), 39 41 FontBaseline("ascent", 800, "hhea", "ascent", None, None), 42 + FontBaseline("ascent", 800, "vhea", "ascent", None, None), 40 43 FontBaseline("ideographic-over", 750, "BASE", "idtp", "IDEOGRAPHIC-OVER", FontBaselineStyle.SOLID), 41 44 FontBaseline("hanging", 650, "BASE", "hang", "HANGING", FontBaselineStyle.SOLID), 42 45 FontBaseline("cap-height", 550, "OS/2", "sCapHeight", "CAP-HEIGHT", FontBaselineStyle.SOLID), ··· 50 53 FontBaseline("ideographic-under", -50, "BASE", "ideo", "IDEOGRAPHIC-UNDER", FontBaselineStyle.SOLID), 51 54 FontBaseline("descent", -200, "OS/2", "sTypoDescender", None, None), 52 55 FontBaseline("descent", -200, "hhea", "descent", None, None), 56 + FontBaseline("descent", -200, "vhea", "descent", None, None), 53 57 ] 54 58 )) 55 59