Closed scumola closed 2 years ago
The following is the correct use of epd47.bitmap(), it will not restart.
LilyGo-EPD47 using in micropython
import epd
import framebuf
epd47 = epd.EPD47()
epd47.power(True)
epd47.clear()
bitmap = bytearray(100*10*2)
fbuf = framebuf.FrameBuffer(bitmap, 100, 10, framebuf.GS4_HMSB)
fbuf.fill(0)
fbuf.text('MicroPython!', 0, 0, 0xffff)
fbuf.hline(0, 9, 96, 0xffff)
epd47.bitmap(list(bitmap),0,0,100,100)
But what is displayed is not correct.
Ahh, I wasn't passing in the list of the one bytearray! I am able to see the black blob that gets sent to the screen (not what's expected). I tried different options for the framebuf.GS4_HMSB (all of the mono options too) and none of them seem to work as expected. Is this a bug or am I just not using it properly?
I think that if we could come up with good examples for working full-screen 1-bit framebuffer and 4-bit framebuffer, we could close this issue, but I've not been able to get that working yet.
Also, every other time I try to get this to work, it reboots the board it seems
I think that if we could come up with good examples for working full-screen 1-bit framebuffer and 4-bit framebuffer, we could close this issue, but I've not been able to get that working yet.
from math import floor
class FrameBuffer():
def __init__(self, buffer, width, height):
self.fb = buffer
self.width = width
self.height = height
def fill(self, color):
'''Fill the entire FrameBuffer with the specified color.
'''
for i in range(0, floor(self.width * self.height / 2)):
self.fb[i] = color
def pixel(self, x, y, color):
'''Draw a pixel a given framebuffer.
Args:
x: Horizontal position in pixels.
y: Vertical position in pixels.
color: The gray value of the line (0-255).
'''
if x < 0 or x >= self.width:
return
if y < 0 or y >= self.height:
return
pos = y * floor(self.width / 2) + floor(x / 2)
if floor(x % 2):
self.fb[pos] = self.fb[pos] & 0x0F | color & 0xF0
else:
self.fb[pos] = self.fb[pos] & 0xF0 | color >> 4
def hline(self, x, y, length, color):
'''Draw a horizontal line to a given framebuffer.
Args:
x: Horizontal start position in pixels.
y: Vertical start position in pixels.
length: Length of the line in pixels.
color: The gray value of the line (0-255);
'''
for i in range(0, length):
self.pixel(x + i, y, color)
def vline(self, x, y, length, color):
'''Draw a horizontal line to a given framebuffer.
Args:
x: Horizontal start position in pixels.
y: Vertical start position in pixels.
length: Length of the line in pixels.
color: The gray value of the line (0-255);
'''
for i in range(0, length):
self.pixel(x, y + i, color)
def circle(self, x, y, r, color):
'''Draw a circle with given center and radius
Args:
x: Center-point x coordinate
y: Center-point y coordinate
r: Radius of the circle in pixels
color: The gray value of the line (0-255)
'''
f = 1 - r
ddF_x = 1
ddF_y = -2 * r
xx = 0
yy = r
self.pixel(x, y + r, color)
self.pixel(x, y - r, color)
self.pixel(x + r, y, color)
self.pixel(x - r, y, color)
while xx < yy:
if (f >= 0):
yy -= 1
ddF_y += 2
f += ddF_y
xx += 1
ddF_x += 2
f += ddF_x
self.pixel(x + xx, y + yy, color)
self.pixel(x - xx, y + yy, color)
self.pixel(x + xx, y - yy, color)
self.pixel(x - xx, y - yy, color)
self.pixel(x + yy, y + xx, color)
self.pixel(x - yy, y + xx, color)
self.pixel(x + yy, y - xx, color)
self.pixel(x - yy, y - xx, color)
def fill_circle(self, x, y, r, color):
'''Draw a circle with fill with given center and radius
Args:
x: Center-point x coordinate
y: Center-point y coordinate
r: Radius of the circle in pixels
color: The gray value of the line (0-255)
'''
self.vline(x, y - r, 2 * r + 1, color)
self._fill_circle_helper(x, y, r, 3, 0, color)
def rect(self, x, y, w, h, color):
'''Draw a rectanle with no fill color
Args:
x: Top left corner x coordinate
y: Top left corner y coordinate
w: Width in pixels
h: Height in pixels
color: The gray value of the line (0-255);
'''
self.hline(x, y, w, color)
self.hline(x, y + h - 1, w, color)
self.vline(x, y, h, color)
self.vline(x + w - 1, y, h, color)
def fill_rect(self, x, y, w, h, color):
'''Draw a rectanle with fill color
Args:
x: Top left corner x coordinate
y: Top left corner y coordinate
w: Width in pixels
h: Height in pixels
color: The gray value of the line (0-255)
'''
for i in range(x, x + w):
self.vline(i, y, h, color)
def line(self, x0, y0, x1, y1, color):
'''Draw a line
Args:
x0 Start point x coordinate
y0 Start point y coordinate
x1 End point x coordinate
y1 End point y coordinate
color: The gray value of the line (0-255)
'''
if x0 == x1:
if (y0 > y1):
y0, y1 = self._swap_int(y0, y1)
self.vline(x0, y0, y1 - y0 + 1, color)
elif y0 == y1:
if x0 > x1:
x0, x1 = self._swap_int(x0, x1)
self.hline(x0, y0, x1 - x0 + 1, color)
else:
self._write_line(x0, y0, x1, y1, color)
def triangle(self, x0, y0, x1, y1, x2, y2, color):
'''Draw a triangle with no fill color
Args:
x0: Vertex #0 x coordinate
y0: Vertex #0 y coordinate
x1: Vertex #1 x coordinate
y1: Vertex #1 y coordinate
x2: Vertex #2 x coordinate
y2: Vertex #2 y coordinate
color: The gray value of the line (0-255)
'''
self.line(x0, y0, x1, y1, color)
self.line(x1, y1, x2, y2, color)
self.line(x2, y2, x0, y0, color)
def fill_triangle(self, x0, y0, x1, y1, x2, y2, color):
'''Draw a triangle with color-fill
Args:
x0: Vertex #0 x coordinate
y0: Vertex #0 y coordinate
x1: Vertex #1 x coordinate
y1: Vertex #1 y coordinate
x2: Vertex #2 x coordinate
y2: Vertex #2 y coordinate
color: The gray value of the line (0-255)
'''
a = 0
b = 0
y = 0
last = 0
if y0 > y1 :
y0, y1 = self._swap_int(y0, y1)
x0, x1 = self._swap_int(x0, x1)
if y1 > y2 :
y2, y1 = self._swap_int(y2, y1)
x2, x1 = self._swap_int(x2, x1)
if y0 > y1 :
y0, y1 = self._swap_int(y0, y1)
x0, x1 = self._swap_int(x0, x1)
if y0 == y2 :
a = b = x0
if x1 < a :
a = x1
elif x1 > b :
b = x1
if x2 < a :
a = x2
elif x2 > b:
b = x2
self.hline(a, y0, b - a + 1, color)
return
dx01 = x1 - x0
dy01 = y1 - y0
dx02 = x2 - x0
dy02 = y2 - y0
dx12 = x2 - x1
dy12 = y2 - y1
sa = 0
sb = 0
if y1 == y2 :
last = y1
else:
last = y1 - 1
for y in range(y0, last + 1) :
a = x0 + floor(sa / dy01)
b = x0 + floor(sb / dy02)
sa += dx01
sb += dx02
if a > b :
a, b = self._swap_int(a, b)
self.hline(a, y, b - a + 1, color)
y = last + 1
sa = dx12 * (y - y1)
sb = dx02 * (y - y0)
for i in range(y, y2 + 1):
a = x1 + floor(sa / dy12)
b = x0 + floor(sb / dy02)
sa += dx12
sb += dx02
if (a > b):
a, b = self._swap_int(a, b)
self.hline(a, i, b - a + 1, color)
def _fill_circle_helper(self, x0, y0, r, corners, delta, color):
f = 1 - r
ddF_x = 1
ddF_y = -2 * r
x = 0
y = r
px = x
py = y
delta += 1
while x < y:
if f >= 0:
y -= 1
ddF_y += 2
f += ddF_y
x += 1
ddF_x += 2
f += ddF_x
if (x < (y + 1)):
if (corners & 1):
self.vline(x0 + x, y0 - y, 2 * y + delta, color)
if (corners & 2):
self.vline(x0 - x, y0 - y, 2 * y + delta, color)
if y != py:
if corners & 1:
self.vline(x0 + py, y0 - px, 2 * px + delta, color)
if corners & 2:
self.vline(x0 - py, y0 - px, 2 * px + delta, color)
py = y
px = x
def _write_line(self, x0, y0, x1, y1, color):
'''Write a line. Bresenham's algorithm - thx wikpedia
Args:
x0 Start point x coordinate
y0 Start point y coordinate
x1 End point x coordinate
y1 End point y coordinate
color: The gray value of the line (0-255)
'''
steep = abs(y1 - y0) > abs(x1 - x0)
if steep:
x0, y0 = self._swap_int(x0, y0)
x1, y1 = self._swap_int(x1, y1)
if x0 > x1:
x0, x1 = self._swap_int(x0, x1)
x1, y1 = self._swap_int(y0, y1)
dx = x1 - x0
dy = abs(y1 - y0)
err = floor(dx / 2)
ystep = 1 if y0 < y1 else -1
while x0 <= x1:
if steep:
self.pixel(y0, x0, color)
else:
self.pixel(x0, y0, color)
err -= dy
if err < 0:
y0 += ystep
err += dx
x0 += 1
@staticmethod
def _swap_int(a, b):
return b, a
if __name__ == "__main__":
from epd import EPD47
e = EPD47()
e.power(True)
e.clear()
buffer = bytearray(480 * 540)
fb = FrameBuffer(buffer, 960, 540)
fb.fill(255)
fb.hline(100, 100, 100, 256)
fb.vline(100, 100, 100, 256)
fb.circle(200, 200, 50, 256)
fb.fill_circle(400, 200, 50, 256)
fb.rect(600, 200, 100, 100, 256)
fb.fill_rect(800, 200, 100, 100, 256)
fb.line(100, 300, 400, 500, 256)
fb.triangle(200, 400, 150, 500, 250, 400, 256)
fb.fill_triangle(600, 400, 600, 500, 700, 500, 256)
e.bitmap(list(buffer), 0, 0, 960, 540)
Oh, wow! Quite a bit of work. I'm impressed! I didn't know that you'd be re-writing all of the framebuffer functions yourself! There isn't a way to just re-use all of the existing framebuffer libraries out there already - the ones that support fonts and everything? Will I have to write my own font-rendering code in python in order to draw text to the framebuffer?
I cannot get any of these examples to work, my screen keeps displaying white. I can only draw things if I change the offset on bitmap()
to 20, 20
. The C++ demos work fine, though. Does anyone know what might be wrong?
@skorokithakis I'm having a similar issue. Generally, the micropython EPD support seems to be troubled, and very little of the examples here work, and the few which do result in very poor quality images. When compared to the C++ examples, there's a stark difference. Perhaps something upstream changed and has caused regressions?
Getting a reboot when trying to run this:
(dies on the epd47.bitmap() call)
Output: