From 0c0084dae93becf8b25eb206976cbe28e7f609fc Mon Sep 17 00:00:00 2001 From: Jonathan Dahan Date: Wed, 1 Feb 2023 18:11:46 -0700 Subject: [PATCH 1/8] Add 2bit grayscale support This lets people use framebuf for 2 color displays like the 8x8x2 matrix. It is a mostly mechanical port of the circuitpython GS2_HMSB code. --- adafruit_framebuf.py | 53 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index 7e3ac12..fcca6c1 100755 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -16,6 +16,7 @@ **Hardware:** * `Adafruit SSD1306 OLED displays `_ +* `Adafruit HT16K33 Matrix displays `_ **Software and Dependencies:** @@ -36,7 +37,57 @@ GS4_HMSB = 2 # Unimplemented! MHMSB = 3 # Single bit displays like the Sharp Memory RGB888 = 4 # Neopixels and Dotstars +GS2_HMSB = 5 # 2-bit color displays like the HT16K33 8x8 Matrix +class GS2HMSBFormat: + """GS2HMSBFormat""" + + + @staticmethod + def set_pixel(framebuf, x, y, color): + """Set a given pixel to a color.""" + index = (y * framebuf.stride + x) >> 2 # why 2? + pixel = framebuf.buf[index] + + shift = (x & 0b11) << 1 # why 1? + mask = 0b11 << shift + color = (color & 0b11) << shift + + framebuf.buf[index] = color | (pixel & (~mask)) + + @staticmethod + def get_pixel(framebuf, x, y): + """Get the color of a given pixel""" + index = (y * framebuf.stride + x) >> 2 # same as // 8? why? + pixel = framebuf.buf[index] + + shift = (x & 0b11) << 1 # why 1? + return (pixel >> shift) & 0b11 + + @staticmethod + def fill(framebuf, color): + """completely fill/clear the buffer with a color""" + if color: + fill = color & 0b11 + else: + fill = 0x00 + for i in range(len(framebuf.buf)): # pylint: disable=consider-using-enumerate + framebuf.buf[i] = fill + + @staticmethod + def rect(framebuf, x, y, width, height, color): + """Draw the outline of a rectangle at the given location, size and color.""" + for xx in range(x, x + width): + for yy in range(y, y + height): + if xx in [x, x+width] or yy in [y, y+height]: + GS2HMSBFormat.set_pixel(framebuf, xx, yy, color) + + @staticmethod + def fill_rect(framebuf, x, y, width, height, color): + """Draw both the outline and interior of a rectangle at the given location, size and color.""" + for xx in range(x, x + width): + for yy in range(y, y + height): + GS2HMSBFormat.set_pixel(framebuf, xx, yy, color) class MHMSBFormat: """MHMSBFormat""" @@ -256,6 +307,8 @@ def __init__(self, buf, width, height, buf_format=MVLSB, stride=None): self.format = RGB888Format() elif buf_format == RGB565: self.format = RGB565Format() + elif buf_format == GS2_HMSB: + self.format = GS2HMSBFormat() else: raise ValueError("invalid format") self._rotation = 0 From 6e6f8db423303cc93a95371666f1af8fb587544c Mon Sep 17 00:00:00 2001 From: Jonathan Dahan Date: Sat, 4 Feb 2023 14:09:33 -0500 Subject: [PATCH 2/8] fix pylint warnings --- adafruit_framebuf.py | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index fcca6c1..1117520 100755 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -77,17 +77,19 @@ def fill(framebuf, color): @staticmethod def rect(framebuf, x, y, width, height, color): """Draw the outline of a rectangle at the given location, size and color.""" - for xx in range(x, x + width): - for yy in range(y, y + height): - if xx in [x, x+width] or yy in [y, y+height]: - GS2HMSBFormat.set_pixel(framebuf, xx, yy, color) + # pylint: disable=too-many-arguments + for _x in range(x, x + width): + for _y in range(y, y + height): + if _x in [x, x+width] or _y in [y, y+height]: + GS2HMSBFormat.set_pixel(framebuf, _x, _y, color) @staticmethod def fill_rect(framebuf, x, y, width, height, color): - """Draw both the outline and interior of a rectangle at the given location, size and color.""" - for xx in range(x, x + width): - for yy in range(y, y + height): - GS2HMSBFormat.set_pixel(framebuf, xx, yy, color) + """Draw the outline and interior of a rectangle at the given location, size and color.""" + # pylint: disable=too-many-arguments + for _x in range(x, x + width): + for _y in range(y, y + height): + GS2HMSBFormat.set_pixel(framebuf, _x, _y, color) class MHMSBFormat: """MHMSBFormat""" From d8b82385090ae0aa2108d42e23e5df17dbad74b9 Mon Sep 17 00:00:00 2001 From: Jonathan Dahan Date: Sat, 4 Feb 2023 14:09:49 -0500 Subject: [PATCH 3/8] Run black formatter --- adafruit_framebuf.py | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index 1117520..544c44c 100755 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -37,19 +37,19 @@ GS4_HMSB = 2 # Unimplemented! MHMSB = 3 # Single bit displays like the Sharp Memory RGB888 = 4 # Neopixels and Dotstars -GS2_HMSB = 5 # 2-bit color displays like the HT16K33 8x8 Matrix +GS2_HMSB = 5 # 2-bit color displays like the HT16K33 8x8 Matrix + class GS2HMSBFormat: """GS2HMSBFormat""" - @staticmethod def set_pixel(framebuf, x, y, color): """Set a given pixel to a color.""" - index = (y * framebuf.stride + x) >> 2 # why 2? + index = (y * framebuf.stride + x) >> 2 # why 2? pixel = framebuf.buf[index] - shift = (x & 0b11) << 1 # why 1? + shift = (x & 0b11) << 1 # why 1? mask = 0b11 << shift color = (color & 0b11) << shift @@ -58,10 +58,10 @@ def set_pixel(framebuf, x, y, color): @staticmethod def get_pixel(framebuf, x, y): """Get the color of a given pixel""" - index = (y * framebuf.stride + x) >> 2 # same as // 8? why? + index = (y * framebuf.stride + x) >> 2 # same as // 8? why? pixel = framebuf.buf[index] - shift = (x & 0b11) << 1 # why 1? + shift = (x & 0b11) << 1 # why 1? return (pixel >> shift) & 0b11 @staticmethod @@ -80,7 +80,7 @@ def rect(framebuf, x, y, width, height, color): # pylint: disable=too-many-arguments for _x in range(x, x + width): for _y in range(y, y + height): - if _x in [x, x+width] or _y in [y, y+height]: + if _x in [x, x + width] or _y in [y, y + height]: GS2HMSBFormat.set_pixel(framebuf, _x, _y, color) @staticmethod @@ -91,6 +91,7 @@ def fill_rect(framebuf, x, y, width, height, color): for _y in range(y, y + height): GS2HMSBFormat.set_pixel(framebuf, _x, _y, color) + class MHMSBFormat: """MHMSBFormat""" From d84d55093b7568caacfb6b8d826a7091e965ae78 Mon Sep 17 00:00:00 2001 From: Jonathan Dahan Date: Sat, 4 Feb 2023 14:24:48 -0500 Subject: [PATCH 4/8] Fix fill --- adafruit_framebuf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index 544c44c..fa37ae4 100755 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -68,7 +68,8 @@ def get_pixel(framebuf, x, y): def fill(framebuf, color): """completely fill/clear the buffer with a color""" if color: - fill = color & 0b11 + bits = (color & 0b11) + fill = (bits << 6) | (bits << 4) | (bits << 2) | (bits << 0) else: fill = 0x00 for i in range(len(framebuf.buf)): # pylint: disable=consider-using-enumerate From 3959f9bef62baef9853b64ccdf451aefc53e602a Mon Sep 17 00:00:00 2001 From: Jonathan Dahan Date: Sat, 4 Feb 2023 14:36:01 -0500 Subject: [PATCH 5/8] pylint --- adafruit_framebuf.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index fa37ae4..a8c1d4f 100755 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -68,7 +68,7 @@ def get_pixel(framebuf, x, y): def fill(framebuf, color): """completely fill/clear the buffer with a color""" if color: - bits = (color & 0b11) + bits = color & 0b11 fill = (bits << 6) | (bits << 4) | (bits << 2) | (bits << 0) else: fill = 0x00 @@ -537,9 +537,7 @@ def image(self, img): imwidth, imheight = img.size if imwidth != width or imheight != height: raise ValueError( - "Image must be same dimensions as display ({0}x{1}).".format( - width, height - ) + f"Image must be same dimensions as display ({width}x{height})." ) # Grab all the pixels from the image, faster than getpixel. pixels = img.load() From 97d197ed0b13283a3af15fce4cec3fc1184914d7 Mon Sep 17 00:00:00 2001 From: Jonathan Dahan Date: Sat, 4 Feb 2023 14:37:36 -0500 Subject: [PATCH 6/8] remove comments --- adafruit_framebuf.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index a8c1d4f..f0d6040 100755 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -46,10 +46,10 @@ class GS2HMSBFormat: @staticmethod def set_pixel(framebuf, x, y, color): """Set a given pixel to a color.""" - index = (y * framebuf.stride + x) >> 2 # why 2? + index = (y * framebuf.stride + x) >> 2 pixel = framebuf.buf[index] - shift = (x & 0b11) << 1 # why 1? + shift = (x & 0b11) << 1 mask = 0b11 << shift color = (color & 0b11) << shift @@ -58,10 +58,10 @@ def set_pixel(framebuf, x, y, color): @staticmethod def get_pixel(framebuf, x, y): """Get the color of a given pixel""" - index = (y * framebuf.stride + x) >> 2 # same as // 8? why? + index = (y * framebuf.stride + x) >> 2 pixel = framebuf.buf[index] - shift = (x & 0b11) << 1 # why 1? + shift = (x & 0b11) << 1 return (pixel >> shift) & 0b11 @staticmethod From 4839047e456dfc9f1cb44503a8500ee2c56a35f6 Mon Sep 17 00:00:00 2001 From: Jonathan Dahan Date: Sat, 4 Feb 2023 14:46:53 -0500 Subject: [PATCH 7/8] Fix fill --- adafruit_framebuf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index f0d6040..e47886c 100755 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -72,8 +72,8 @@ def fill(framebuf, color): fill = (bits << 6) | (bits << 4) | (bits << 2) | (bits << 0) else: fill = 0x00 - for i in range(len(framebuf.buf)): # pylint: disable=consider-using-enumerate - framebuf.buf[i] = fill + + framebuf.buf = [ fill for i in range(len(framebuf.buf)) ] @staticmethod def rect(framebuf, x, y, width, height, color): From 1991606d9f2f6c0395265db2fbbef5388b405ac0 Mon Sep 17 00:00:00 2001 From: Jonathan Dahan Date: Sun, 5 Feb 2023 16:34:37 -0500 Subject: [PATCH 8/8] format --- adafruit_framebuf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index e47886c..b86c54a 100755 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -73,7 +73,7 @@ def fill(framebuf, color): else: fill = 0x00 - framebuf.buf = [ fill for i in range(len(framebuf.buf)) ] + framebuf.buf = [fill for i in range(len(framebuf.buf))] @staticmethod def rect(framebuf, x, y, width, height, color):