Source code for pyfirmata_epd.epdpaint

try:
    from .fonts import sFONT
except:
    from fonts import sFONT
from math import floor

COLORED = 0
UNCOLORED = 1

# Display orientation
ROTATE_0 = 0
ROTATE_90 = 1
ROTATE_180 = 2
ROTATE_270 = 3

# Color inverse. 1 or 0 = set or reset a bit if set a colored pixel
IF_INVERT_COLOR = 1


[docs] def fixX(x, paint): if x < 0: return round((paint.GetHeight() if paint.GetRotate() in [ROTATE_90, ROTATE_270] else paint.GetWidth()) + x) return round(x)
[docs] def fixY(y, paint): if y < 0: return round((paint.GetWidth() if paint.GetRotate() in [ROTATE_90, ROTATE_270] else paint.GetHeight()) + y) return round(y)
[docs] class Paint: """ Initialize a paint class :param list[int] image: Default image buffer. Can be empty :param int width: Width of paint screen (should be multiple of 8) :param int height: Height of paint screen """ _image = [] _width = 0 _height = 0 _rotate = ROTATE_0 def __init__(self, image, width, height): self._image = image # 1 byte = 8 pixels, so the width should be the multiple of 8 self._width = width + 8 - (width % 8) if width % 8 else width self._height = height for i in range(len(self._image), floor(self._width / 8) * self._height): self._image.append(255)
[docs] def Clear(self, colored): """clear the image :param int colored: Should the pixels be colored or not """ for x in range(self._width): for y in range(self._height): self.DrawAbsolutePixel(x, y, colored)
[docs] def DrawAbsolutePixel(self, x, y, colored): """this draws a pixel by absolute coordinates. this function won't be affected by the rotate parameter. :param int x: X Location :param int y: Y Location :param int colored: Should the pixel be colored or not """ if x < 0 or x >= self._width or y < 0 or y >= self._height: return location = floor((x + y * self._width) / 8) if IF_INVERT_COLOR: if colored: self._image[location] |= 0x80 >> (x % 8) else: self._image[location] &= ~(0x80 >> (x % 8)) elif colored: self._image[location] &= ~(0x80 >> (x % 8)) else: self._image[location] |= 0x80 >> (x % 8)
# Getters and Setters
[docs] def GetImage(self): """Get the image object :rtype: list[int] """ return self._image
[docs] def GetWidth(self): """Get the width :rtype: int """ return self._width
[docs] def SetWidth(self, width): """Set the width :param int width: New width value. Should be multiple of 8 """ self._width = width + 8 - (width % 8) if width % 8 else width
[docs] def GetHeight(self): """Get the height :rtype: int """ return self._height
[docs] def SetHeight(self, height): """Set the height :param int height: New height value """ self._height = height
[docs] def GetRotate(self): """Get the rotation :rtype: int """ return self._rotate
[docs] def SetRotate(self, rotate): """Set the rotation :param int rotate: New rotate value """ self._rotate = rotate
[docs] def DrawPixel(self, x, y, colored): """this draws a pixel by the coordinates :param int x: X Location :param int y: Y Location :param int colored: Should the pixel be colored or not """ if self._rotate == ROTATE_0: if x < 0 or x >= self._width or y < 0 or y >= self._height: return elif self._rotate == ROTATE_90: if x < 0 or x >= self._height or y < 0 or y >= self._width: return point_temp = x x = self._width - y - 1 y = point_temp elif self._rotate == ROTATE_180: if x < 0 or x >= self._width or y < 0 or y >= self._height: return x = self._width - x - 1 y = self._height - y - 1 elif self._rotate == ROTATE_270: if x < 0 or x >= self._height or y < 0 or y >= self._width: return point_temp = x x = y y = self._height - point_temp - 1 else: return self.DrawAbsolutePixel(x, y, colored)
[docs] def DrawCharAt(self, x, y, ascii_char, font, colored): """this draws a charactor on the frame buffer but not refresh :param int x: X Location :param int y: Y Location :param chr ascii_char: ASCII char :param sFONT font: Font for the char :param int colored: Should the pixels be colored or not """ char_offset = floor((ord(ascii_char) - ord(' ')) * font.Height * floor(font.Width / 8 + (1 if font.Width % 8 else 0))) ptr = font.table[char_offset] for j in range(font.Height): for i in range(font.Width): if ptr & (0x80 >> (i % 8)): self.DrawPixel(x + i, y + j, colored) if i % 8 == 7: char_offset += 1 ptr = font.table[char_offset] if font.Width % 8 != 0: char_offset += 1 ptr = font.table[char_offset]
[docs] def DrawStringAt(self, x, y, text, font, colored): """this displays a string on the frame buffer but not refresh :param int x: X Location :param int y: Y Location :param str text: The whole string :param sFONT font: Font for the text :param int colored: Should the pixels be colored or not """ x = fixX(x, self) y = fixY(y, self) p_text = 0 counter = 0 refcolumn = x # Send the string character by character on EPD while p_text < len(text): # Display one character on EPD self.DrawCharAt(refcolumn, y, text[p_text], font, colored) # Decrement the column position by 16 refcolumn += font.Width # Point on the next character p_text += 1 counter += 1
[docs] def DrawLine(self, x0, y0, x1, y1, colored): """this draws a line on the frame buffer :param int x0: Start X Location :param int y0: Start Y Location :param int x1: End X Location :param int y1: End Y Location :param int colored: Should the pixels be colored or not """ # Bresenham algorithm dx = x1 - x0 if x1 - x0 >= 0 else x0 - x1 sx = 1 if x0 < x1 else -1 dy = y1 - y0 if y1 - y0 <= 0 else y0 - y1 sy = 1 if y0 < y1 else -1 err = dx + dy while (x0 != x1) and (y0 != y1): self.DrawPixel(x0, y0, colored) if 2 * err >= dy: err += dy; x0 += sx; if 2 * err <= dx: err += dx; y0 += sy;
[docs] def DrawHorizontalLine(self, x, y, line_width, colored): """this draws a horizontal line on the frame buffer :param int x: X Location :param int y: Y Location :param int line_width: Line width :param int colored: Should the pixels be colored or not """ for i in range(x, round(x + line_width)): self.DrawPixel(i, y, colored)
[docs] def DrawVerticalLine(self, x, y, line_height, colored): """this draws a vertical line on the frame buffer :param int x: X Location :param int y: Y Location :param int line_height: Line height :param int colored: Should the pixels be colored or not """ for i in range(y, round(y + line_height)): self.DrawPixel(x, i, colored)
[docs] def DrawRectangle(self, x0, y0, x1, y1, colored): """this draws a rectangle :param int x0: Start X Location :param int y0: Start Y Location :param int x1: End X Location :param int y1: End Y Location :param int colored: Should the pixels be colored or not """ x0 = fixX(x0, self) x1 = fixX(x1, self) y0 = fixY(y0, self) y1 = fixY(y1, self) min_x = x0 if x1 > x0 else x1 max_x = x1 if x1 > x0 else x0 min_y = y0 if y1 > y0 else y1 max_y = y1 if y1 > y0 else y0 self.DrawHorizontalLine(min_x, min_y, max_x - min_x + 1, colored) self.DrawHorizontalLine(min_x, max_y, max_x - min_x + 1, colored) self.DrawVerticalLine(min_x, min_y, max_y - min_y + 1, colored) self.DrawVerticalLine(max_x, min_y, max_y - min_y + 1, colored)
[docs] def DrawFilledRectangle(self, x0, y0, x1, y1, colored): """this draws a filled rectangle :param int x0: Start X Location :param int y0: Start Y Location :param int x1: End X Location :param int y1: End Y Location :param int colored: Should the pixels be colored or not """ x0 = fixX(x0, self) x1 = fixX(x1, self) y0 = fixY(y0, self) y1 = fixY(y1, self) min_x = x0 if x1 > x0 else x1 max_x = x1 if x1 > x0 else x0 min_y = y0 if y1 > y0 else y1 max_y = y1 if y1 > y0 else y0 for i in range(min_x, max_x + 1): # <= max_x self.DrawVerticalLine(i, min_y, max_y - min_y + 1, colored)
[docs] def DrawCircle(self, x, y, radius, colored): """this draws a circle :param int x: Middle X Location :param int y: Middle Y Location :param int radius: Radius of the circle :param int colored: Should the pixels be colored or not """ # Bresenham algorithm x_pos = -radius y_pos = 0 err = 2 - 2 * radius x = fixX(x, self) y = fixY(y, self) while x_pos <= 0: self.DrawPixel(x - x_pos, y + y_pos, colored) self.DrawPixel(x + x_pos, y + y_pos, colored) self.DrawPixel(x + x_pos, y - y_pos, colored) self.DrawPixel(x - x_pos, y - y_pos, colored) e2 = err if e2 <= y_pos: y_pos += 1 err += y_pos * 2 + 1 if -x_pos == y_pos and e2 <= x_pos: e2 = 0 if e2 > x_pos: x_pos += 1 err += x_pos * 2 + 1
[docs] def DrawFilledCircle(self, x, y, radius, colored): """this draws a filled circle :param int x: Middle X Location :param int y: Middle Y Location :param int radius: Radius of the circle :param int colored: Should the pixels be colored or not """ # Bresenham algorithm x_pos = -radius y_pos = 0 err = 2 - 2 * radius x = fixX(x, self) y = fixY(y, self) while x_pos <= 0: self.DrawPixel(x - x_pos, y + y_pos, colored) self.DrawPixel(x + x_pos, y + y_pos, colored) self.DrawPixel(x + x_pos, y - y_pos, colored) self.DrawPixel(x - x_pos, y - y_pos, colored) self.DrawHorizontalLine(x + x_pos, y + y_pos, 2 * (-x_pos) + 1, colored) self.DrawHorizontalLine(x + x_pos, y - y_pos, 2 * (-x_pos) + 1, colored) e2 = err if e2 <= y_pos: y_pos += 1 err += y_pos * 2 + 1 if -x_pos == y_pos and e2 <= x_pos: e2 = 0 if e2 > x_pos: x_pos += 1 err += x_pos * 2 + 1