g13gui: Add LPBM image conversion and tests

This is the first step to actually rendering to the G13's display by way of the
g13d daemon. The bitmap format is kinda weird: it's actually 860 bytes of
useable pixel data, but padded out to 960. Each byte corresponds with one
vertical column of 8-pixels, going from top to bottom.

The tests for this effectively check to make sure the length is correct, and
also dumps it out to a running g13d (if there is one). This should probably be
automated a bit more by checking the bytes directly, but given that this is a
visual task anyway, I'm being a bit lazy.
This commit is contained in:
June Tate-Gans 2021-04-29 20:20:15 -05:00
parent a38048ea9f
commit aeced13908
5 changed files with 106 additions and 23 deletions

View File

@ -1,3 +1,4 @@
from g13gui.bitwidgets.display import Fonts
from g13gui.bitwidgets.display import FontManager
from g13gui.bitwidgets.fonts import Fonts
from g13gui.bitwidgets.fonts import FontManager
from g13gui.bitwidgets.display import Display
from g13gui.bitwidgets.display import DisplayMetrics

View File

@ -1,12 +1,51 @@
import struct
import PIL.ImageDraw
import PIL.PyAccess
import sys
from io import BytesIO
from PIL import Image
from PIL.ImageDraw import ImageDraw
from g13gui.observer import Subject
from g13gui.observer import ChangeType
class DisplayMetrics(object):
WIDTH_PIXELS = 160
HEIGHT_PIXELS = 48
HEIGHT_PIXELS = 43
LPBM_LENGTH = 960
def ImageToLPBM(image):
i = PIL.PyAccess.new(image, readonly=True)
bio = BytesIO()
maxBytes = (DisplayMetrics.WIDTH_PIXELS * DisplayMetrics.HEIGHT_PIXELS // 8)
row = 0
col = 0
for byteNum in range(0, maxBytes):
b = int()
if row == 40:
maxSubrow = 3
else:
maxSubrow = 8
for subrow in range(0, maxSubrow):
b |= i[col, row + subrow] << subrow
bio.write(struct.pack('<B', b))
col += 1
if (col % 160) == 0:
col = 0
row += 8
# padding? lpbm files are always 960 bytes, the last bytes are filled with garbage.
bio.write(bytes(LPBM_LENGTH - maxBytes))
return bio.getvalue()
class Display(Subject):
@ -17,7 +56,7 @@ class Display(Subject):
DisplayMetrics.HEIGHT_PIXELS))
def getContext(self):
return ImageDraw.Draw(self._bitmap)
return PIL.ImageDraw.Draw(self._bitmap)
def commit(self):
# convert to LPBM

View File

@ -1,20 +1,29 @@
import unittest
import PIL.Image
from g13gui.bitwidgets.display import LPBM_LENGTH
from g13gui.bitwidgets.display import ImageToLPBM
from g13gui.bitwidgets import Fonts
from g13gui.bitwidgets import FontManager
from g13gui.bitwidgets import Display
from g13gui.bitwidgets import DisplayMetrics
d = Display()
ctx = d.getContext()
class DisplayTests(unittest.TestCase):
def setUp(self):
self.d = Display()
def testConversion(self):
ctx = self.d.getContext()
ctx.text((0, 0), "Hello world!",
font=FontManager.getFont(Fonts.TINY),
fill=(1))
ctx.text((0, 6), "Hello world!",
font=FontManager.getFont(Fonts.MEDIUM),
fill=(1))
ctx.text((0, 11), "Hello world!",
font=FontManager.getFont(Fonts.LARGE),
fill=(1))
ctx.text((0, 19), "Hello world!",
font=FontManager.getFont(Fonts.HUGE),
fill=(1))
d.debug()
font=FontManager.getFont(Fonts.HUGE), fill=1)
result = ImageToLPBM(self.d._bitmap)
self.assertEqual(len(result), LPBM_LENGTH)
with open('/run/g13d/in', 'wb') as fp:
fp.write(result)
if __name__ == '__main__':
unittest.main()

View File

@ -26,9 +26,10 @@ X11_FONT_PATH = pathlib.Path('/usr/share/fonts/X11/misc')
class Fonts(enum.Enum):
TINY = X11_FONT_PATH / '4x6.pcf.gz'
MEDIUM = X11_FONT_PATH / '5x7.pcf.gz'
LARGE = X11_FONT_PATH / '8x13.pcf.gz'
HUGE = X11_FONT_PATH / '9x18.pcf.gz'
SMALL = X11_FONT_PATH / '5x7.pcf.gz'
MEDIUM = X11_FONT_PATH / '8x13.pcf.gz'
LARGE = X11_FONT_PATH / '9x18.pcf.gz'
HUGE = X11_FONT_PATH / '10x20.pcf.gz'
class PcfFontConverter(PcfFontFile):

View File

@ -0,0 +1,33 @@
#!/usr/bin/python
import unittest
from g13gui.bitwidgets import Fonts
from g13gui.bitwidgets import FontManager
from g13gui.bitwidgets import Display
class FontsTests(unittest.TestCase):
def testFontDrawing(self):
d = Display()
ctx = d.getContext()
ctx.text((0, 0), "Hello world!",
font=FontManager.getFont(Fonts.TINY),
fill=(1))
ctx.text((0, 6), "Hello world!",
font=FontManager.getFont(Fonts.SMALL),
fill=(1))
ctx.text((0, 11), "Hello world!",
font=FontManager.getFont(Fonts.MEDIUM),
fill=(1))
ctx.text((0, 19), "Hello world!",
font=FontManager.getFont(Fonts.LARGE),
fill=(1))
ctx.text((0, 31), "Hello world!",
font=FontManager.getFont(Fonts.HUGE),
fill=(1))
d.debug()
if __name__ == '__main__':
unittest.main()