Python RGB Matrix games and animations https://www.xythobuz.de/ledmatrix_v2.html
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

draw.py 6.2KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. #!/usr/bin/env python3
  2. # Uses the Python BDF format bitmap font parser:
  3. # https://github.com/tomchen/bdfparser
  4. #
  5. # And the pillow Python Imaging Library:
  6. # https://github.com/python-pillow/Pillow
  7. #
  8. # ----------------------------------------------------------------------------
  9. # "THE BEER-WARE LICENSE" (Revision 42):
  10. # <xythobuz@xythobuz.de> wrote this file. As long as you retain this notice
  11. # you can do whatever you want with this stuff. If we meet some day, and you
  12. # think this stuff is worth it, you can buy me a beer in return. Thomas Buck
  13. # ----------------------------------------------------------------------------
  14. from bdfparser import Font
  15. from PIL import Image
  16. import os
  17. import time
  18. class DrawText:
  19. def __init__(self, g, fg = (255, 255, 255), bg = (0, 0, 0), c = (0, 255, 0)):
  20. self.gui = g
  21. self.fg = fg
  22. self.bg = bg
  23. self.color = c
  24. scriptDir = os.path.dirname(os.path.realpath(__file__))
  25. fontDir = os.path.join(scriptDir, "fonts")
  26. self.fonts = {}
  27. for f in os.listdir(os.fsencode(fontDir)):
  28. filename = os.fsdecode(f)
  29. if not filename.lower().endswith(".bdf"):
  30. continue
  31. # TODO hard-coded per-font offsets and spacing adjustment
  32. offset = 0
  33. spacing = 0
  34. if filename == "iv18x16u.bdf":
  35. offset = 6
  36. elif filename == "ib8x8u.bdf":
  37. offset = 10
  38. elif filename == "lemon.bdf":
  39. offset = 8
  40. spacing = -3
  41. elif filename == "antidote.bdf":
  42. offset = 9
  43. spacing = -1
  44. elif filename == "uushi.bdf":
  45. offset = 8
  46. spacing = -2
  47. elif filename == "tom-thumb.bdf":
  48. offset = 12
  49. spacing = 2
  50. # center vertically, in case of
  51. # multiple stacked panels
  52. # TODO hard-coded offsets assume 32x32 panels
  53. if self.gui.height > 32:
  54. offset += 16
  55. font = Font(os.path.join(fontDir, filename))
  56. data = (font, offset, {}, spacing)
  57. self.fonts[filename[:-4]] = data
  58. def getGlyph(self, c, font):
  59. if not isinstance(font, str):
  60. # fall-back to first available font
  61. f, offset, cache, spacing = next(iter(self.fonts))
  62. else:
  63. # users font choice
  64. f, offset, cache, spacing = self.fonts[font]
  65. # only render glyphs once, cache resulting image data
  66. if not c in cache:
  67. g = f.glyph(c).draw()
  68. # invert color
  69. g = g.replace(1, 2).replace(0, 1).replace(2, 0)
  70. # render to pixel data
  71. bytesdict = {
  72. 0: int(self.fg[2] << 16 | self.fg[1] << 8 | self.fg[0]).to_bytes(4, byteorder = "little"),
  73. 1: int(self.bg[2] << 16 | self.bg[1] << 8 | self.bg[0]).to_bytes(4, byteorder = "little"),
  74. 2: int(self.color[2] << 16 | self.color[1] << 8 | self.color[0]).to_bytes(4, byteorder = "little"),
  75. }
  76. img = Image.frombytes('RGBA',
  77. (g.width(), g.height()),
  78. g.tobytes('RGBA', bytesdict))
  79. cache[c] = img
  80. return (cache[c], offset, spacing)
  81. def drawGlyph(self, g, xOff, yOff, spacing):
  82. if xOff >= self.gui.width:
  83. return
  84. for x in range(0, g.width):
  85. for y in range(0, g.height):
  86. xTarget = xOff + x
  87. if (xTarget < 0) or (xTarget >= self.gui.width):
  88. continue
  89. p = g.getpixel((x, y))
  90. self.gui.set_pixel(xTarget, yOff + y, p)
  91. for x in range(0, spacing):
  92. for y in range(0, g.height):
  93. self.gui.set_pixel(xOff + x + g.width, yOff + y, self.bg)
  94. def text(self, s, f, offset = 0, earlyAbort = True, yOff = 0):
  95. w = 0
  96. for c in s:
  97. xOff = -offset + w
  98. if earlyAbort:
  99. if xOff >= self.gui.width:
  100. break
  101. g, y, spacing = self.getGlyph(c, f)
  102. w += g.width + spacing
  103. if xOff >= -16: # some wiggle room so chars dont disappear
  104. self.drawGlyph(g, xOff, y + yOff, spacing)
  105. return w
  106. class ScrollText:
  107. def __init__(self, g, t, f, i = 1, s = 75, fg = (255, 255, 255), bg = (0, 0, 0)):
  108. self.gui = g
  109. self.drawer = DrawText(self.gui, fg, bg)
  110. self.iterations = i
  111. self.speed = 1.0 / s
  112. self.setText(t, f)
  113. self.restart()
  114. def setText(self, t, f):
  115. self.text = t
  116. self.font = f
  117. self.width = self.drawer.text(self.text, self.font, 0, False)
  118. def restart(self):
  119. self.offset = -self.gui.width
  120. self.last = time.time()
  121. self.count = 0
  122. def finished(self):
  123. return (self.count >= self.iterations)
  124. def draw(self):
  125. if (time.time() - self.last) > self.speed:
  126. off = (time.time() - self.last) / self.speed
  127. self.offset += int(off)
  128. self.last = time.time()
  129. if self.offset >= self.width:
  130. self.offset = -self.gui.width
  131. self.count += 1
  132. self.drawer.text(self.text, self.font, self.offset, True)
  133. if __name__ == "__main__":
  134. import util
  135. t = util.getTarget()
  136. from splash import SplashScreen
  137. splash = SplashScreen(t)
  138. t.loop_start()
  139. splash.draw()
  140. t.loop_end()
  141. from manager import Manager
  142. m = Manager(t)
  143. m.add(ScrollText(t, "tom-thumb Abcdefgh tom-thumb", "tom-thumb",
  144. 1, 75, (0, 255, 0), (0, 0, 25)))
  145. m.add(ScrollText(t, "antidote Abcdefgh antidote", "antidote",
  146. 1, 75, (0, 255, 0), (0, 0, 25)))
  147. m.add(ScrollText(t, "uushi Abcdefgh uushi", "uushi",
  148. 1, 75, (0, 255, 0), (0, 0, 25)))
  149. m.add(ScrollText(t, "lemon Abcdefgh lemon", "lemon",
  150. 1, 75, (0, 255, 0), (0, 0, 25)))
  151. m.add(ScrollText(t, "ib8x8u Abcdefgh ib8x8u", "ib8x8u",
  152. 1, 75, (0, 255, 0), (0, 0, 25)))
  153. m.add(ScrollText(t, "iv18x16u Abcdefgh iv18x16u", "iv18x16u",
  154. 1, 75, (0, 255, 0), (0, 0, 25)))
  155. m.restart()
  156. t.loop(m.draw)