A general-use 5x7 Unicode font.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

gen.py 2.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. #! /usr/bin/python3
  2. import PIL.Image
  3. import sys
  4. import os
  5. import re
  6. if len(sys.argv) <= 1:
  7. print(f"usage: {sys.argv[0]} <block files...>")
  8. sys.exit(1)
  9. files = sorted(sys.argv[1:])
  10. chars = PIL.Image.open("gen-chars.png")
  11. WHITE = (255, 255, 255)
  12. BLACK = (0, 0, 0)
  13. def empty_separator():
  14. img = PIL.Image.new("RGB", (112, 9), color=WHITE)
  15. for j in range(3, 6):
  16. for i in range(1, 111):
  17. if not ((i + j) & 1):
  18. img.putpixel((i, j), BLACK)
  19. return img
  20. def char_index(c):
  21. o = ord(c)
  22. if ord('0') <= o <= ord('9'):
  23. return o - ord('0')
  24. if ord('A') <= o <= ord('F'):
  25. return o - ord('A') + 10
  26. if c == 'U':
  27. return 16
  28. if c == '+':
  29. return 17
  30. raise Exception(f"Unsupported char '{c}'")
  31. def char_image(c):
  32. index = 4 * char_index(c)
  33. return chars.crop((index, 0, index + 3, 5))
  34. def separator(start, end):
  35. img = PIL.Image.new("RGB", (112, 9), color=WHITE)
  36. for j in range(3, 6):
  37. for i in range(1, 26):
  38. if not ((i + j) & 1):
  39. img.putpixel((i, j), BLACK)
  40. for i in range(86, 111):
  41. if not ((i + j) & 1):
  42. img.putpixel((i, j), BLACK)
  43. x = 27
  44. for c in "U+{:04X}".format(start):
  45. img.paste(char_image(c), (x, 2))
  46. x += 4
  47. for i in range(54, 58):
  48. img.putpixel((i, 4), BLACK)
  49. x = 62
  50. for c in "U+{:04X}".format(end):
  51. img.paste(char_image(c), (x, 2))
  52. x += 4
  53. return img
  54. class Block:
  55. def __init__(self, path):
  56. basename = os.path.basename(path)
  57. match = re.search(r'U\+([0-9A-Za-z]{4})', basename)
  58. self.block_start = None
  59. self.block_end = None
  60. self.img = PIL.Image.open(path)
  61. if match is not None:
  62. self.block_start = int(match[1], 16)
  63. self.block_end = self.block_start + 16 * (self.img.height // 9) - 1
  64. print('{} U+{:04X} - U+{:04X}'.format(basename, self.block_start,
  65. self.block_end))
  66. else:
  67. print(f'{basename} not a block')
  68. def header(self):
  69. if self.block_start is not None:
  70. return separator(self.block_start, self.block_end)
  71. else:
  72. return empty_separator()
  73. def body(self):
  74. return self.img
  75. def height(self):
  76. return self.img.height + 9
  77. blocks = [ Block(file) for file in files ]
  78. height = sum(b.height() for b in blocks)
  79. left_height = 0
  80. for b in blocks:
  81. left_height += b.height()
  82. if 2 * left_height >= height: break
  83. result = PIL.Image.new("RGB", (2 * 112 + 8, left_height), color=WHITE)
  84. x = 0
  85. y = 0
  86. for b in blocks:
  87. header = b.header()
  88. result.paste(header, (x, y))
  89. y += header.height
  90. body = b.body()
  91. result.paste(body, (x, y))
  92. y += body.height
  93. if y >= left_height:
  94. y = 0
  95. x += 112 + 8
  96. result.save("uf5x7.png")