made citf
This commit is contained in:
parent
fccdf56188
commit
af68d788b0
105
ctif.py
105
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)
|
||||
|
||||
|
||||
13
filters.py
13
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())
|
||||
|
||||
|
||||
7
main.py
7
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()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user