字符画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
from PIL import Image
import argparse
import os

def image_to_ascii(image_path, output_width=1500, aspect_ratio=0.5,
chars="@#S%?*+;:,. ", output_file=None, max_output_width=None):
"""
将图像转换为ASCII艺术

参数:
- image_path: 输入图片路径
- output_width: 输出ASCII艺术的宽度(字符数)
- aspect_ratio: 高宽比调整因子,通常0.4-0.6
- chars: 用于表示灰度的字符序列(从暗到亮)
- output_file: 输出文件路径,如为None则打印到控制台
- max_output_width: 最大输出宽度,用于控制台显示限制
"""

try:
# 打开并验证图像
img = Image.open(image_path)
except Exception as e:
print(f"无法打开图像: {e}")
return None

# 计算调整后的高度
width_percent = output_width / float(img.size[0])
output_height = int(float(img.size[1]) * float(width_percent * aspect_ratio))

# 调整图像大小
img_resized = img.resize((output_width, output_height), Image.NEAREST)

# 转换为灰度图
img_gray = img_resized.convert("L")

# 获取像素数据
pixels = img_gray.load()

# 字符映射表
ascii_chars = list(chars)
chars_count = len(ascii_chars)

# 生成ASCII艺术
result_lines = []
for i in range(output_height):
line = ""
for j in range(output_width):
gray = pixels[j, i]
# 安全地计算字符索引
index = min(int(gray / 255 * chars_count), chars_count - 1)
line += ascii_chars[index]
result_lines.append(line)

# 处理输出宽度限制
if max_output_width and max_output_width < output_width:
trimmed_lines = []
for line in result_lines:
# 每max_output_width个字符换行
for i in range(0, len(line), max_output_width):
trimmed_lines.append(line[i:i+max_output_width])
result_lines = trimmed_lines

result = "\n".join(result_lines)

# 输出结果
if output_file:
try:
with open(output_file, 'w', encoding='utf-8') as f:
f.write(result)
print(f"ASCII艺术已保存到: {output_file}")
except Exception as e:
print(f"保存文件时出错: {e}")
return None
else:
# 直接打印到控制台
print(result)

return result

def main():
"""主函数,处理命令行参数"""
parser = argparse.ArgumentParser(description='将图像转换为ASCII艺术')
parser.add_argument('image_path', help='输入图像路径')
parser.add_argument('-w', '--width', type=int, default=15,
help='输出宽度(字符数),默认1500')
parser.add_argument('-a', '--aspect', type=float, default=0.5,
help='高宽比调整因子,默认0.5')
parser.add_argument('-c', '--chars', default="@#S%?*+;:,. ",
help='灰度字符序列(从暗到亮)')
parser.add_argument('-o', '--output',
help='输出文件路径(如不指定则打印到控制台)')
parser.add_argument('-m', '--max-width', type=int,
help='最大输出宽度(用于控制台显示限制)')

args = parser.parse_args()

# 检查文件是否存在
if not os.path.exists(args.image_path):
print(f"错误: 文件 '{args.image_path}' 不存在")
return

# 生成ASCII艺术
image_to_ascii(
image_path=args.image_path,
output_width=args.width,
aspect_ratio=args.aspect,
chars=args.chars,
output_file=args.output,
max_output_width=args.max_width
)

# 示例使用函数
def example_usage():
"""示例用法"""
# 基本用法
result = image_to_ascii("exapmple.jpg")

# 保存到文件
image_to_ascii("exapmple.jpg", output_file="ascii_art.txt")

# 自定义参数
image_to_ascii(
image_path="exapmple.jpg",
output_width=800,
aspect_ratio=0.4,
chars="@%#*+=-:. ",
output_file="custom_ascii.txt",
max_output_width=100 # 适合控制台显示
)

# if __name__ == "__main__":
# # 如果直接运行脚本,使用命令行参数
# main()

# # 取消注释以下行来测试示例用法
# # example_usage()

使用示例

1
2
3
4
5
6
7
8
result = image_to_ascii(
image_path="avatar_椎叶.jpg",
output_width=160,
aspect_ratio=0.4,
chars="@%#*+=-:. ",
output_file="custom_ascii.txt",
max_output_width=200 # 适合控制台显示
)

效果展示