kopia lustrzana https://github.com/peterhinch/micropython-micro-gui
101 wiersze
3.5 KiB
Python
101 wiersze
3.5 KiB
Python
# bitmap.py Provides the BMG (bitmapped graphics) class
|
|
|
|
# Released under the MIT License (MIT). See LICENSE.
|
|
# Copyright (c) 2022 Peter Hinch
|
|
import gc
|
|
from framebuf import FrameBuffer, MONO_HLSB
|
|
from gui.core.ugui import Widget
|
|
from gui.core.colors import *
|
|
from gui.core.ugui import ssd
|
|
|
|
def rbit8(v):
|
|
v = (v & 0x0f) << 4 | (v & 0xf0) >> 4
|
|
v = (v & 0x33) << 2 | (v & 0xcc) >> 2
|
|
return (v & 0x55) << 1 | (v & 0xaa) >> 1
|
|
|
|
class BMG(Widget):
|
|
|
|
@staticmethod
|
|
def make_buffer(height, width):
|
|
w = (width >> 3) + int(width & 7 > 0)
|
|
return bytearray(height * w)
|
|
|
|
def __init__(self, writer, row, col, height, width, scale=1, *, fgcolor=None, bgcolor=None, bdcolor=RED, buf=None):
|
|
super().__init__(writer, row, col, height, width, fgcolor, bgcolor, bdcolor, False)
|
|
if buf is None:
|
|
buf = BMG.make_buffer(height, width)
|
|
self._fb = FrameBuffer(buf, width, height, MONO_HLSB)
|
|
self._scale = scale
|
|
self._buf = buf
|
|
|
|
def show(self):
|
|
if super().show(True): # Draw or erase border
|
|
palette = ssd.palette
|
|
palette.bg(self.bgcolor)
|
|
palette.fg(self.fgcolor)
|
|
ssd.blit(self._fb, self.col, self.row, -1, palette)
|
|
|
|
def color(self, fgcolor=None, bgcolor=None):
|
|
if fgcolor is not None:
|
|
self.fgcolor = fgcolor
|
|
if bgcolor is not None:
|
|
self.bgcolor = bgcolor
|
|
self.draw = True
|
|
|
|
def value(self, obj):
|
|
if isinstance(obj, list): # 2d list of booleans
|
|
self._fb.fill(1)
|
|
s = self._scale
|
|
wd = len(obj[0])
|
|
ht = len(obj)
|
|
if wd * s > self.width or ht * s > self.height:
|
|
print('Object too large for buffer', wd * s, self.width, ht * s, self.height)
|
|
else:
|
|
print(f"Object is {wd} x {ht}")
|
|
for row in range(ht):
|
|
for col in range(wd):
|
|
v = obj[row][col]
|
|
for nc in range(s):
|
|
for nr in range(s):
|
|
self._fb.pixel(col * s + nc, row * s + nr, v)
|
|
elif isinstance(obj, str): # Assume filename
|
|
try:
|
|
with open(obj, "r") as f:
|
|
g = self.handle_stream(f)
|
|
n = 0
|
|
for x in g:
|
|
self._buf[n] = rbit8(x)
|
|
n += 1
|
|
except OSError:
|
|
print(f"Failed to input from {obj}")
|
|
self.draw = True
|
|
gc.collect()
|
|
# TODO graphic must be exactly the right size. Get dims from file in app, pass stream?
|
|
def handle_stream(self, f):
|
|
m = self._scale
|
|
s = f.readline()
|
|
elements = s.split(" ")
|
|
if elements[1].endswith("width"):
|
|
wd = int(elements[2])
|
|
else:
|
|
raise OSError
|
|
s = f.readline()
|
|
elements = s.split(" ")
|
|
if elements[1].endswith("height"):
|
|
ht = int(elements[2])
|
|
else:
|
|
raise OSError
|
|
if wd * m > self.width or ht * m > self.height:
|
|
print("Object too large for buffer", wd * m, self.width, ht * m, self.height)
|
|
raise OSError
|
|
s = f.readline()
|
|
if not s.startswith("static"):
|
|
raise OSError
|
|
while s := f.readline():
|
|
if (lb := s.find("}")) != -1:
|
|
s = s[:lb] # Strip trailing };
|
|
p = s.strip().split(',')
|
|
for x in p:
|
|
if x:
|
|
yield int(x, 16)
|