gfxlcd/gfxlcd/drawing/page.py
Bartosz Kościów 7be3f9c0af refactor colors
add tests
2017-07-08 19:43:38 +02:00

139 lines
4.8 KiB
Python

import abc
from gfxlcd.drawing.pixel import Pixel
class Page(Pixel, metaclass=abc.ABCMeta):
"""Page drawing algorithm"""
def __init__(self, driver):
self.driver = driver
Pixel.__init__(self, driver)
self.buffer = []
def init(self):
"""init page"""
if self.rotation == 0 or self.rotation == 180:
self.buffer = [[0] * (self.height // 8) for x in range(self.width)]
else:
self.buffer = [[0] * (self.width // 8) for x in range(self.height)]
def draw_pixel(self, pos_x, pos_y, color=None):
"""draw a pixel at x,y"""
if color is None:
color = self.options['color']
self.buffer[pos_x][pos_y//8] |= self._convert_color(color) << (pos_y % 8)
self.flush()
def draw_line(self, pos_x1, pos_y1, pos_x2, pos_y2):
"""draw diagonal line"""
width = abs(pos_x2 - pos_x1)
height = abs(pos_y2 - pos_y1)
if pos_x1 == pos_x2:
steps = [height+1]
horizontal = False
offset_x = offset_y = 0
elif pos_y1 == pos_y2:
steps = [width+1]
horizontal = True
offset_x = offset_y = 0
elif width > height:
width += 1
if pos_x2 < pos_x1:
pos_x1, pos_x2 = pos_x2, pos_x1
pos_y1, pos_y2 = pos_y2, pos_y1
offset_y = 1 if pos_y2 > pos_y1 else -1
offset_x = 1 if pos_x2 > pos_x1 else -1
horizontal = True
step = height + 1
length = width // step
steps = self._calculate_line_steps(length, step, width)
else:
height += 1
if pos_y2 < pos_y1:
pos_x1, pos_x2 = pos_x2, pos_x1
pos_y1, pos_y2 = pos_y2, pos_y1
offset_y = 1 if pos_y2 > pos_y1 else -1
offset_x = 1 if pos_x2 > pos_x1 else -1
horizontal = False
step = width + 1
length = height // step
steps = self._calculate_line_steps(length, step, height)
delta_y = 0
delta_x = 0
for idx, step in enumerate(steps):
if horizontal:
for appendix in range(int(step)):
self.draw_pixel(
int(pos_x1 + delta_x + appendix),
int(pos_y1 + (idx * offset_y))
)
delta_x += step * offset_x
else:
for appendix in range(int(step)):
self.draw_pixel(
int(pos_x1 + (idx * offset_x)),
int(pos_y1 + delta_y + appendix)
)
delta_y += step * offset_y
def fill_rect(self, pos_x1, pos_y1, pos_x2, pos_y2):
"""draw a filled rectangle"""
if pos_y2 < pos_y1:
pos_y1, pos_y2 = pos_y2, pos_y1
if pos_x2 < pos_x1:
pos_x1, pos_x2 = pos_x2, pos_x1
start_page = pos_y1 // 8
start_bit = pos_y1 % 8
end_page = pos_y2 // 8
end_bit = pos_y2 % 8
rows = []
first_page = int(('0' * start_bit).rjust(8, '1'), 2)
last_page = int('1' * (end_bit+1), 2)
if start_page != end_page:
rows.append(first_page)
for _ in range(end_page - start_page - 1):
rows.append(255)
rows.append(last_page)
else:
rows.append(first_page & last_page)
page = start_page
for value in rows:
for x_diff in range(pos_x2-pos_x1+1):
self.buffer[pos_x1+x_diff][page] |= value
page += 1
def get_page_value(self, column, page):
"""returns value"""
return self.buffer[column][page]
@abc.abstractmethod
def flush(self, force=None):
"""flush buffer to the screen"""
pass
def draw_image(self, pos_x, pos_y, image):
"""draw a PIL image"""
image_file = image.convert('L')
width, height = image_file.size
offset_x = 0
offset_y = 0
for stream in list(image_file.getdata()):
if stream > self.options['threshold'] \
and not self._is_transparent(stream):
self.draw_pixel(pos_x + offset_x, pos_y + offset_y)
offset_x += 1
if offset_x > width - 1:
offset_x = 0
offset_y += 1
def _is_transparent(self, color):
"""check if color is a transparency color"""
if type(self.options['transparency_color']) == int \
and color == self.options['transparency_color']:
return True
elif type(self.options['transparency_color']) == list \
and color in self.options['transparency_color']:
return True
return False