Python RGB Matrix games and animations https://www.xythobuz.de/ledmatrix_v2.html
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符

draw.py 6.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  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. font = Font(os.path.join(fontDir, filename))
  51. data = (font, offset, {}, spacing)
  52. self.fonts[filename[:-4]] = data
  53. def getGlyph(self, c, font):
  54. if not isinstance(font, str):
  55. # fall-back to first available font
  56. f, offset, cache, spacing = next(iter(self.fonts))
  57. else:
  58. # users font choice
  59. f, offset, cache, spacing = self.fonts[font]
  60. # only render glyphs once, cache resulting image data
  61. if not c in cache:
  62. g = f.glyph(c).draw()
  63. # invert color
  64. g = g.replace(1, 2).replace(0, 1).replace(2, 0)
  65. # render to pixel data
  66. bytesdict = {
  67. 0: int(self.fg[2] << 16 | self.fg[1] << 8 | self.fg[0]).to_bytes(4, byteorder = "little"),
  68. 1: int(self.bg[2] << 16 | self.bg[1] << 8 | self.bg[0]).to_bytes(4, byteorder = "little"),
  69. 2: int(self.color[2] << 16 | self.color[1] << 8 | self.color[0]).to_bytes(4, byteorder = "little"),
  70. }
  71. img = Image.frombytes('RGBA',
  72. (g.width(), g.height()),
  73. g.tobytes('RGBA', bytesdict))
  74. cache[c] = img
  75. return (cache[c], offset, spacing)
  76. def drawGlyph(self, g, xOff, yOff, spacing):
  77. if xOff >= self.gui.width:
  78. return
  79. for x in range(0, g.width):
  80. for y in range(0, g.height):
  81. xTarget = xOff + x
  82. if (xTarget < 0) or (xTarget >= self.gui.width):
  83. continue
  84. p = g.getpixel((x, y))
  85. self.gui.set_pixel(xTarget, yOff + y, p)
  86. for x in range(0, spacing):
  87. for y in range(0, g.height):
  88. self.gui.set_pixel(xOff + x + g.width, yOff + y, self.bg)
  89. def text(self, s, f, offset = 0, earlyAbort = True, yOff = 0):
  90. w = 0
  91. for c in s:
  92. xOff = -offset + w
  93. if earlyAbort:
  94. if xOff >= self.gui.width:
  95. break
  96. g, y, spacing = self.getGlyph(c, f)
  97. w += g.width + spacing
  98. if xOff >= -16: # some wiggle room so chars dont disappear
  99. self.drawGlyph(g, xOff, y + yOff, spacing)
  100. return w
  101. class ScrollText:
  102. def __init__(self, g, t, f, i = 1, s = 75, fg = (255, 255, 255), bg = (0, 0, 0)):
  103. self.gui = g
  104. self.drawer = DrawText(self.gui, fg, bg)
  105. self.text = t
  106. self.font = f
  107. self.iterations = i
  108. self.speed = 1.0 / s
  109. self.width = self.drawer.text(self.text, self.font, 0, False)
  110. self.restart()
  111. def restart(self):
  112. self.offset = -self.gui.width
  113. self.last = time.time()
  114. self.count = 0
  115. def finished(self):
  116. return (self.count >= self.iterations)
  117. def draw(self):
  118. if (time.time() - self.last) > self.speed:
  119. off = (time.time() - self.last) / self.speed
  120. self.offset += int(off)
  121. self.last = time.time()
  122. if self.offset >= self.width:
  123. self.offset = -self.gui.width
  124. self.count += 1
  125. self.drawer.text(self.text, self.font, self.offset, True)
  126. if __name__ == "__main__":
  127. import util
  128. t = util.getTarget()
  129. from splash import SplashScreen
  130. splash = SplashScreen(t)
  131. t.loop_start()
  132. splash.draw()
  133. t.loop_end()
  134. from manager import Manager
  135. m = Manager(t)
  136. m.add(ScrollText(t, "tom-thumb Abcdefgh tom-thumb", "tom-thumb",
  137. 1, 75, (0, 255, 0), (0, 0, 255)))
  138. m.add(ScrollText(t, "antidote Abcdefgh antidote", "antidote",
  139. 1, 75, (0, 255, 0), (0, 0, 255)))
  140. m.add(ScrollText(t, "uushi Abcdefgh uushi", "uushi",
  141. 1, 75, (0, 255, 0), (0, 0, 255)))
  142. m.add(ScrollText(t, "lemon Abcdefgh lemon", "lemon",
  143. 1, 75, (0, 255, 0), (0, 0, 255)))
  144. m.add(ScrollText(t, "ib8x8u Abcdefgh ib8x8u", "ib8x8u",
  145. 1, 75, (0, 255, 0), (0, 0, 255)))
  146. m.add(ScrollText(t, "iv18x16u Abcdefgh iv18x16u", "iv18x16u",
  147. 1, 75, (0, 255, 0), (0, 0, 255)))
  148. m.restart()
  149. t.debug_loop(m.draw)