Skip to content

Commit 1f320f2

Browse files
committed
Squares squares squares
1 parent 35f2a9f commit 1f320f2

13 files changed

Lines changed: 1683 additions & 1205 deletions

xkcd-script/font/xkcd-script.otf

-34.4 KB
Binary file not shown.

xkcd-script/font/xkcd-script.sfd

Lines changed: 1614 additions & 1181 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

xkcd-script/font/xkcd-script.ttf

2.59 KB
Binary file not shown.

xkcd-script/font/xkcd-script.woff

34.1 KB
Binary file not shown.
12.4 KB
Loading
9.56 KB
Loading

xkcd-script/generator/pt4_additional_sources.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,8 @@ def extract_symbol(arr, y0, y1, x0, x1, name, exclude=None):
154154

155155
# Each entry is (output_name, source_filename_stem).
156156
EXTRAS = [
157+
('notdef', '1913_i_2x__notdef'), # .notdef fallback glyph source
158+
('square', '2251_alignment_chart_2x__square'), # □ U+25A1 source
157159
('eszett', 'eszett'), # ß U+00DF / ẞ U+1E9E source
158160
('lambda', '1145_sky_color_2x__lambda'), # λ U+03BB source
159161
('tau', '2520_symbols_2x__tau'), # τ U+03C4 source

xkcd-script/generator/pt5_svg_to_font.py

Lines changed: 36 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -317,26 +317,9 @@ def charname(char):
317317
c = font.createMappedChar(32)
318318
c.width = 256
319319

320-
# recommended by OpenType specification
321-
c = font.createChar(-1, '.notdef')
322-
c.addReference('question', psMat.compose(psMat.scale(0.5), psMat.translate(font.ascent * 0.25, font.ascent * 0.25)))
323-
c.unlinkRef()
324-
c.width = round(font.em * 0.6)
325-
pen = c.glyphPen(replace=False)
326-
pen.moveTo(20, 20)
327-
pen.lineTo((c.width - 20, 20))
328-
pen.lineTo((c.width - 20, font.ascent - 20))
329-
pen.lineTo((20, font.ascent - 20))
330-
pen.lineTo((20, 20))
331-
pen.lineTo((60, 60))
332-
pen.lineTo((60, font.ascent - 60))
333-
pen.lineTo((c.width - 60, font.ascent - 60))
334-
pen.lineTo((c.width - 60, 60))
335-
pen.lineTo((60, 60))
336-
pen.closePath()
337-
c = font.createChar(0x0000, '.null')
320+
c = font.createChar(0x0000, '.null') # U+0000: null, zero-width; required by OpenType
338321
c.width = 256
339-
c = font.createChar(0x000D, 'nonmarkingreturn')
322+
c = font.createChar(0x000D, 'nonmarkingreturn') # U+000D: carriage return, zero-width; required by OpenType
340323
c.width = 256
341324

342325

@@ -413,6 +396,23 @@ def _import_comic_glyph(font, name, svg_path, target_top, weight_delta=0):
413396
return g
414397

415398

399+
# .notdef is shown for any codepoint the font doesn't cover; OpenType requires it.
400+
# Hand-drawn source: xkcd #1913 (I), a sketchy question-mark-in-a-box.
401+
_notdef_svg = os.path.join(_COMIC_CHARS_DIR, 'notdef.svg')
402+
_notdef_src = _import_comic_glyph(font, 'notdef', _notdef_svg, target_top=font.ascent, weight_delta=20)
403+
_bb = _notdef_src.boundingBox()
404+
_notdef_src.transform(psMat.translate(0, -_bb[1]))
405+
_bb = _notdef_src.boundingBox()
406+
if _bb[3] > 0:
407+
_notdef_src.transform(psMat.scale(font.ascent / _bb[3]))
408+
_notdef_src.width = int(round(_notdef_src.boundingBox()[2] + 20))
409+
c = font.createChar(-1, '.notdef')
410+
c.clear()
411+
for _cont in _notdef_src.foreground:
412+
c.foreground += _cont
413+
c.width = _notdef_src.width
414+
415+
416416
# Greek letters vectorised by pt4 from xkcd comic images.
417417
# Each entry: (svg_name, unicode_cp, ref_char_for_height, baseline_snap)
418418
# baseline_snap=True → translate so bb[1]=0 (letters that sit on the baseline).
@@ -614,6 +614,23 @@ def _import_comic_glyph(font, name, svg_path, target_top, weight_delta=0):
614614
_ch.width = _g.width
615615

616616

617+
# □ U+25A1 WHITE SQUARE — hand-drawn source from extras/square.png.
618+
_square_svg = os.path.join(_COMIC_CHARS_DIR, 'square.svg')
619+
_target_top_sq = font['H'].boundingBox()[3]
620+
_square_src = _import_comic_glyph(font, 'square', _square_svg, target_top=_target_top_sq, weight_delta=45)
621+
_bb = _square_src.boundingBox()
622+
_square_src.transform(psMat.translate(0, -_bb[1]))
623+
_bb = _square_src.boundingBox()
624+
if _bb[3] > 0:
625+
_square_src.transform(psMat.scale(_target_top_sq / _bb[3]))
626+
_square_src.width = int(round(_square_src.boundingBox()[2] + 20))
627+
_ch = font.createMappedChar(0x25A1)
628+
_ch.clear()
629+
for _cont in _square_src.foreground:
630+
_ch.foreground += _cont
631+
_ch.width = _square_src.width
632+
633+
617634
# ---------------------------------------------------------------------------
618635
# Save
619636
# ---------------------------------------------------------------------------

xkcd-script/generator/pt6_derived_chars.py

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -212,12 +212,29 @@ def _accented(cp, base_name, mark_name, gap=20, x_adj=0):
212212
# Glyph aliases and re-uses
213213
# ---------------------------------------------------------------------------
214214

215+
# U+20DE COMBINING ENCLOSING SQUARE — zero-width mark sized and positioned to
216+
# enclose '?' with a small margin. GPOS would be needed for full generality.
217+
_sq = font[0x25A1]
218+
_sq_bb = _sq.boundingBox()
219+
_sq_cx = (_sq_bb[0] + _sq_bb[2]) / 2
220+
_sq_h = _sq_bb[3] - _sq_bb[1] # sq_bb[1] == 0 after baseline snap
221+
_q_bb = font[ord('?')].boundingBox()
222+
_q_adv = font[ord('?')].width
223+
_margin = 20
224+
_scale_y = (_q_bb[3] - _q_bb[1] + 2 * _margin) / _sq_h
225+
_x_offset = -_q_adv / 2 - _sq_cx
226+
_y_offset = _q_bb[1] - _margin
227+
c = font.createMappedChar(0x20DE)
228+
c.addReference(_sq.glyphname, psMat.compose(
229+
psMat.scale(1, _scale_y),
230+
psMat.translate(_x_offset, _y_offset),
231+
))
232+
c.width = 0
233+
215234
# Vertical pipe: re-use the I glyph (same stroke, same weight).
216-
font.selection.select('I')
217-
font.copy()
218235
c = font.createChar(-1, 'I.sansserif')
219-
font.selection.select(c)
220-
font.paste()
236+
c.addReference('I')
237+
c.width = font['I'].width
221238
pipe = font.createMappedChar(ord('|'))
222239
pipe.clear()
223240
pipe.addReference('I.sansserif', psMat.compose(psMat.scale(1, 1.3), psMat.translate(0, -0.2 * font.ascent)))
-25 Bytes
Loading

0 commit comments

Comments
 (0)