在数字世界的无尽探索中,我们时常被那些看似平凡的技术所启发,它们如同星辰般点缀着我们的创意天空。今天,我突发奇想,想要用Python开发一个将图片转化为字符画的小工具。这不仅是一次技术的实践,更是一场艺术与科技的奇妙融合。
让我们一起踏上这段旅程,用Python的代码,绘制出属于我们自己的字符画世界。在这个世界里,每一行代码都是一笔,每一次运行都是一次创作,每一张字符画都是一次心灵的触动。
1.功能概述
使用PyQt5框架开发的ASCII字符画生成器。用户可以通过该程序加载图片,将其转换为ASCII字符表示,并保存生成的ASCII字符画。
效果图
2.设计思路
- 用户界面设计:使用PyQt5创建一个图形用户界面,包括图片显示区域、文本编辑区域、ASCII字符设置区域和操作按钮。
- 图片处理:加载图片后,调整图片大小并转换为灰度图像,以便于生成ASCII艺术。
- ASCII艺术生成:根据灰度图像的像素值,将每个像素映射到预设的ASCII字符集中的一个字符。
- 保存ASCII艺术:将生成的ASCII字符串保存为文本文件。
3.主要函数解析
__init__
:初始化主窗口,设置UI元素。initUI
:设置窗口标题和布局,添加必要的控件和按钮。load_image
:打开文件对话框,加载用户选择的图片。resize_image
:调整图片大小,保持宽高比。grayify
:将图片转换为灰度图像。generate_ascii
:生成ASCII艺术,将灰度图像转换为ASCII字符串,并在文本编辑器中显示。save_ascii
:保存生成的ASCII艺术到文本文件。pixels_to_ascii
:将灰度图像的像素转换为ASCII字符。
4.详细设计
-
界面设计:
- 左侧区域用于显示原始图片。
- 右侧上半部分用于显示生成的ASCII字符。
- 右侧下半部分包括:
- 自定义ASCII字符输入框。
- 加载图片、生成ASCII、保存ASCII的按钮。
-
功能实现:
- 加载图片:用户点击按钮后,通过文件对话框选择图片文件,加载并显示在左侧区域。
- 生成ASCII:点击按钮后,程序将图片转换为灰度并调整大小,然后根据灰度值映射到ASCII字符,结果显示在右侧文本编辑区域。
- 保存ASCII:用户点击按钮后,选择保存位置和文件名,将文本编辑区域的内容保存为文本文件。
-
错误处理:
- 在加载图片和生成ASCII时,程序会检查是否有图片路径,如果没有则不执行后续操作。
- 在生成ASCII时,如果自定义的ASCII字符集为空,程序会提示用户输入。
-
用户体验:
- 提供清晰的界面布局和直观的操作流程。
- 在执行可能耗时的操作(如生成ASCII)时,提供进度反馈或加载指示。
5.完整代码
# -*- coding: gbk -*-
"""
Created on 2024/6/18 11:22@Deprecated:
@Author: DanMo
@File : ASCIIArtGenerator.py
"""
import sys
from PyQt5.QtWidgets import QApplication, QMainWindow, QLabel, QPushButton, QTextEdit, QFileDialog, QVBoxLayout, \QHBoxLayout, QWidget, QLineEdit
from PyQt5.QtGui import QPixmap
from PIL import Imageclass MainWindow(QMainWindow):def __init__(self):super().__init__()self.ASCII_CHARS = '@%#*+=-:. 'self.initUI()def initUI(self):self.setWindowTitle('ASCII Art Generator')central_widget = QWidget(self)self.setCentralWidget(central_widget)# 创建布局main_layout = QHBoxLayout(central_widget)# 左侧显示图片的部分self.label = QLabel(self)main_layout.addWidget(self.label)# 右侧操作部分right_layout = QVBoxLayout()self.textEdit = QTextEdit(self)right_layout.addWidget(self.textEdit)# 添加设置ASCII字符的部分ascii_label = QLabel('Custom ASCII Chars:', self)right_layout.addWidget(ascii_label)self.ascii_edit = QLineEdit(self)self.ascii_edit.setText(self.ASCII_CHARS)right_layout.addWidget(self.ascii_edit)button_layout = QHBoxLayout()self.btnLoad = QPushButton('Load Image', self)self.btnLoad.clicked.connect(self.load_image)button_layout.addWidget(self.btnLoad)self.btnGenerate = QPushButton('Generate ASCII', self)self.btnGenerate.clicked.connect(self.generate_ascii)button_layout.addWidget(self.btnGenerate)self.btnSave = QPushButton('Save ASCII', self)self.btnSave.clicked.connect(self.save_ascii)button_layout.addWidget(self.btnSave)right_layout.addLayout(button_layout)main_layout.addLayout(right_layout)self.resize(800, 600) # 初始窗口大小def load_image(self):options = QFileDialog.Options()fileName, _ = QFileDialog.getOpenFileName(self, "Open Image File", "", "Image Files (*.png *.jpg *.jpeg *.bmp)",options=options)if fileName:pixmap = QPixmap(fileName)self.label.setPixmap(pixmap)self.image_path = fileName# 调整图片尺寸并灰度化def resize_image(self, image, new_width=100):width, height = image.sizeratio = height / width / 2new_height = int(new_width * ratio)resized_image = image.resize((new_width, new_height))return resized_imagedef grayify(self, image):return image.convert('L')def generate_ascii(self):if not hasattr(self, 'image_path'):returntry:image = Image.open(self.image_path)except Exception as e:print(e)returnimage = self.resize_image(image, new_width=100)image = self.grayify(image)self.ASCII_CHARS = self.ascii_edit.text()if not self.ASCII_CHARS:print('Please input ASCII_CHARS!')returnascii_str = self.pixels_to_ascii(image)img_width = image.widthascii_img = ''for i in range(0, len(ascii_str), img_width):ascii_img += ascii_str[i:i + img_width] + '\n'self.textEdit.setPlainText(ascii_img)def save_ascii(self):if not hasattr(self, 'image_path'):returntry:image = Image.open(self.image_path)except Exception as e:print(e)returnimage = self.resize_image(image, new_width=100)image = self.grayify(image)self.ASCII_CHARS = self.ascii_edit.text()if not self.ASCII_CHARS:print('Please input ASCII_CHARS!')returnascii_str = self.pixels_to_ascii(image)img_width = image.widthascii_img = ''for i in range(0, len(ascii_str), img_width):ascii_img += ascii_str[i:i + img_width] + '\n'options = QFileDialog.Options()fileName, _ = QFileDialog.getSaveFileName(self, "Save ASCII File", "", "Text Files (*.txt)", options=options)if fileName:with open(fileName, 'w') as f:f.write(ascii_img)def pixels_to_ascii(self, image):pixels = image.getdata()ascii_str = ''for pixel in pixels:# 确保灰度值在合理范围内pixel_char = self.ASCII_CHARS[min(len(self.ASCII_CHARS) - 1, pixel // 25)]ascii_str += pixel_charreturn ascii_strdef main():app = QApplication(sys.argv)mainWindow = MainWindow()mainWindow.show()sys.exit(app.exec_())if __name__ == '__main__':main()
6.效果展示
自定义设置字符
另存为文本