Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 5afcdcc

Browse filesBrowse files
feat: img_to_ascii(_2) - Create ascii arts based on images
1 parent 938577b commit 5afcdcc
Copy full SHA for 5afcdcc

File tree

Expand file treeCollapse file tree

8 files changed

+231
-0
lines changed
Filter options
Expand file treeCollapse file tree

8 files changed

+231
-0
lines changed

‎ebook/chapters/third_party_chapters/commandline.tex

Copy file name to clipboardExpand all lines: ebook/chapters/third_party_chapters/commandline.tex
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -133,3 +133,19 @@ \subsection{Cooked Input}
133133
What is your name?: FlOriAn dAhliTz
134134
Florian Dahlitz
135135
\end{lstlisting}
136+
137+
138+
\subsection{Image To ASCII Art}
139+
140+
Once in a while you may want to enhance the look and feel of your command-line application by adding some ascii art to it.
141+
Luckily, the folowing to recipes allow you to create ascii arts based on images.
142+
As both recipes are quite long, they are not display here, but you can find them in the corresponding repository.
143+
144+
The first one saves the ascii art to a file called \lstinline{out.txt} in your current working directory.
145+
The second one prints the resulting ascii art directly to stdout.
146+
Make sure to checkout the code of the first recipe as it shows you, which arguments you can pass to the file.
147+
148+
\begin{lstlisting}[caption=Usage of both recipes]
149+
$ python img_to_ascii.py --file src/python.png --cols 120
150+
$ python img_to_ascii_2.py src/python.png
151+
\end{lstlisting}

‎ebook/python-snippets.epub

Copy file name to clipboard
395 Bytes
Binary file not shown.

‎ebook/python-snippets.mobi

Copy file name to clipboard
438 Bytes
Binary file not shown.

‎ebook/python-snippets.pdf

Copy file name to clipboard
1.68 KB
Binary file not shown.

‎third_party/README.md

Copy file name to clipboardExpand all lines: third_party/README.md
+1Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ A collection of useful snippets using third party packages.
1919
| folium_snippet | Folium is used to create interactive maps |
2020
| formatted_json | Dump json-objects in a formatted way |
2121
| f-strings_vs_str | Compare the time of f-strings and str |
22+
| img_to_ascii(_2) | Create ascii arts based on images |
2223
| inspect_docker | Control docker from within Python |
2324
| interactive_cli | Example of PyInquirer to create interactive CLIs |
2425
| is_holiday | Checks whether a given date is a holiday in a certain country |

‎third_party/img_to_ascii.py

Copy file name to clipboard
+155Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
2+
# Python code to convert an image to ASCII image.
3+
import sys, random, argparse
4+
import numpy as np
5+
import math
6+
7+
from PIL import Image
8+
9+
# gray scale level values from:
10+
# http://paulbourke.net/dataformats/asciiart/
11+
12+
# 70 levels of gray
13+
gscale1 = "$@B%8&WM#*oahkbdpqwmZO0QLCJUYXzcvunxrjft/\|()1{}[]?-_+~<>i!lI;:,\"^`'. "
14+
15+
# 10 levels of gray
16+
gscale2 = '@%#*+=-:. '
17+
18+
def getAverageL(image):
19+
20+
"""
21+
Given PIL Image, return average value of grayscale value
22+
"""
23+
# get image as numpy array
24+
im = np.array(image)
25+
26+
# get shape
27+
w,h = im.shape
28+
29+
# get average
30+
return np.average(im.reshape(w*h))
31+
32+
def covertImageToAscii(fileName, cols, scale, moreLevels):
33+
"""
34+
Given Image and dims (rows, cols) returns an m*n list of Images
35+
"""
36+
# declare globals
37+
global gscale1, gscale2
38+
39+
# open image and convert to grayscale
40+
image = Image.open(fileName).convert('L')
41+
42+
# store dimensions
43+
W, H = image.size[0], image.size[1]
44+
print("input image dims: %d x %d" % (W, H))
45+
46+
# compute width of tile
47+
w = W/cols
48+
49+
# compute tile height based on aspect ratio and scale
50+
h = w/scale
51+
52+
# compute number of rows
53+
rows = int(H/h)
54+
55+
print("cols: %d, rows: %d" % (cols, rows))
56+
print("tile dims: %d x %d" % (w, h))
57+
58+
# check if image size is too small
59+
if cols > W or rows > H:
60+
print("Image too small for specified cols!")
61+
exit(0)
62+
63+
# ascii image is a list of character strings
64+
aimg = []
65+
# generate list of dimensions
66+
for j in range(rows):
67+
y1 = int(j*h)
68+
y2 = int((j+1)*h)
69+
70+
# correct last tile
71+
if j == rows-1:
72+
y2 = H
73+
74+
# append an empty string
75+
aimg.append("")
76+
77+
for i in range(cols):
78+
79+
# crop image to tile
80+
x1 = int(i*w)
81+
x2 = int((i+1)*w)
82+
83+
# correct last tile
84+
if i == cols-1:
85+
x2 = W
86+
87+
# crop image to extract tile
88+
img = image.crop((x1, y1, x2, y2))
89+
90+
# get average luminance
91+
avg = int(getAverageL(img))
92+
93+
# look up ascii char
94+
if moreLevels:
95+
gsval = gscale1[int((avg*69)/255)]
96+
else:
97+
gsval = gscale2[int((avg*9)/255)]
98+
99+
# append ascii char to string
100+
aimg[j] += gsval
101+
102+
# return txt image
103+
return aimg
104+
105+
# main() function
106+
def main():
107+
# create parser
108+
descStr = "This program converts an image into ASCII art."
109+
parser = argparse.ArgumentParser(description=descStr)
110+
# add expected arguments
111+
parser.add_argument('--file', dest='imgFile', required=True)
112+
parser.add_argument('--scale', dest='scale', required=False)
113+
parser.add_argument('--out', dest='outFile', required=False)
114+
parser.add_argument('--cols', dest='cols', required=False)
115+
parser.add_argument('--morelevels',dest='moreLevels',action='store_true')
116+
117+
# parse args
118+
args = parser.parse_args()
119+
120+
imgFile = args.imgFile
121+
122+
# set output file
123+
outFile = 'out.txt'
124+
if args.outFile:
125+
outFile = args.outFile
126+
127+
# set scale default as 0.43 which suits
128+
# a Courier font
129+
scale = 0.43
130+
if args.scale:
131+
scale = float(args.scale)
132+
133+
# set cols
134+
cols = 80
135+
if args.cols:
136+
cols = int(args.cols)
137+
138+
print('generating ASCII art...')
139+
# convert image to ascii txt
140+
aimg = covertImageToAscii(imgFile, cols, scale, args.moreLevels)
141+
142+
# open file
143+
f = open(outFile, 'w')
144+
145+
# write to file
146+
for row in aimg:
147+
f.write(row + '\n')
148+
149+
# cleanup
150+
f.close()
151+
print("ASCII art written to %s" % outFile)
152+
153+
# call main
154+
if __name__ == '__main__':
155+
main()

‎third_party/img_to_ascii_2.py

Copy file name to clipboard
+59Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
from PIL import Image
2+
3+
ASCII_CHARS = [ '#', '?', '%', '.', 'S', '+', '.', '*', ':', ',', '@']
4+
5+
def scale_image(image, new_width=100):
6+
"""Resizes an image preserving the aspect ratio.
7+
"""
8+
(original_width, original_height) = image.size
9+
aspect_ratio = original_height/float(original_width)
10+
new_height = int(aspect_ratio * new_width)
11+
12+
new_image = image.resize((new_width, new_height))
13+
return new_image
14+
15+
def convert_to_grayscale(image):
16+
return image.convert('L')
17+
18+
def map_pixels_to_ascii_chars(image, range_width=25):
19+
"""Maps each pixel to an ascii char based on the range
20+
in which it lies.
21+
22+
0-255 is divided into 11 ranges of 25 pixels each.
23+
"""
24+
25+
pixels_in_image = list(image.getdata())
26+
pixels_to_chars = [ASCII_CHARS[pixel_value//range_width] for pixel_value in
27+
pixels_in_image]
28+
29+
return "".join(pixels_to_chars)
30+
31+
def convert_image_to_ascii(image, new_width=100):
32+
image = scale_image(image)
33+
image = convert_to_grayscale(image)
34+
35+
pixels_to_chars = map_pixels_to_ascii_chars(image)
36+
len_pixels_to_chars = len(pixels_to_chars)
37+
38+
image_ascii = [pixels_to_chars[index: index + new_width] for index in
39+
range(0, len_pixels_to_chars, new_width)]
40+
41+
return "\n".join(image_ascii)
42+
43+
def handle_image_conversion(image_filepath):
44+
image = None
45+
try:
46+
image = Image.open(image_filepath)
47+
except Exception as e:
48+
print("Unable to open image file {image_filepath}.".format(image_filepath=image_filepath))
49+
print(e)
50+
return
51+
52+
image_ascii = convert_image_to_ascii(image)
53+
print(image_ascii)
54+
55+
if __name__=='__main__':
56+
import sys
57+
58+
image_file_path = sys.argv[1]
59+
handle_image_conversion(image_file_path)

‎third_party/src/python.png

Copy file name to clipboard
50.9 KB
Loading

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.