diff --git a/ctif.py b/ctif.py index 0399613..920cf08 100644 --- a/ctif.py +++ b/ctif.py @@ -2,6 +2,7 @@ import logging import math import os +from rich.console import Console from PIL import Image import pygame as pg @@ -39,12 +40,38 @@ CHARS = list(reversed([ ' ' ])) +ALL_CHARS = [ + u'█', + '@', + '?', + 'O', + 'P', + 'o', + 'c', + 'i', + '.', + ' ', + '|', + '/', + '-', + '\\' +] + # Character Text Image Format class CTIF: - data: list + colors: list + text: str + width: int + height: int - def __init__(self): - pass + def __init__(self, image: Image.Image | None = None): + self.colors = [] + self.text = "" + self.width = 0 + self.height = 0 + + if image: + self.convert(image) def convert(self, image: Image.Image) -> None: @@ -66,12 +93,10 @@ class CTIF: sb.save('debug/sobel.png') text_grid_width = w / SCALED_WIDTH + self.width = text_grid_width + text_grind_height = h / SCALED_HEIGHT - - pg.init() - font = pg.font.Font(FONT_PATH, 12) - window = pg.display.set_mode((text_grid_width * TEXT_WIDTH, text_grind_height * TEXT_HEIGHT)) - + self.height = text_grind_height y_offset = 0 for y in range(math.floor(h / SCALED_HEIGHT)): @@ -81,7 +106,7 @@ class CTIF: histogram = {} # Collect the most common char for a group of pixels - colors = [] + color = [] for y2 in range(SCALED_HEIGHT): for x2 in range(SCALED_WIDTH): @@ -103,9 +128,10 @@ class CTIF: else: histogram[char] = 1 - colors.append(image.getpixel((real_x, real_y))) + color.append(image.getpixel((real_x, real_y))) - color_avg = self._average_colors(colors) + color_avg = filters.average_colors(color) + self.colors.append(color_avg) # get most common most_common = None @@ -115,16 +141,12 @@ class CTIF: score = histogram[char] most_common = char - rendered_char = font.render(str(most_common), True, color_avg) - window.blit(rendered_char, (x * TEXT_WIDTH, y * TEXT_HEIGHT)) + self.text += str(most_common) x_offset += SCALED_WIDTH y_offset += SCALED_HEIGHT - pg.display.update() - pg.image.save(window, "render.png") - pg.quit() # TODO @0x01FE : refactor plz increment by 30 & 60 @@ -151,15 +173,50 @@ class CTIF: else: return '|' - def _average_colors(self, colors: list): - avg = [0 for x in range(len(colors[0]))] + def render(self) -> None: + console = Console() + for i, (color, char) in enumerate(zip(self.colors, self.text)): - for color in colors: - for i, num in enumerate(color): - avg[i] += num + hex_color = '#%x%x%x' % color - for i, n in enumerate(avg): - avg[i] /= len(colors) + console.print(f'[{hex_color}]{char}', end='') - return avg + if i + 1 % self.width == 0: + print() + + def save_image(self, path: str) -> None: + pg.init() + font = pg.font.Font(FONT_PATH, 12) + + window = pg.display.set_mode((self.width * TEXT_WIDTH, self.height * TEXT_HEIGHT)) + + x, y = 0, 0 + for (color, char) in zip(self.colors, self.text): + rendered_char = font.render(char, True, color) + window.blit(rendered_char, (x * TEXT_WIDTH, y * TEXT_HEIGHT)) + + x += 1 + + if x == self.width: + x = 0 + y += 1 + + pg.display.update() + pg.image.save(window, path) + pg.quit() + + def save_citf(self, filename: str) -> None: + # 3 byte for color, byte for char + + b = bytes() + + for (color, char) in zip(self.colors, self.text): + + for n in color: + b += n.to_bytes(1, 'big') + + b += ALL_CHARS.index(char).to_bytes(1, 'big') + + with open(f'{filename}.citf', 'wb+') as file: + file.write(b) diff --git a/filters.py b/filters.py index 5fca603..8521e5a 100644 --- a/filters.py +++ b/filters.py @@ -69,3 +69,16 @@ def sobel(img: Image.Image, gradient_threshold: int | None = 20) -> tuple[Image. return (newimg, gradient) +def average_colors(colors: list) -> tuple: + colors = np.array(colors) + + np.average(colors) + + sum = np.zeros(len(colors[0])) + for c in colors: + sum += c + + sum /= len(colors) + + return tuple(sum.astype(np.uint8).tolist()) + diff --git a/main.py b/main.py index fd2335e..985291e 100644 --- a/main.py +++ b/main.py @@ -1,7 +1,8 @@ import logging from PIL import Image -import asciify +import ctif + FORMAT = "%(levelname)s %(filename)s - %(message)s" logging.basicConfig(level=logging.DEBUG, format=FORMAT) @@ -11,7 +12,9 @@ IMAGE_PATH = 'sample-images/engine.PNG' def main(): image = Image.open(IMAGE_PATH) - asciify.asciify(image) + i = ctif.CTIF(image) + # i.save_image('render.png') + i.save_citf('engine') if __name__ == '__main__': main()