From 389375c74f2b6ee21076d0db9127d74aee235ecd Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 6 Jan 2019 11:39:14 -0500 Subject: [PATCH 1/6] remove unsupported RGB, add rotation --- adafruit_framebuf.py | 125 ++++++++++++++++++++++++++----------------- 1 file changed, 76 insertions(+), 49 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index 6a736bd..eda6827 100644 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -68,6 +68,16 @@ def get_pixel(framebuf, x, y): offset = 7 - x & 0x07 return (framebuf.buf[index] >> offset) & 0x01 + @staticmethod + def fill(framebuf, color): + """completely fill/clear the buffer with a color""" + if color: + fill = 0xFF + else: + fill = 0x00 + for i in range(len(framebuf.buf)): + framebuf.buf[i] = fill + @staticmethod def fill_rect(framebuf, x, y, width, height, color): """Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws @@ -96,6 +106,16 @@ def get_pixel(framebuf, x, y): offset = y & 0x07 return (framebuf.buf[index] >> offset) & 0x01 + @staticmethod + def fill(framebuf, color): + """completely fill/clear the buffer with a color""" + if color: + fill = 0xFF + else: + fill = 0x00 + for i in range(len(framebuf.buf)): + framebuf.buf[i] = fill + @staticmethod def fill_rect(framebuf, x, y, width, height, color): """Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws @@ -110,36 +130,6 @@ def fill_rect(framebuf, x, y, width, height, color): y += 1 height -= 1 - -class RGB565Format: - """RGB565Format""" - @staticmethod - def set_pixel(framebuf, x, y, color): - """Set a given pixel to a color.""" - index = (x + y * framebuf.stride) * 2 - framebuf.buf[index] = (color >> 8) & 0xFF - framebuf.buf[index + 1] = color & 0xFF - - @staticmethod - def get_pixel(framebuf, x, y): - """Get the color of a given pixel""" - index = (x + y * framebuf.stride) * 2 - return (framebuf.buf[index] << 8) | framebuf.buf[index + 1] - - @staticmethod - def fill_rect(framebuf, x, y, width, height, color): - # pylint: disable=too-many-arguments - """Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws - both the outline and interior.""" - while height > 0: - for w_w in range(width): - index = (w_w + x + y * framebuf.stride) * 2 - framebuf.buf[index] = (color >> 8) & 0xFF - framebuf.buf[index + 1] = color & 0xFF - y += 1 - height -= 1 - - class FrameBuffer: """FrameBuffer object. @@ -171,31 +161,43 @@ def __init__(self, buf, width, height, buf_format=MVLSB, stride=None): self.format = MVLSBFormat() elif buf_format == MHMSB: self.format = MHMSBFormat() - elif buf_format == RGB565: - self.format = RGB565Format() else: raise ValueError('invalid format') + self._rotation = 0 + + @property + def rotation(self): + return self._rotation + + @rotation.setter + def rotation(self, val): + if not val in (0, 1, 2, 3): + raise RuntimeError("Bad rotation setting") + self._rotation = val def fill(self, color): """Fill the entire FrameBuffer with the specified color.""" - self.format.fill_rect(self, 0, 0, self.width, self.height, color) + self.format.fill(self, color) def fill_rect(self, x, y, width, height, color): """Draw a rectangle at the given location, size and color. The ``fill_rect`` method draws both the outline and interior.""" # pylint: disable=too-many-arguments, too-many-boolean-expressions - if width < 1 or height < 1 or (x + width) <= 0 or (y + height) <= 0 or y >= self.height \ - or x >= self.width: - return - x_end = min(self.width, x + width) - y_end = min(self.height, y + height) - x = max(x, 0) - y = max(y, 0) - self.format.fill_rect(self, x, y, x_end - x, y_end - y, color) + self.rect(x, y, width, height, color, fill=True) def pixel(self, x, y, color=None): """If ``color`` is not given, get the color value of the specified pixel. If ``color`` is given, set the specified pixel to the given color.""" + if self.rotation == 1: + x, y = y, x + x = self.width - x - 1 + if self.rotation == 2: + x = self.width - x - 1 + y = self.width - y - 1 + if self.rotation == 3: + x, y = y, x + y = self.width - y - 1 + if x < 0 or x >= self.width or y < 0 or y >= self.height: return None if color is None: @@ -205,20 +207,42 @@ def pixel(self, x, y, color=None): def hline(self, x, y, width, color): """Draw a horizontal line up to a given length.""" - self.fill_rect(x, y, width, 1, color) + self.rect(x, y, width, 1, color, fill=True) def vline(self, x, y, height, color): """Draw a vertical line up to a given length.""" - self.fill_rect(x, y, 1, height, color) + self.rect(x, y, 1, height, color, fill=True) - def rect(self, x, y, width, height, color): + def rect(self, x, y, width, height, color, *, fill=False): """Draw a rectangle at the given location, size and color. The ```rect``` method draws only a 1 pixel outline.""" # pylint: disable=too-many-arguments - self.fill_rect(x, y, width, 1, color) - self.fill_rect(x, y + height-1, width, 1, color) - self.fill_rect(x, y, 1, height, color) - self.fill_rect(x + width - 1, y, 1, height, color) + if self.rotation == 1: + x, y = y, x + width, height = height, width + x = self.width - x - 1 + if self.rotation == 2: + x = self.width - x - 1 + y = self.width - y - 1 + if self.rotation == 3: + x, y = y, x + width, height = height, width + y = self.width - y - 1 + + if width < 1 or height < 1 or (x + width) <= 0 or (y + height) <= 0 or y >= self.height \ + or x >= self.width: + return + x_end = min(self.width-1, x + width) + y_end = min(self.height-1, y + height) + x = max(x, 0) + y = max(y, 0) + if fill: + self.format.fill_rect(self, x, y, x_end - x, y_end - y, color) + else: + self.format.fill_rect(self, x, y, x_end - x, 1, color) + self.format.fill_rect(self, x, y, 1, y_end - y, color) + self.format.fill_rect(self, x, y_end, x_end - x, 1, color) + self.format.fill_rect(self, x_end, y, 1, y_end - y, color) def line(self, x_0, y_0, x_1, y_1, color): # pylint: disable=too-many-arguments @@ -363,7 +387,10 @@ def draw_char(self, char, x, y, framebuffer, color): for char_x in range(self.font_width): # Grab the byte for the current column of font data. self._font.seek(2 + (ord(char) * self.font_width) + char_x) - line = struct.unpack('B', self._font.read(1))[0] + try: + line = struct.unpack('B', self._font.read(1))[0] + except RuntimeError: + continue # maybe character isnt there? go to next # Go through each row in the column byte. for char_y in range(self.font_height): # Draw a pixel for each bit that's flipped on. From 8febfe8d4ca9af5f101ac35ea10d971ff964a534 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 6 Jan 2019 15:09:06 -0500 Subject: [PATCH 2/6] todo: fix later to handle rotation --- adafruit_framebuf.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index eda6827..8c40ee3 100644 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -380,9 +380,9 @@ def draw_char(self, char, x, y, framebuffer, color): # pylint: disable=too-many-arguments """Draw one character at position (x,y) to a framebuffer in a given color""" # Don't draw the character if it will be clipped off the visible area. - if x < -self.font_width or x >= framebuffer.width or \ - y < -self.font_height or y >= framebuffer.height: - return + #if x < -self.font_width or x >= framebuffer.width or \ + # y < -self.font_height or y >= framebuffer.height: + # return # Go through each column of the character. for char_x in range(self.font_width): # Grab the byte for the current column of font data. From 8a17b6065ed4a233f218fb93475197c61b4be23e Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 6 Jan 2019 16:20:20 -0500 Subject: [PATCH 3/6] fix pixel rotaion --- adafruit_framebuf.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index 8c40ee3..c7ee5de 100644 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -193,10 +193,10 @@ def pixel(self, x, y, color=None): x = self.width - x - 1 if self.rotation == 2: x = self.width - x - 1 - y = self.width - y - 1 + y = self.height - y - 1 if self.rotation == 3: x, y = y, x - y = self.width - y - 1 + y = self.height - y - 1 if x < 0 or x >= self.width or y < 0 or y >= self.height: return None From 1e31b8691886a0d3cdd8ec4a9f11eb1fd50b9cc3 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sat, 30 Mar 2019 23:27:23 -0400 Subject: [PATCH 4/6] fix rectangle rotation --- adafruit_framebuf.py | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index c7ee5de..c0d298a 100644 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -220,29 +220,29 @@ def rect(self, x, y, width, height, color, *, fill=False): if self.rotation == 1: x, y = y, x width, height = height, width - x = self.width - x - 1 + x = self.width - x - width if self.rotation == 2: - x = self.width - x - 1 - y = self.width - y - 1 + x = self.width - x - width + y = self.height - y - height if self.rotation == 3: x, y = y, x width, height = height, width - y = self.width - y - 1 + y = self.height - y - height if width < 1 or height < 1 or (x + width) <= 0 or (y + height) <= 0 or y >= self.height \ or x >= self.width: return - x_end = min(self.width-1, x + width) - y_end = min(self.height-1, y + height) + x_end = min(self.width-1, x + width-1) + y_end = min(self.height-1, y + height-1) x = max(x, 0) y = max(y, 0) if fill: - self.format.fill_rect(self, x, y, x_end - x, y_end - y, color) + self.format.fill_rect(self, x, y, x_end-x+1, y_end-y+1, color) else: - self.format.fill_rect(self, x, y, x_end - x, 1, color) - self.format.fill_rect(self, x, y, 1, y_end - y, color) - self.format.fill_rect(self, x, y_end, x_end - x, 1, color) - self.format.fill_rect(self, x_end, y, 1, y_end - y, color) + self.format.fill_rect(self, x, y, x_end-x+1, 1, color) + self.format.fill_rect(self, x, y, 1, y_end-y+1, color) + self.format.fill_rect(self, x, y_end, x_end-x+1, 1, color) + self.format.fill_rect(self, x_end, y, 1, y_end-y+1, color) def line(self, x_0, y_0, x_1, y_1, color): # pylint: disable=too-many-arguments From 2bc3144f7a148adb4fe4e48626f5bab742414fac Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 00:10:26 -0400 Subject: [PATCH 5/6] linted --- adafruit_framebuf.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index c0d298a..10f9d0b 100644 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -167,6 +167,7 @@ def __init__(self, buf, width, height, buf_format=MVLSB, stride=None): @property def rotation(self): + """The rotation setting of the display, can be one of (0, 1, 2, 3)""" return self._rotation @rotation.setter @@ -230,7 +231,7 @@ def rect(self, x, y, width, height, color, *, fill=False): y = self.height - y - height if width < 1 or height < 1 or (x + width) <= 0 or (y + height) <= 0 or y >= self.height \ - or x >= self.width: + or x >= self.width: # pylint: disable=too-many-boolean-expressions return x_end = min(self.width-1, x + width-1) y_end = min(self.height-1, y + height-1) From cd1c6be81af9d4ebf655a13b9618d816d307d2a6 Mon Sep 17 00:00:00 2001 From: ladyada Date: Sun, 31 Mar 2019 00:40:18 -0400 Subject: [PATCH 6/6] try lint again! --- adafruit_framebuf.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/adafruit_framebuf.py b/adafruit_framebuf.py index 10f9d0b..33ba50a 100644 --- a/adafruit_framebuf.py +++ b/adafruit_framebuf.py @@ -230,8 +230,9 @@ def rect(self, x, y, width, height, color, *, fill=False): width, height = height, width y = self.height - y - height - if width < 1 or height < 1 or (x + width) <= 0 or (y + height) <= 0 or y >= self.height \ - or x >= self.width: # pylint: disable=too-many-boolean-expressions + # pylint: disable=too-many-boolean-expressions + if width < 1 or height < 1 or (x + width) <= 0 or (y + height) <= 0 or \ + y >= self.height or x >= self.width: return x_end = min(self.width-1, x + width-1) y_end = min(self.height-1, y + height-1)