@@ -15,7 +15,7 @@ __all__ = ["MicroBMP"] | |||
class MicroBMP(object): | |||
def __init__(self, width=None, height=None, depth=None, palette=None, data_callback=None): | |||
def __init__(self, width=None, height=None, depth=None, palette=None, header_callback=None, data_callback=None): | |||
# BMP Header | |||
self.BMP_id = b"BM" | |||
self.BMP_size = None | |||
@@ -44,6 +44,7 @@ class MicroBMP(object): | |||
self.row_size = None | |||
self.padded_row_size = None | |||
self.header_callback = header_callback | |||
self.data_callback = data_callback | |||
self.initialised = False | |||
@@ -211,7 +212,7 @@ class MicroBMP(object): | |||
x += 1 | |||
def read_io(self, bf_io): | |||
print("BMP reading file") | |||
#print("BMP reading file") | |||
# BMP Header | |||
data = bf_io.read(14) | |||
self.BMP_id = data[0:2] | |||
@@ -234,18 +235,7 @@ class MicroBMP(object): | |||
self.DIB_hres, | |||
self.DIB_vres, | |||
) = unpack("<iiHHIIii", data[0:28]) | |||
print("BMP metadata: ", str([ | |||
self.DIB_w, | |||
self.DIB_h, | |||
self.DIB_planes_num, | |||
self.DIB_depth, | |||
self.DIB_comp, | |||
self.DIB_raw_size, | |||
self.DIB_hres, | |||
self.DIB_vres, | |||
])) | |||
DIB_plt_num_info = unpack("<I", data[28:32])[0] | |||
DIB_plt_important_num_info = unpack("<I", data[32:36])[0] | |||
if self.DIB_len > 40: | |||
@@ -270,31 +260,52 @@ class MicroBMP(object): | |||
else: | |||
is_top_down = False | |||
header = [ | |||
self.DIB_w, | |||
self.DIB_h, | |||
self.DIB_planes_num, | |||
self.DIB_depth, | |||
self.DIB_comp, | |||
self.DIB_raw_size, | |||
self.DIB_hres, | |||
self.DIB_vres, | |||
self.palette, | |||
] | |||
#print("BMP metadata: ", str(header)) | |||
if self.header_callback is not None: | |||
self.header_callback(header) | |||
self.parray = None | |||
assert self._init(), "Failed to initialize the image!" | |||
# Pixels | |||
print("BMP reading data") | |||
#print("BMP reading data") | |||
if self.DIB_comp == 0: | |||
# BI_RGB | |||
for h in range(self.DIB_h): | |||
y = h if is_top_down else self.DIB_h - h - 1 | |||
data = bf_io.read(self.padded_row_size) | |||
#pixels_row = [] | |||
for x in range(self.DIB_w): | |||
if self.DIB_depth <= 8: | |||
#self[x, y] = self._extract_from_bytes(data, x) | |||
pixel_data = self._extract_from_bytes(data, x) | |||
##self[x, y] = self._extract_from_bytes(data, x) | |||
byte_index, pos_in_byte = divmod(x, self.ppb) | |||
shift = 8 - self.DIB_depth * (pos_in_byte + 1) | |||
pixel_data = (data[byte_index] >> shift) & self.pmask | |||
#pixel_data = self._extract_from_bytes(data, x) | |||
pixel = pixel_data if self.palette is None else self.palette[pixel_data] | |||
##pixels_row.append(pixel) | |||
self.data_callback(x, y, pixel) | |||
else: | |||
v = x * 3 | |||
# BMP colour is in BGR order. | |||
self[x, y] = (data[v + 2], data[v + 1], data[v]) | |||
#self.data_callback(0, y, pixels_row) | |||
else: | |||
# BI_RLE8 or BI_RLE4 | |||
self._decode_rle(bf_io) | |||
print("BMP done") | |||
#print("BMP done") | |||
return self | |||
def write_io(self, bf_io, force_40B_DIB=False): | |||
@@ -1,9 +1,11 @@ | |||
import epaper | |||
import microbmp | |||
import time | |||
import random | |||
import gc | |||
colormap = [ | |||
epd_resolution = [600, 448] | |||
epd_colormap = [ | |||
[0x00, 0x00, 0x00], # black | |||
[0xff, 0xff, 0xff], # white | |||
[0x00, 0xdd, 0x00], # green | |||
@@ -25,32 +27,63 @@ def init_display(): | |||
def draw_image(filename): | |||
global epd | |||
global colormap | |||
def color_distance(c1, c2): | |||
def dist(a, b): | |||
return abs(a - b) | |||
return dist(c1[0], c2[0]) + dist(c1[1], c2[1]) + dist(c1[2], c2[2]) | |||
def callback(x, y, color): | |||
global epd_colormap | |||
offset_x = 0 | |||
offset_y = 0 | |||
color_map = {} | |||
def header_callback(header): | |||
print("header callback: ", str(header)) | |||
global epd_resolution | |||
w = header[0] | |||
h = header[1] | |||
offset_x = (epd_resolution[0] - w)//2 | |||
offset_y = (epd_resolution[1] - h)//2 | |||
print("offset: ", offset_x, offset_y) | |||
def pixel_callback(x, y, color): | |||
global epd | |||
global colormap | |||
best_index = 0 | |||
best_score = 256 | |||
for index in range(len(colormap)): | |||
c = colormap[index] | |||
score = color_distance(c, color) | |||
if score < best_score: | |||
best_score = score | |||
best_index = index | |||
pixel = best_index | |||
global epd_colormap | |||
# translate color to color index | |||
color_index = 0 | |||
color_key = color[0] + color[1] << 8 + color[2] << 16 | |||
if color_key in color_map: | |||
color_index = color_map[color_key] | |||
else: | |||
# search for the best color | |||
best_index = 0 | |||
best_score = 1000 | |||
for index in range(len(epd_colormap)): | |||
c1 = epd_colormap[index] | |||
c2 = color | |||
score = abs(c1[0] - c2[0]) + abs(c1[1] - c2[1]) + abs(c1[2] - c2[2]) | |||
if score < best_score: | |||
best_score = score | |||
best_index = index | |||
if score < 20: | |||
break | |||
color_index = best_index | |||
color_map[color_key] = color_index | |||
# hack directly into the 4-bit color buffer instead of: | |||
# epd.pixel(offset_x + x, offset_y + y, color_to_index(color)) | |||
buffer_pos = (offset_x + x + (offset_y + y) * epd_resolution[0]) | |||
buffer_index = buffer_pos // 2 | |||
if buffer_pos % 2 == 1: | |||
buffer_pos = buffer_pos << 4 | |||
epd.buffer[buffer_index] = color_index | |||
def pixel_row_callback(x, y, colors): | |||
pass | |||
#global epd | |||
#print("PXL ", str([color, r,g,b, pixel])) | |||
epd.pixel(x, y, pixel) | |||
#for i in range(len(colors)): | |||
# epd.pixel(offset_x + x + i, offset_y + y, color_to_index(colors[i])) | |||
#print("BMP ", filename, " loading ", str(time.localtime())) | |||
print(str(time.localtime()), " BMP ", filename, " loading") | |||
epd.fill(epd.White) | |||
microbmp.MicroBMP(data_callback=callback).load(filename) | |||
#print("BMP loaded ", str(time.localtime())) | |||
microbmp.MicroBMP(header_callback=header_callback, data_callback=pixel_callback).load(filename) | |||
print(str(time.localtime()), " BMP loaded") | |||
epd.EPD_5IN65F_Display(epd.buffer) | |||
#print("ePaper printed ", str(time.localtime())) | |||
print(str(time.localtime()), " ePaper printed") | |||
# MAIN | |||