from typing import List from math import sqrt from bitmap import Bitmap class Image: def __init__(self, name: str, width: int, height: int, empty: bool = False) -> None: self.name = name self.width = width self.height = height self.modified = False if empty: self.data = [0] * ((width * height) // 8) self.modified = True else: self.data = [] def finalize(self) -> None: if self.width == 0: pixels = len(self.data) * 8 width = int(sqrt(pixels)) while width > 1 and pixels % width != 0: width -= 1 self.width = width self.height = pixels // width def add_data(self, raw_data: List[str]) -> None: for v in raw_data: self.data += [int(v, 16)] def __get_position(self, x: int, y: int) -> int: real_width = (len(self.data) * 8) // self.height return y * real_width + x def get_pixel(self, x: int, y: int) -> bool: position = self.__get_position(x, y) chunk_id = position // 8 try: return self.data[chunk_id] & (1 << (7 - position % 8)) > 0 except: return False def set_pixel(self, x: int, y: int, v: bool) -> None: position = self.__get_position(x, y) chunk_id = position // 8 if v != self.get_pixel(x, y): try: if v: self.data[chunk_id] |= 1 << (7 - position % 8) else: self.data[chunk_id] &= ~(1 << (7 - position % 8)) except: pass self.modified = True def __get_color_bytes(self) -> bytes: output = bytes() for y in range(self.height): for x in range(self.width): if self.get_pixel(x, y): output += bytes([0, 0, 0]) else: output += bytes([255, 255, 255]) return output def export_bmp(self, path: str) -> None: Bitmap.write_bmp(path, self.width, 3, self.__get_color_bytes()) def __set_color_bytes(self, color_depth: int, data: bytes) -> None: for y in range(self.height): for x in range(self.width): position = (y * self.width + x) * color_depth colors = data[position : position + color_depth] mean_color = sum(c for c in colors) / color_depth if mean_color < 128: self.set_pixel(x, y, True) def import_bmp(self, path: str) -> None: self.width, self.height, color_depth, bmp_data = Bitmap.read_bmp(path) self.data = [0] * ((self.width * self.height) // 8) self.__set_color_bytes(color_depth, bmp_data) def export_cpp(self) -> str: # 16 per line output = [ f"// '{self.name}', {self.width}x{self.height}px", f"const unsigned char {self.name} [] PROGMEM = {{", ] while len(self.data) > 16: output += ["\t" + ", ".join(f"0x{v:02x}" for v in self.data[0:16]) + ","] self.data = self.data[16:] output += ["\t" + ", ".join(f"0x{v:02x}" for v in self.data), "};", ""] return "\n".join(output)