added color

This commit is contained in:
iou1name 2017-11-26 14:04:47 -05:00
parent 2eb6dd716c
commit 72211f6688

123
ascii.py Normal file → Executable file
View File

@ -12,7 +12,7 @@ import numpy as np
import numpngw import numpngw
ASCII_CHARS = "$@%#*+=-:. " ASCII_CHARS = "$@%#*+=-:. "
HEADERS = {'User-Agent': 'bix nood where dah ascii tiddies at'} HEADERS = {'User-Agent': 'Gimme the ascii.'}
def scale_image(image, size=(100,100)): def scale_image(image, size=(100,100)):
@ -51,22 +51,68 @@ def pixels_to_chars(image, reverse=False):
""" """
range_width = int(255 / len(ASCII_CHARS)) + (255 % len(ASCII_CHARS) > 0) range_width = int(255 / len(ASCII_CHARS)) + (255 % len(ASCII_CHARS) > 0)
pixels_in_image = list(image.getdata()) pixels = list(image.getdata())
pixels_to_chars = [] chars = []
for pixel_value in pixels_in_image: for pixel in pixels:
if reverse: if reverse:
index = -int(pixel_value/range_width)-1 index = -int(pixel/range_width)-1
else: else:
index = int(pixel_value/range_width) index = int(pixel/range_width)
pixels_to_chars.append(ASCII_CHARS[index]) chars.append(ASCII_CHARS[index])
return "".join(pixels_to_chars) chars = "".join(chars)
chars = [chars[i:i + image.size[0]] for i in range(0, len(chars),
image.size[0])]
return "\n".join(chars)
def char_color(pixel, code="irc"):
"""
Maps a color to a character based on the original pixel color.
Calculates the distance from the provided color to each of the 16
colors in the IRC and ANSI color codes and selects the closest match.
"""
colors_index = ["white", "black", "blue", "green", "red", "brown", "purple",
"orange", "yellow", "light green", "teal", "cyan", "light blue", "pink",
"grey", "silver"]
colors_rgb = {"white": (0,0,0), "black": (255,255,255), "blue": (0,0,255),
"green": (0,255,0), "red": (255,0,0), "brown": (150,75,0),
"purple": (128,0,128), "orange": (255,128,0), "yellow": (255,255,0),
"light green": (191,255,0), "teal": (0,128,128), "cyan": (0,255,255),
"light blue": (65,105,225), "pink":(255,192,203), "grey": (128,128,128),
"silver": (192,192,192)}
colors_irc = {"white": "0", "black": "1", "blue": "2", "green": "3", "red": "4",
"brown": "5", "purple": "6", "orange": "7", "yellow": "8", "light green": "9",
"teal": "10", "cyan": "11", "light blue": "12", "pink": "13", "grey": "14",
"silver": "15"}
colors_ansi = {"white": "[1;37m", "black": "[0;30m", "blue": "[0;34m",
"green": "[0;32m", "red": "[0;31m", "brown": "[0;33m",
"purple": "[0;35m", "orange": "[1;31m", "yellow": "[1;33m",
"light green": "[1;32m", "teal": "[0;36m", "cyan": "[1;36m",
"light blue": "[1;34m", "pink": "[1;35m", "grey": "[1;30m",
"silver": "[0;37m"}
dist = [(abs(pixel[0] - colors_rgb[color][0])**2
+ abs(pixel[1] - colors_rgb[color][1])**2
+ abs(pixel[2] - colors_rgb[color][2])**2)**0.5
for color in colors_index]
color = colors_index[dist.index(min(dist))]
if code == "irc":
return colors_irc[color]
elif code == "ansi":
return colors_ansi[color]
def open_image(imagePath): def open_image(imagePath):
""" """
Opens the image at the supplied file path in PIL. If an internet URL Opens the image at the supplied file path in PIL. If an internet URL
is supplied, it will download the image and then open it. is supplied, it will download the image and then open it. Returns a
PIL image object.
""" """
try: try:
if imagePath.startswith("http"): if imagePath.startswith("http"):
@ -77,39 +123,53 @@ def open_image(imagePath):
else: else:
image = Image.open(imagePath) image = Image.open(imagePath)
except FileNotFoundError as e: except FileNotFoundError as e:
return e return f"File not found: {imagePath}"
except OSError:
return e
except Exception as e: except Exception as e:
return("Error opening image file: " + imagePath) return(f"Error opening image: {imagePath}\n{e}")
return image return image
def image_to_ascii(image, reverse=False): def colorize(chars, image, code):
"""
Colorizes the ascii matrix.
"""
prefix = {"irc": "\03", "ansi":"\033"}
chars = chars.split("\n")
for j in range(0, image.size[1]):
new_row = ""
for k in range(0, image.size[0]):
new_row += prefix[code] + char_color(image.getpixel((k,j)), code)
new_row += chars[j][k]
chars[j] = new_row
return "\n".join(chars)
def image_to_ascii(image, reverse=False, colors=None):
""" """
Reads an image file and converts it to ascii art. Returns a Reads an image file and converts it to ascii art. Returns a
newline-delineated string. If reverse is True, the ascii scale is newline-delineated string. If reverse is True, the ascii scale is
reversed. reversed.
""" """
image = scale_image(image) image = scale_image(image)
image = image.convert('L') # convert to grayscale image_grey = image.convert('L') # convert to grayscale
chars = pixels_to_chars(image, reverse) chars = pixels_to_chars(image_grey, reverse)
image_ascii = [] if colors:
for index in range(0, len(chars), image.size[0]): chars = colorize(chars, image, colors)
image_ascii.append(chars[index: index + image.size[0]])
image.close() image.close()
image_grey.close()
del(image) del(image)
return "\n".join(image_ascii) del(image_grey)
return chars
def ascii_to_image(image_ascii): def ascii_to_image(image_ascii):
""" """
Creates a plain image and draws text on it. Creates a plain image and draws text on it.
""" """
# TODO: make font type, size, and image size non-fixed # TODO: make font type and size non-fixed
width = len(image_ascii[:image_ascii.index("\n")]) * 8 width = len(image_ascii[:image_ascii.index("\n")]) * 8
height = (image_ascii.count("\n")+1) * 12 + 4 height = (image_ascii.count("\n")+1) * 12 + 4
@ -120,7 +180,10 @@ def ascii_to_image(image_ascii):
return image return image
def handle_gif(output, reverse=False): def handle_gif(image, output, reverse=False):
"""
Handle gifs seperately.
"""
image = open_image(args.imagePath) image = open_image(args.imagePath)
ascii_seq = [] ascii_seq = []
new_image = ascii_to_image(image_to_ascii(image, reverse)) new_image = ascii_to_image(image_to_ascii(image, reverse))
@ -137,8 +200,6 @@ def handle_gif(output, reverse=False):
# duration=60, loop=0, optimize=True) # duration=60, loop=0, optimize=True)
ascii_seq = [new_image] + ascii_seq ascii_seq = [new_image] + ascii_seq
np_ascii_seq = [np.array(im) for im in ascii_seq] np_ascii_seq = [np.array(im) for im in ascii_seq]
#images2gif.writeGif(output, ascii_seq, nq=10, subRectangles=False)
#imageio.mimsave(output, np_ascii_seq)
with open(output, "wb") as file: with open(output, "wb") as file:
numpngw.write_apng(file, np_ascii_seq) numpngw.write_apng(file, np_ascii_seq)
@ -171,6 +232,11 @@ if __name__=='__main__':
"--animated", "--animated",
action="store_true", action="store_true",
help="Handles animated GIFs. Includes --image.") help="Handles animated GIFs. Includes --image.")
parser.add_argument(
"-c",
"--color",
type=str,
help="Colorizes the ascii matrix.")
parser.set_defaults(reverse=False, image=False, animated=False) parser.set_defaults(reverse=False, image=False, animated=False)
args = parser.parse_args() args = parser.parse_args()
@ -180,11 +246,12 @@ if __name__=='__main__':
if not args.output: if not args.output:
parser.error("--image requires --output") parser.error("--image requires --output")
if args.animated:
handle_gif(args.output, args.reverse)
else:
image = open_image(args.imagePath) image = open_image(args.imagePath)
image_ascii = image_to_ascii(image, args.reverse) if args.animated:
handle_gif(image, args.output, args.reverse)
exit()
image_ascii = image_to_ascii(image, args.reverse, args.color)
if args.image: if args.image:
image = ascii_to_image(image_ascii) image = ascii_to_image(image_ascii)
image.save(args.output, "PNG") image.save(args.output, "PNG")