1. 介绍
ASCII 字符画 (ASCII Art) 是一种使用 ASCII 文本字符表示图像的创造性表达,可以追溯到图形界面受限的早期计算时代。 尽管技术在不断发展,但 ASCII 字符画经受住了时间的考验,在社交媒体平台、代码库和数字艺术社区中重新流行起来。 这篇文章将向您介绍使用 Python 生成 ASCII 字符画的方法和过程。
2. 准备工作
要使用 Python 制作 ASCII 艺术作品,您需要在计算机上设置 Python 环境。 如果您还没有,请从官方网站 (https://www.python.org/downloads/) 下载并安装 Python。 安装 Python 后,您需要安装 Pillow 库,用于打开、操作和保存图像文件:
要安装 Pillow 库,请打开终端或命令提示符并运行以下命令:
pip install pillow
3. 生成黑白的 ASCII 字符画
从图像创建 ASCII 艺术作品涉及几个基本步骤:调整图像大小、将其转换为灰度以及将灰度像素映射到 ASCII 字符。 在本节中,我们将使用 Python 和 Pillow 库完成这些步骤。
3.1 第 1 步:调整图像大小并将其转换为灰度
要使图像适合 ASCII 字符画,需要先将高分辨率图像调整为较小的分辨率,并将图像转换为灰度,因为 ASCII 字符画主要依靠灰色阴影来表示细节。
import PIL.Image as Image import PIL.ImageDraw as ImageDraw import PIL.ImageFont as ImageFont # 将图像调整为指定大小 def resize_image(image_path, output_width, output_height): # 打开图像 image = Image.open(image_path) # 调整图像大小 image = image.resize((output_width, output_height)) return image # 将图像转换为灰度图像 def convert_to_gray(image): return image.convert('L')
3.2 第 2 步:将灰度像素映射到 ASCII 字符
经过第1 步我们有了一个调整大小后的灰度图像,我们需要将每个像素的灰度值映射到一个 ASCII 字符。 为此,我们创建一串按视觉密度排序的 ASCII 字符,并将灰度值映射到这些字符。
# 将像素映射为 ASCII 字符 def map_pixels_to_ascii(gray_image, ascii_chars): ascii_image = [] # 遍历输出图像的每一行 for y in range(output_height): row = "" # 遍历输出图像的每一列 for x in range(output_width): # 获取当前像素的灰度值 gray_value = gray_image.getpixel((x, y)) # 根据灰度值计算对应的 ASCII 字符的索引 char_index = int(gray_value / 255 * (len(ascii_chars) - 1)) # 将对应的 ASCII 字符添加到当前行中 row += ascii_chars[char_index] # 将当前行添加到 ASCII 图像中 ascii_image.append(row) # 将 ASCII 字符画转换为字符串并返回 return "\n".join(ascii_image)
map_pixels_to_ascii
函数接受两个参数:
gray_image
,输入的灰度图像。ascii_chars
,用于映射像素的 ASCII 字符集。ASCII 字符集的原则是按视觉密度排序,如@%#*+=-:.
。
3.3 第 3 步:将图像转换为 ASCII 字符画
通过组织第1步、第2步中的函数我们可以将图像转换为 ASCII 字符画。其基本流程为:调整图像大小 → 转换为灰度图像 → 用 ASCII 字符替换像素。
# 将图像转换为黑白 ASCII 字符画 def image_to_bw_ascii(image_path, output_width, output_height): # 调整图片大小 resized_image = resize_image(image_path, output_width, output_height) # 转换为灰度图像 gray_image = convert_to_gray(resized_image) # 用 ASCII 字符替换像素 ascii_image = map_pixels_to_ascii(gray_image, bw_ascii_chars) return ascii_image
image_to_bw_ascii
函数接收三个参数:
image_path
,原始图片。可以是绝对路径,也可以是相对路径。output_width
,输出字符画的宽度。对于文本形式的字符画,如显示在终端窗口的字符画,其单位为列;对于图像形式的字符画,如存储在图片文件中的字符画,其单位为像素。output_height
,输出字符画的高度。对于文本形式的字符画,如显示在终端窗口的字符画,其单位为行;对于图像形式的字符画,如存储在图片文件中的字符画,其单位为像素。
3.4 第 4 步:存储 ASCII 字符画到文本文件
ASCII 字符画是由字符组成的,因此可以将其存储到文本文件中。
# 存储黑白 ASCII 字符画到文本文件 def save_bw_ascii_image_as_text(ascii_image, output_path): with open(output_path, 'w') as file: file.write(ascii_image)
save_bw_ascii_image_as_text
函数接收三个参数:
ascii_image
,ASCII 字符画。output_path
,存储 ASCII 字符画的文本文件。
3.5 第 5 步:存储 ASCII 字符画到图像文件
使用 Pillow 库可以将 ASCII 字符画存储为 jpg、png 等图片文件。
# 存储黑白 ASCII 字符画到图片 def save_bw_ascii_image_as_picture(ascii_image, font_path, font_size, output_path): # 将输入的 ASCII 字符画按换行符拆分 lines = ascii_image.split('\n') # 根据最长行的长度和行数计算出结果图像的宽度和高度 width = max(len(line) for line in lines) height = len(lines) # 使用计算出的尺寸和白色背景颜色创建一个新的 RGB 图像 image = Image.new('RGB', ((width * font_size), height * font_size), color='white') # 使用 ImageDraw.Draw 方法创建一个 Draw 对象 draw = ImageDraw.Draw(image) # 使用 ImageFont.truetype 方法创建一个 Font 对象 font = ImageFont.truetype(font_path, font_size) # 遍历 ASCII 艺术输入中的每个字符,并使用 Draw.text 方法将其绘制到图像上 for y, line in enumerate(lines): for x, char in enumerate(line): # 根据其 x 和 y 坐标以及 font_size 参数计算每个字符的位置 draw.text((x * font_size, y * font_size), char, font=font, fill='black') # 使用 Image.save 方法将生成的图像保存到 output_path 参数中 image.save(output_path)
save_bw_ascii_image_as_picture
函数接收四个参数:
ascii_image
,ASCII 字符画。font_path
,绘图所用字体。font_size
,绘图字体大小。output_path
,图片文件。
3.6 效果展示
把上面的步骤串联起来就可以将一幅图片转换为 ASCII 字符画,并将它输出到终端、保存到文本文件、保存到图片文件中。
# 定义输出宽度和高度(行/像素) output_width = 60 output_height = 35 # 定义黑白 ASCII 字符画绘图字体和字体大小 bw_ascii_image_font = "arial.ttf" bw_ascii_image_font_size = 8 # 定义黑白 ASCII 字符画替换像素的 ASCII 字符 bw_ascii_chars = "@%#*+=-:. " if __name__ == "__main__": image_path = "path/to/your/image.jpg" # 生成黑白 ASCII 字符画 bw_ascii_image = image_to_bw_ascii(image_path, output_width, output_height) # 输出到终端 print(bw_ascii_image) # 存储黑白 ASCII 字符画到文本文件 save_bw_ascii_image_as_text(bw_ascii_image, "bw_ascii_image.txt") # 存储黑白 ASCII 字符画到图片文件 save_bw_ascii_image_as_picture(bw_ascii_image, bw_ascii_image_font, bw_ascii_image_font_size, "bw_ascii_image.png")
注意将 "path/to/your/image.jpg"
替换为图像文件的路径。 您可以调整 output_width
和 output_height
变量来控制生成的 ASCII 字符画的大小。您还可以调整bw_ascii_chars
变量来观察不同字符生成的 ASCII 字符画的效果。
下面是生成的 ASCII 字符画的效果示例。
原图:
终端输出效果:
生成的文本文件效果:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@###@@@@@@@@@@@@@@@@@@@@%####@@@@@@@@@@@@@@@ @@@@@@@@@@@@@##*######@@@@@@@@@@@@@@@@##*######@@@@@@@@@@@@@ @@@@@@@@@@@@@#+.:---*# @@@@@@@@@@@@@@ #+.::::*#@@@@@@@@@@@@@ @@@@@@@@@@@@@#*++***## @@@@@@@@@@@@@@ #*+++++*#@@@@@@@@@@@@@ @@@@@@@@@@@@@##+:::=##@@@@@@@@@@@@@@@@*##-:-###@@@@@@@@@@@@@ @@@@@@@@@@@@##= =##@@@@@@@@@@@@@ ###*. .*###@@@@@@@@@@@@ @@@@@@@@@@@##- -##@@@@@@@@@@@##*=:. .:=*##@@@@@@@@@@ @@@@@@@@@@##- .......-##@@@@@@@@@##=. .........=##@@@@@@@@@ @@@@@@@@@*#- .:.......=#*@@@@@@@*#: :::::::::::=#*@@@@@@@@ @@@@@@@@ #+. ...........*#:@@@@@-#+ .::::::::::::*# @@@@@@@ @@@@@@@@*#: .:.........-#*@@@@@+#= .::::::::::::+#-@@@@@@@ @@@@@@@@#*. ............:*#@@@@@+#= .::::::::::::+#-@@@@@@@ @@@@@@@ #+ .:...........+#:@@@@+#= .::::::::::::+#-@@@@@@@ @@@@@@@:#= .............=#+@@@@+#= .::::::::::::=#-@@@@@@@ @@@@@@@*#*+++++++++++++++*#*@@@@+#*+++*************#*@@@@@@@ @@@@@@@*#+::-============*#*@@@@+#+:::------------+#*@@@@@@@ @@@@@@@*#= .------------+#*@@@@+#= .::::::::::::+#*@@@@@@@ @@@@@@@*#= :--------====*#*@@@@+#= .::::::::----+#*@@@@@@@ @@@@@@@*#= :--------****##*@@@@+#= .:::::::-+**+##*@@@@@@@ @@@@@@@*#= :------------+#*@@@@+#= .::::::::::::+#*@@@@@@@ @@@@@@@*#= :------------+#*@@@@+#= .::::::::----+#*@@@@@@@ @@@@@@@*#= :--------****##*@@@@+#= .:::::::-****##*@@@@@@@ @@@@@@@*#= :------------+#*@@@@+#= .::::::::::::+#*@@@@@@@ @@@@@@@*#= .------------+#*@@@@+#= .::::::::::::+#*@@@@@@@ @@@@@@@*#*==+***********+*#*@@@@+#*==+++++++++++++*#*@@@@@@@ @@@@@@@=#+---------------+#*@@@@+#+---============+#-@@@@@@@ @@@@@@@-#- .............=#*@@@@+#= .::::::::::::=#-@@@@@@@ @@@@@@@-#= .:...........=#*@@@@+#= .::::::::::::+#-@@@@@@@ @@@@@@@-#= .:...........=#+@@@@+#= .::::::::::::+#:@@@@@@@ @@@@@@@ #*. ............:*# @@@@ #*. .::::::::::::*# @@@@@@@ @@@@@@@@*#*-..:::::::::-*#*@@@@@@*#*-..::::::::-=*#*@@@@@@@@ @@@@@@@@@@###*********###@@@@@@@@@@###********####@@@@@@@@@@ @@@@@@@@@@@@@*#######*@@@@@@@@@@@@@@@@@##******@@@@@@@@@@@@@ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
生成的图片效果:
3.7 完整代码
# gen-bw-ascii-image.py import PIL.Image as Image import PIL.ImageDraw as ImageDraw import PIL.ImageFont as ImageFont # 定义输出宽度和高度(行/像素) output_width = 60 output_height = 35 # 定义黑白 ASCII 字符画绘图字体和字体大小 bw_ascii_image_font = "arial.ttf" bw_ascii_image_font_size = 8 # 定义黑白 ASCII 字符画替换像素的 ASCII 字符 bw_ascii_chars = "@%#*+=-:. " # 将图像调整为指定大小 def resize_image(image_path, output_width, output_height): image = Image.open(image_path) image = image.resize((output_width, output_height)) return image # 将图像转换为灰度图像 def convert_to_gray(image): return image.convert('L') # 将像素映射为 ASCII 字符 def map_pixels_to_ascii(gray_image, ascii_chars): ascii_image = [] for y in range(output_height): row = "" for x in range(output_width): gray_value = gray_image.getpixel((x, y)) char_index = int(gray_value / 255 * (len(ascii_chars) - 1)) row += ascii_chars[char_index] ascii_image.append(row) return "\n".join(ascii_image) # 将图像转换为黑白 ASCII 字符画 def image_to_bw_ascii(image_path, output_width, output_height): resized_image = resize_image(image_path, output_width, output_height) gray_image = convert_to_gray(resized_image) ascii_image = map_pixels_to_ascii(gray_image, bw_ascii_chars) return ascii_image # 存储黑白 ASCII 字符画到文本文件 def save_bw_ascii_image_as_text(ascii_image, output_path): with open(output_path, 'w') as file: file.write(ascii_image) # 存储黑白 ASCII 字符画到图片 def save_bw_ascii_image_as_picture(ascii_image, font_path, font_size, output_path): lines = ascii_image.split('\n') width = max(len(line) for line in lines) height = len(lines) image = Image.new('RGB', ((width * font_size), height * font_size), color='white') draw = ImageDraw.Draw(image) font = ImageFont.truetype(font_path, font_size) for y, line in enumerate(lines): for x, char in enumerate(line): draw.text((x * font_size, y * font_size-), char, font=font, fill='black') image.save(output_path) if __name__ == "__main__": image_path = "path/to/your/image.jpg" # 生成黑白 ASCII 字符画 bw_ascii_image = image_to_bw_ascii(image_path, output_width, output_height) # 存储黑白 ASCII 字符画到文本文件 save_bw_ascii_image_as_text(bw_ascii_image, "bw_ascii_image.txt") # 存储黑白 ASCII 字符画到图片文件 save_bw_ascii_image_as_picture(bw_ascii_image, bw_ascii_image_font, bw_ascii_image_font_size, "bw_ascii_image.png") # 在终端窗口打印彩色 ASCII 字符画 print(bw_ascii_image)
4. 生成彩色的 ASCII 字符画
在色彩斑斓的现代社会 ASCII 字符画也要进步,下面我们探索如何生成彩色的 ASCII 字符画。
生成彩色 ASCII 字符画的步骤与生成黑白 ASCII 字符画的步骤基本相同,详述如下。
4.1 第 1 步:调整图像大小并将其转换为灰度
此步骤与生成黑白 ASCII 字符画的第 1 步相同,此处略过。
4.2 第 2 步:将图像转换为 ASCII 字符画
对于彩色字符画我们需要逐个像素地扫描图像,提取像素颜色,并完成像素到字符的映射,同时将扫描的信息存储起来,从而实现将图像转换为彩色的 ASCII 字符画。
# 将图像转换为彩色 ASCII 字符画 def image_to_colored_ascii(image_path, output_width, output_height): # 调整图片大小 resized_image = resize_image(image_path, output_width, output_height) # 创建 ASCII 字符画 ascii_image = [] ascii_image_chars = [] ascii_image_colors=[] for y in range(output_height): row = "" for x in range(output_width): # 获取像素颜色 color = resized_image.getpixel((x, y)) # 计算灰度值并选择相应的 ASCII 字符 gray_value = sum(color) // 3 char_index = int(gray_value / 255 * (len(colored_ascii_chars) - 1)) if char_index >= len(colored_ascii_chars): char_index = len(colored_ascii_chars) - 1 # 将 ASCII 字符和颜色添加到行中 row += f"\033[38;2;{color[0]};{color[1]};{color[2]}m{colored_ascii_chars[char_index]}" # 存储字符和颜色 ascii_image_chars.append(colored_ascii_chars[char_index]) ascii_image_colors.append((color[0], color[1], color[2])) # 将行添加到 ASCII 字符画中 ascii_image.append(row) return "\n".join(ascii_image), ascii_image_chars, ascii_image_colors
4.3 第 3 步:存储 ASCII 字符画到图像文件
下面的函数是将彩色 ASCII 字符画存储为图片。它通过创建一个新的 RGB 图像来实现,该图像的尺寸为 output_width * font_size
和 output_height * font_size
。然后使用 ImageDraw 模块将 ASCII 字符以及相应的颜色绘制到图像上。最后,将图像保存到指定的 output_path。
# 将彩色 ASCII 艺术图像存储为图片 def save_colored_ascii_image_as_picture(ascii_image_chars, ascii_image_colors, font_path, font_size, output_path): # 创建一个新的 RGB 图像 image = Image.new('RGB', ((output_width * (font_size-3)), (output_height * (font_size-1))), color='black') draw = ImageDraw.Draw(image) font = ImageFont.truetype(font_path, font_size) # 绘制 ASCII 字符和颜色 for i in range(output_height): for j in range(output_width): draw.text((j * (font_size-3), i * (font_size-1)), ascii_image_chars[i*output_width+j], font=font, fill=ascii_image_colors[i*output_width+j]) # 保存图像 image.save(output_path)
4.4 效果展示
将上面的代码组织一下就可以实现我们的目标了:将一幅图片转换为彩色 ASCII 字符画,并将它输出到终端、保存到图片文件中。
# 定义输出宽度和高度(行/像素) output_width = 60 output_height = 35 # 定义彩色 ASCII 字符画绘图字体和字体大小 colored_ascii_image_font = "arial.ttf" colored_ascii_image_font_size = 8 # 定义彩色 ASCII 字符画替换像素的 ASCII 字符 colored_ascii_chars = ["0", "1", "2", "3", "4", "5", "6", "8", "9"] if __name__ == "__main__": image_path = "path/to/your/image.jpg" # 将图像转换为彩色 ASCII 字符画 colored_ascii_image, colored_ascii_image_chars, colored_ascii_image_colors = image_to_colored_ascii(image_path, output_width, output_height) # 存储彩色 ASCII 字符画到图片文件 save_colored_ascii_image_as_picture(colored_ascii_image_chars, colored_ascii_image_colors, colored_ascii_image_font, colored_ascii_image_font_size, "colored_ascii_image.png") # 在终端窗口打印彩色 ASCII 字符画 print(colored_ascii_image)
注意将 "path/to/your/image.jpg"
替换为图像文件的路径。
下面是生成的彩色 ASCII 字符画的效果示例。
终端输出效果:
生成的图片效果:
4.5 更多效果展示
4.6 完整代码
# gen-colored-ascii-image.py import PIL.Image as Image import PIL.ImageDraw as ImageDraw import PIL.ImageFont as ImageFont # 定义输出宽度和高度(行/像素) output_width = 60 output_height = 35 # 定义彩色 ASCII 字符画绘图字体和字体大小 colored_ascii_image_font = "arialbd.ttf" colored_ascii_image_font_size = 8 # 定义彩色 ASCII 字符画替换像素的 ASCII 字符 colored_ascii_chars = ["0", "1", "2", "3", "4", "5", "6", "8", "9"] # 将图像调整为指定大小 def resize_image(image_path, output_width, output_height): image = Image.open(image_path) image = image.resize((output_width, output_height)) return image # 将图像转换为灰度图像 def convert_to_gray(image): return image.convert('L') # 将图像转换为彩色 ASCII 字符画 def image_to_colored_ascii(image_path, output_width, output_height): resized_image = resize_image(image_path, output_width, output_height) ascii_image = [] ascii_image_chars = [] ascii_image_colors=[] for y in range(output_height): row = "" for x in range(output_width): color = resized_image.getpixel((x, y)) gray_value = sum(color) // 3 char_index = int(gray_value / 255 * (len(colored_ascii_chars) - 1)) if char_index >= len(colored_ascii_chars): char_index = len(colored_ascii_chars) - 1 row += f"\033[38;2;{color[0]};{color[1]};{color[2]}m{colored_ascii_chars[char_index]}" ascii_image_chars.append(colored_ascii_chars[char_index]) ascii_image_colors.append((color[0], color[1], color[2])) ascii_image.append(row) return "\n".join(ascii_image), ascii_image_chars, ascii_image_colors # 将彩色 ASCII 艺术图像存储为图片 def save_colored_ascii_image_as_picture(ascii_image_chars, ascii_image_colors, font_path, font_size, output_path): image = Image.new('RGB', ((output_width * font_size), (output_height * font_size)), color='black') draw = ImageDraw.Draw(image) font = ImageFont.truetype(font_path, font_size) for i in range(output_height): for j in range(output_width): draw.text((j * font_size, i * font_size), ascii_image_chars[i*output_width+j], font=font, fill=ascii_image_colors[i*output_width+j]) image.save(output_path) if __name__ == "__main__": image_path = "path/to/your/image.jpg" # 将图像转换为彩色 ASCII 字符画 colored_ascii_image, colored_ascii_image_chars, colored_ascii_image_colors = image_to_colored_ascii(image_path, output_width, output_height) # 存储彩色 ASCII 字符画到图片文件 save_colored_ascii_image_as_picture(colored_ascii_image_chars, colored_ascii_image_colors, colored_ascii_image_font, colored_ascii_image_font_size, "colored_ascii_image.png") # 在终端窗口打印彩色 ASCII 字符画 print(colored_ascii_image)
5. 总结
本文向您介绍了 ASCII 字符画的迷人世界,并展示了 Python 如何成为制作您自己的字符画杰作的强大工具。 您可以尝试不同的图像、不同的设置来创建独特且令人着迷的 ASCII 艺术作品。您还可以在本文的基础上继续探索,创造更多有趣的功能。
6. 附录
以下是一些与 ASCII 字符画相关的资源,您可以在其中找到创建 ASCII 艺术的示例和灵感:
- ASCII Art Archive:大量的 ASCII 艺术收藏。
- ASCII World:一个以各种 ASCII 艺术示例和资源为特色的网站。
- Python + Diagrams: 用代码输出高档系统架构图
- Python + Pandas : 轻松搞定CSV文件
- Python + PyAutoGUI: 轻松实现用户界面自动化
- Python + Cryptography : 给你的数据加把锁
- Python 中的浅拷贝和深拷贝
- Python 字典 (Dictionary) 入门
- 从串联到 F-字符串:释放 Python 字符串格式化的力量
- 神奇的 Python 元类 (metaclass) 及其应用
- Python 之禅
- 使用 Python 生成 Lorem lpsum 拉丁文本