├── .gitignore
├── LICENSE
├── README.md
├── bgs
├── #000000-1000x1000.png
├── #000000-200x200.png
├── #000000-500x500.png
├── #ff55ff-500x500.png
├── grid.jpeg
├── letter.png
├── my.jpg
├── 村庄信笺纸.jpg
└── 树信笺纸.jpg
├── fonts
├── hand.ttf
├── 上首鸿志手写体.ttf
├── 品如手写体.ttf
├── 张维镜手写楷书.ttf
├── 手写大象体.ttf
├── 未知手写体_1.ttf
├── 李国夫董事长手写体.ttf
├── 薛文轩钢笔楷体.ttf
└── 青叶手写体.ttf
├── img_1.png
├── img_1_.png
├── img_4.png
├── img_5.png
├── logo.png
├── main.py
├── main.spec
└── ui.png
/.gitignore:
--------------------------------------------------------------------------------
1 | build
2 | dist
3 | test
4 | bgs
5 | .idea
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2023 CodeFly
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # **HandwritingGenerator**
2 |
3 | > HandwritingGenerator 是一个使用 PyQt6 制作的手写文本图片生成器。
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 | 1. **配置效果参数:** 打开 HandwritingGenerator,使用左侧的配置面板调整手写文本图片的效果参数。
32 |
33 | 2. **实时预览:** 在左侧配置的同时,右侧将实时显示生成的手写文本图片,以便用户可视化调整效果。
34 |
35 | 3. **输出图片:** 调整好效果参数后,点击导出按钮即可将生成的手写文本图片保存到本地。
36 |
37 | ## 如何安装
38 |
39 | ### 下载安装包:
40 |
41 | 就是项目中的rar文件,解压即可使用。
42 |
43 | 下载链接:[https://github.com/w-x-x-w/HandwritingGenerator/releases](https://github.com/w-x-x-w/HandwritingGenerator/releases)
44 |
45 | ### 下载源代码:
46 |
47 | 使用以下步骤在本地运行 HandwritingGenerator:
48 |
49 | ```bash
50 | # 克隆仓库
51 | git clone https://github.com/w-x-x-w/HandwritingGenerator.git
52 |
53 | # 进入项目目录
54 | cd HandwritingGenerator
55 |
56 | # 安装依赖
57 | pip install PyQt6
58 |
59 | # 运行应用
60 | python main.py
61 | ```
62 |
63 | ## 后续待增加功能
64 |
65 | - 创建渐变色或纹理背景,使用户能够更灵活地定制图片外观。
66 |
67 | - 用户更大自由度选择字体而不是只能选择列表项
68 |
--------------------------------------------------------------------------------
/bgs/#000000-1000x1000.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/bgs/#000000-1000x1000.png
--------------------------------------------------------------------------------
/bgs/#000000-200x200.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/bgs/#000000-200x200.png
--------------------------------------------------------------------------------
/bgs/#000000-500x500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/bgs/#000000-500x500.png
--------------------------------------------------------------------------------
/bgs/#ff55ff-500x500.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/bgs/#ff55ff-500x500.png
--------------------------------------------------------------------------------
/bgs/grid.jpeg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/bgs/grid.jpeg
--------------------------------------------------------------------------------
/bgs/letter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/bgs/letter.png
--------------------------------------------------------------------------------
/bgs/my.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/bgs/my.jpg
--------------------------------------------------------------------------------
/bgs/村庄信笺纸.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/bgs/村庄信笺纸.jpg
--------------------------------------------------------------------------------
/bgs/树信笺纸.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/bgs/树信笺纸.jpg
--------------------------------------------------------------------------------
/fonts/hand.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/fonts/hand.ttf
--------------------------------------------------------------------------------
/fonts/上首鸿志手写体.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/fonts/上首鸿志手写体.ttf
--------------------------------------------------------------------------------
/fonts/品如手写体.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/fonts/品如手写体.ttf
--------------------------------------------------------------------------------
/fonts/张维镜手写楷书.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/fonts/张维镜手写楷书.ttf
--------------------------------------------------------------------------------
/fonts/手写大象体.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/fonts/手写大象体.ttf
--------------------------------------------------------------------------------
/fonts/未知手写体_1.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/fonts/未知手写体_1.ttf
--------------------------------------------------------------------------------
/fonts/李国夫董事长手写体.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/fonts/李国夫董事长手写体.ttf
--------------------------------------------------------------------------------
/fonts/薛文轩钢笔楷体.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/fonts/薛文轩钢笔楷体.ttf
--------------------------------------------------------------------------------
/fonts/青叶手写体.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/fonts/青叶手写体.ttf
--------------------------------------------------------------------------------
/img_1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/img_1.png
--------------------------------------------------------------------------------
/img_1_.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/img_1_.png
--------------------------------------------------------------------------------
/img_4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/img_4.png
--------------------------------------------------------------------------------
/img_5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/img_5.png
--------------------------------------------------------------------------------
/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cpython666/HandwritingGenerator/8b1c7c6601f2f742f2db02319936b87d4c0976e8/logo.png
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | import sys
2 | from PyQt6.QtWidgets import (QApplication, QGraphicsView, QGraphicsScene,QWidget,QHBoxLayout,QVBoxLayout,QLabel,
3 | QGraphicsPixmapItem, QGraphicsRectItem, QMainWindow,QMessageBox,
4 | QGraphicsTextItem, QPushButton,QInputDialog,QComboBox,
5 | QSlider,QVBoxLayout,QFileDialog,QColorDialog,QTextEdit,QDialog,QLineEdit)
6 | from PyQt6.QtCore import Qt, QRectF
7 | from PyQt6.QtGui import (QGuiApplication,QPixmap,
8 | QPainter, QImage, QFont,
9 | QKeySequence,QShortcut,QFont,
10 | QFontDatabase,QColor,QIcon)
11 |
12 | class ImageCreator(QDialog):
13 | def __init__(self):
14 | super().__init__()
15 |
16 | self.initUI()
17 | self.initLayout()
18 | self.center()
19 |
20 | def initUI(self):
21 | self.setWindowTitle('输出一个纯色背景图片')
22 | self.setGeometry(100,100,300,300)
23 | self.setWindowIcon(QIcon('logo.png'))
24 |
25 | def center(self):
26 | qr=self.frameGeometry()
27 | cp=QGuiApplication.primaryScreen().availableGeometry().center()
28 | qr.moveCenter(cp)
29 | self.move(qr.topLeft())
30 |
31 | def initLayout(self):
32 |
33 | self.color_label = QLabel('当前颜色:(255,255,255,255)', self)
34 | self.color_button = QPushButton('选择颜色', self)
35 | self.color=QColor('black')
36 | self.color_button.clicked.connect(self.showColorDialog)
37 | color_layout=QHBoxLayout()
38 | color_layout.addStretch(1)
39 | color_layout.addWidget(self.color_label)
40 | color_layout.addWidget(self.color_button)
41 | color_layout.addStretch(1)
42 |
43 | self.bg_a=QLabel('图片不透明度:255')
44 | self.bg_a_slider=QSlider(Qt.Orientation.Horizontal)
45 | self.bg_a_slider.setRange(0, 255)
46 | self.bg_a_slider.setSingleStep(1)
47 | self.bg_a_slider.setValue(255)
48 | bg_a_layout=QHBoxLayout()
49 | bg_a_layout.addStretch(1)
50 | bg_a_layout.addWidget(self.bg_a)
51 | bg_a_layout.addWidget(self.bg_a_slider)
52 | bg_a_layout.addStretch(1)
53 | self.bg_a_slider.valueChanged.connect(self.update_bg_a_label)
54 |
55 | self.color_pre=QLabel('颜色预览:')
56 | self.color_rect=QLabel()
57 | self.color_rect.setFixedSize(50,50)
58 | self.color_rect.setStyleSheet(f'background-color: {self.color.name()}')
59 | color_pre_layout=QHBoxLayout()
60 | color_pre_layout.addStretch(1)
61 | color_pre_layout.addWidget(self.color_pre)
62 | color_pre_layout.addWidget(self.color_rect)
63 | color_pre_layout.addStretch(1)
64 |
65 | self.width_label = QLabel('图片长度:', self)
66 | self.width_input_line = QLineEdit(self)
67 | self.width_input_line.setPlaceholderText('在这里输入整数')
68 | self.width_unit_label = QLabel('像素', self)
69 | width_input_layout = QHBoxLayout()
70 | width_input_layout.addStretch(1)
71 | width_input_layout.addWidget(self.width_label)
72 | width_input_layout.addWidget(self.width_input_line)
73 | width_input_layout.addWidget(self.width_unit_label)
74 | width_input_layout.addStretch(1)
75 |
76 | self.height_label = QLabel('图片宽度:', self)
77 | self.height_input_line = QLineEdit(self)
78 | self.height_input_line.setPlaceholderText('在这里输入整数')
79 | self.height_unit_label = QLabel('像素', self)
80 | height_input_layout = QHBoxLayout()
81 | height_input_layout.addStretch(1)
82 | height_input_layout.addWidget(self.height_label)
83 | height_input_layout.addWidget(self.height_input_line)
84 | height_input_layout.addWidget(self.height_unit_label)
85 | height_input_layout.addStretch(1)
86 |
87 | self.create_button = QPushButton('创建图片', self)
88 | self.create_button.clicked.connect(self.createImage)
89 |
90 | layout = QVBoxLayout()
91 | layout.addLayout(color_layout)
92 | layout.addLayout(bg_a_layout)
93 | layout.addLayout(color_pre_layout)
94 |
95 | layout.addLayout(width_input_layout)
96 | layout.addLayout(height_input_layout)
97 |
98 | layout.addWidget(self.create_button)
99 |
100 | self.setLayout(layout)
101 |
102 | def update_bg_a_label(self):
103 | self.bg_a.setText(f'图片不透明度:{self.bg_a_slider.value()}')
104 | self.color.setAlpha(self.bg_a_slider.value())
105 | self.color_rect.setStyleSheet(f'background-color: {self.color.name()}')
106 |
107 | def showColorDialog(self):
108 | color = QColorDialog.getColor()
109 | if color.isValid():
110 | self.color_label.setText(f'当前颜色:{self.color.getRgb()}')
111 | self.color_button.setStyleSheet(f'background-color: {color.name()}')
112 | self.color_rect.setStyleSheet(f'background-color: {color.name()}')
113 | self.color = color
114 |
115 | def createImage(self):
116 | width = int(self.width_input_line.text())
117 | height = int(self.height_input_line.text())
118 | if width <= 0 or height <= 0:
119 | return
120 | if not hasattr(self, 'color'):
121 | return
122 | image = QPixmap(width, height)
123 | image.fill(self.color)
124 | image.save(f'./bgs/{self.color.name()}-{width}x{height}.png')
125 | QMessageBox.information(self, '提示', '图片已保存在 bgs 目录下!', QMessageBox.StandardButton.Ok)
126 |
127 | # print(f'图片已创建: {self.color.name()}-{width}x{height}.png')
128 |
129 | class HandFontWindow(QMainWindow):
130 | def __init__(self):
131 | super().__init__()
132 |
133 | self.initUI()
134 |
135 | def initUI(self):
136 | self.setGeometry(100, 100, 1200, 600)
137 | self.setWindowTitle('手写字体图片生成器')
138 | self.setWindowIcon(QIcon('logo.png'))
139 |
140 | self.initView()
141 | self.config_widget=self.initConfigForm()
142 |
143 | # 将配置窗口添加到主窗口的布局中
144 | main_layout = QHBoxLayout()
145 | main_layout.addWidget(self.config_widget)
146 | main_layout.addWidget(self.view)
147 | main_widget = QWidget(self)
148 | main_widget.setLayout(main_layout)
149 | self.setCentralWidget(main_widget)
150 |
151 | # 添加导出图片的快捷键 Ctrl + S
152 | export_shortcut = QShortcut(QKeySequence(QKeySequence.StandardKey.Save), self)
153 | export_shortcut.activated.connect(self.view.exportSceneToImage)
154 |
155 | self.updateView()
156 |
157 | self.show()
158 |
159 | def initView(self):
160 | self.my_scene = QGraphicsScene(self)
161 | self.view = GraphicsView(self.my_scene, self)
162 | self.setCentralWidget(self.view)
163 |
164 | def initConfigForm(self):
165 | # 创建配置参数窗口
166 | config_widget = QWidget(self)
167 | config_layout = QVBoxLayout(config_widget)
168 | # 添加文字区域配置
169 | text_config_label = QLabel('效果配置:')
170 | config_layout.addWidget(text_config_label)
171 | # 选择背景图片
172 | self.label_bg=QLabel('letter.png')
173 | self.button_bg=QPushButton('选择背景图')
174 | self.button_bg.clicked.connect(self.show_file_dialog)
175 | self.bg_path='./bgs/letter.png'
176 | config_layout.addWidget(self.label_bg)
177 | config_layout.addWidget(self.button_bg)
178 |
179 | creat_bg_layout=QHBoxLayout()
180 | creat_bg_label=QLabel('没有喜欢的背景图片?')
181 | creat_bg_button=QPushButton('创建一个纯色背景')
182 | creat_bg_button.clicked.connect(self.create_bg_widget)
183 | creat_bg_layout.addWidget(creat_bg_label)
184 | creat_bg_layout.addWidget(creat_bg_button)
185 | config_layout.addLayout(creat_bg_layout)
186 |
187 | # 选择字体
188 | self.label_font = QLabel("选择字体:")
189 | self.combo_box = QComboBox(self)
190 | self.combo_box.addItem('hand.ttf')
191 | self.combo_box.addItem('李国夫董事长手写体.ttf')
192 | self.combo_box.addItem('品如手写体.ttf')
193 | self.combo_box.addItem('青叶手写体.ttf')
194 | self.combo_box.addItem('上首鸿志手写体.ttf')
195 | self.combo_box.addItem('手写大象体.ttf')
196 | self.combo_box.addItem('未知手写体_1.ttf')
197 | self.combo_box.addItem('薛文轩钢笔楷体.ttf')
198 | self.combo_box.addItem('张维镜手写楷书.ttf')
199 | config_layout.addWidget(self.label_font)
200 | config_layout.addWidget(self.combo_box)
201 | self.combo_box.currentIndexChanged.connect(self.updateView)
202 | # 选择字体颜色
203 | self.label_font_color = QLabel("当前字体颜色:black")
204 | self.button_font_color = QPushButton('选择字体颜色')
205 | self.font_color='black'
206 | config_layout.addWidget(self.label_font_color)
207 | config_layout.addWidget(self.button_font_color)
208 | self.button_font_color.clicked.connect(self.show_color_dialog)
209 |
210 | self.label_text=QLabel('要显示的文字:')
211 | self.text_edit = QTextEdit(self)
212 | self.text_edit.setPlaceholderText('要显示的文字')
213 | self.text_edit.setText('''花费了一天,跟gpt3.5对话进百句,修修改改,最终做成这样的效果。
214 | 我的字迹一直很差,我也很讨厌写字,我花费了很多时间在练字上但我的字迹不好反坏。所以当我看到生成手写字图片的可能时,我便开始了迫不及待地尝试。
215 | 做到一半的时候我突然想到网上有没有已经做出来的。确实有,有点小失望,但又细看了一下发现它的应该操作比我的复杂点,所以我又继续做完就是现在的效果。''')
216 | # text_edit.toPlainText()
217 | self.text_edit.textChanged.connect(self.updateView)
218 | config_layout.addWidget(self.label_text)
219 | config_layout.addWidget(self.text_edit)
220 |
221 | # 坐标信息
222 | # 创建滑块调节数值并为其设置标签显示当前数值
223 | self.slider_x = QSlider(Qt.Orientation.Horizontal)
224 | self.slider_x.setRange(0, 500)
225 | self.slider_x.setSingleStep(1)
226 | self.slider_x.valueChanged.connect(self.updateView)
227 | self.slider_x.setValue(0)
228 | self.label_x = QLabel("文字坐标x:0")
229 | config_layout.addWidget(self.label_x)
230 | config_layout.addWidget(self.slider_x)
231 |
232 | self.slider_y = QSlider(Qt.Orientation.Horizontal)
233 | self.slider_y.setRange(0, 800)
234 | self.slider_y.setSingleStep(1)
235 | self.slider_y.valueChanged.connect(self.updateView)
236 | self.slider_x.setValue(0)
237 | self.label_y = QLabel("文字坐标y:0")
238 | config_layout.addWidget(self.label_y)
239 | config_layout.addWidget(self.slider_y)
240 |
241 | # 文字区域宽度
242 | self.slider_width = QSlider(Qt.Orientation.Horizontal)
243 | self.slider_width.setRange(10, 2000)
244 | self.slider_width.setSingleStep(1)
245 | self.slider_width.setValue(100)
246 | self.slider_width.valueChanged.connect(self.updateView)
247 | self.label_width = QLabel("文字显示宽度:100")
248 | config_layout.addWidget(self.label_width)
249 | config_layout.addWidget(self.slider_width)
250 |
251 | self.slider_height = QSlider(Qt.Orientation.Horizontal)
252 | self.slider_height.setRange(1, 2000)
253 | self.slider_height.setSingleStep(1)
254 | self.slider_height.setValue(200)
255 | self.slider_height.valueChanged.connect(self.updateView)
256 | self.label_height = QLabel("文字显示高度:200")
257 | config_layout.addWidget(self.label_height)
258 | config_layout.addWidget(self.slider_height)
259 |
260 | # 字体大小
261 | self.slider_font_size = QSlider(Qt.Orientation.Horizontal)
262 | self.slider_font_size.setRange(1, 100)
263 | self.slider_font_size.setSingleStep(1)
264 | self.slider_font_size.setValue(16)
265 | self.slider_font_size.valueChanged.connect(self.updateView)
266 | self.label_font_size = QLabel("文字大小:16")
267 | config_layout.addWidget(self.label_font_size)
268 | config_layout.addWidget(self.slider_font_size)
269 | # 字体粗细
270 | self.slider_font_weight = QSlider(Qt.Orientation.Horizontal)
271 | self.slider_font_weight.setRange(100, 1000)
272 | self.slider_font_weight.setSingleStep(100)
273 | self.slider_font_weight.setValue(500)
274 | self.slider_font_weight.valueChanged.connect(self.updateView)
275 | self.label_font_weight = QLabel("文字粗细:500")
276 | config_layout.addWidget(self.label_font_weight)
277 | config_layout.addWidget(self.slider_font_weight)
278 |
279 | # 字体间距
280 | self.slider_font_spacing = QSlider(Qt.Orientation.Horizontal)
281 | self.slider_font_spacing.setRange(-20,20)
282 | self.slider_font_spacing.setSingleStep(1)
283 | self.slider_font_spacing.setValue(2)
284 | self.slider_font_spacing.valueChanged.connect(self.updateView)
285 | self.label_font_spacing = QLabel("字体间距:0.1")
286 | config_layout.addWidget(self.label_font_spacing)
287 | config_layout.addWidget(self.slider_font_spacing)
288 |
289 | # 行间距
290 | self.slider_line_spacing = QSlider(Qt.Orientation.Horizontal)
291 | self.slider_line_spacing.setRange(20,80)
292 | self.slider_line_spacing.setSingleStep(1)
293 | self.slider_line_spacing.setValue(40)
294 | self.slider_line_spacing.valueChanged.connect(self.updateView)
295 | self.label_line_spacing = QLabel("行间距:1")
296 | config_layout.addWidget(self.label_line_spacing)
297 | config_layout.addWidget(self.slider_line_spacing)
298 |
299 | # 添加导出按钮
300 | export_btn = QPushButton('导出图片:', self)
301 | export_btn.clicked.connect(self.view.exportSceneToImage)
302 | config_layout.addWidget(export_btn)
303 | config_widget.setLayout(config_layout)
304 |
305 | return config_widget
306 |
307 | def create_bg_widget(self):
308 | self.dialog=ImageCreator()
309 | self.dialog.show()
310 |
311 | def show_file_dialog(self):
312 | # 创建文件选择框
313 | file_dialog = QFileDialog(self)
314 | file_dialog.setWindowTitle('Open File')
315 | file_dialog.setFileMode(QFileDialog.FileMode.ExistingFile)
316 |
317 | # 显示文件选择框并等待用户选择
318 | if file_dialog.exec() == QFileDialog.DialogCode.Accepted:
319 | # 获取用户选择的文件路径
320 | selected_file = file_dialog.selectedFiles()[0]
321 | self.label_bg.setText(selected_file)
322 | self.bg_path=selected_file
323 | self.updateView()
324 | def show_color_dialog(self):
325 | # 创建颜色选择框
326 | color_dialog = QColorDialog(self)
327 | color_dialog.setWindowTitle('Choose Color')
328 |
329 | # 设置初始颜色(可选)
330 | color_dialog.setCurrentColor(QColor(255, 0, 0))
331 |
332 | # 显示颜色选择框并等待用户选择
333 | if color_dialog.exec() == QColorDialog.DialogCode.Accepted:
334 | # 获取用户选择的颜色
335 | self.font_color = color_dialog.currentColor().name()
336 | self.label_font_color.setText('当前字体颜色:'+self.font_color)
337 | self.updateView()
338 |
339 | def updateView(self):
340 | current_text = self.combo_box.currentText()
341 | font_path='./fonts/'+current_text
342 | self.label_x.setText(f"文字坐标x:{self.slider_x.value()}")
343 | self.label_y.setText(f"文字坐标y:{self.slider_y.value()}")
344 | self.label_font_size.setText(f"文字大小:{self.slider_font_size.value()}")
345 | self.label_font_weight.setText(f"文字粗细:{self.slider_font_weight.value()}")
346 | self.label_font_color.setText(f"当前字体颜色:{self.font_color}")
347 | self.label_font_spacing.setText(f"文字间隔:{round(self.slider_font_spacing.value()/20,2)}")
348 | self.label_line_spacing.setText(f"行间隔x:{round(self.slider_line_spacing.value()/20,2)}")
349 | self.label_width.setText(f"文字显示宽度:{self.slider_width.value()}")
350 | self.label_height.setText(f"文字显示高度:{self.slider_height.value()}")
351 |
352 | text_tmp=self.text_edit.toPlainText().replace(' ',' ').replace('\n','
')
353 |
354 | self.view.addTextItem(text=text_tmp,
355 | bg_path=self.bg_path,
356 | font_path=font_path,
357 | font_color=self.font_color,
358 | font_weight=self.slider_font_weight.value(),
359 | x=self.slider_x.value(),y=self.slider_y.value(),
360 | font_size=self.slider_font_size.value(),
361 | font_spacing=round(self.slider_font_spacing.value()/20,2),
362 | line_spacing=round(self.slider_line_spacing.value()/40,2),
363 | rect_width=self.slider_width.value(),
364 | rect_height=self.slider_height.value()
365 | )
366 |
367 | class GraphicsView(QGraphicsView):
368 | def __init__(self, scene, parent):
369 | super().__init__(scene, parent)
370 |
371 | self.setStyleSheet('GraphicsView{background-color:#FDF6E3;}')
372 | self.setRenderHint(QPainter.RenderHint.Antialiasing, True)
373 | self.setDragMode(QGraphicsView.DragMode.ScrollHandDrag) # 启用拖拽模式
374 |
375 | self.drawing_rect = None
376 | self.origin = None
377 | self.is_drawing = False
378 | self.coordinate_text_items = {} # 存储坐标信息的字典,以矩形为键
379 |
380 | def wheelEvent(self, event):
381 | modifiers = event.modifiers()
382 | if modifiers == Qt.KeyboardModifier.ControlModifier:
383 | # 只有在按下 Ctrl 键时才缩放
384 | factor = 1.2 # 缩放因子
385 | if event.angleDelta().y() < 0:
386 | factor = 1.0 / factor # 对于负的滚轮事件进行缩小
387 | self.scale(factor, factor)
388 |
389 | def mouseDoubleClickEvent(self, event):
390 | super().mouseDoubleClickEvent(event)
391 | if event.button() == Qt.MouseButton.LeftButton:
392 | # 获取鼠标双击的位置
393 | double_click_position = event.pos()
394 | # 获取双击位置相对于原图的像素位置
395 | double_click_scene_position = self.mapToScene(double_click_position)
396 | # 获取点击位置相对于原图的像素位置
397 | item = self.scene().itemAt(double_click_scene_position, self.transform())
398 | if isinstance(item, QGraphicsRectItem):
399 | # 删除被点击的矩形的坐标信息
400 | rect_key = id(item)
401 | if rect_key in self.coordinate_text_items:
402 | self.removeCoordinateTextItems(self.coordinate_text_items[rect_key])
403 | # 删除被点击的矩形
404 | self.scene().removeItem(item)
405 |
406 | def mouseMoveEvent(self, event):
407 | super().mouseMoveEvent(event)
408 |
409 | if event.buttons() & Qt.MouseButton.RightButton:
410 | if self.is_drawing and self.origin is not None:
411 | # 获取鼠标当前位置
412 | current_position = event.pos()
413 |
414 | # 获取当前位置相对于原图的像素位置
415 | current_scene_position = self.mapToScene(current_position)
416 |
417 | # 更新矩形的大小
418 | self.drawing_rect.setRect(QRectF(self.origin, current_scene_position))
419 |
420 | # 实时显示图像
421 | scene_rect = self.sceneRect()
422 | self.setSceneRect(scene_rect)
423 |
424 | def mouseReleaseEvent(self, event):
425 | super().mouseReleaseEvent(event)
426 |
427 | if event.button() == Qt.MouseButton.RightButton:
428 | if self.is_drawing and self.origin is not None:
429 | self.is_drawing = False
430 |
431 | # 获取鼠标释放的位置
432 | release_position = event.pos()
433 |
434 | # 获取释放位置相对于原图的像素位置
435 | release_scene_position = self.mapToScene(release_position)
436 |
437 | # 更新矩形的大小
438 | self.drawing_rect.setRect(QRectF(self.origin, release_scene_position))
439 |
440 | # 显示矩形的坐标信息
441 | self.showRectCoordinates(self.drawing_rect)
442 |
443 | def mousePressEvent(self, event):
444 | super().mousePressEvent(event)
445 |
446 | if event.button() == Qt.MouseButton.RightButton:
447 | if not self.is_drawing:
448 | # 获取鼠标点击的位置
449 | click_position = event.pos()
450 |
451 | # 获取点击位置相对于原图的像素位置
452 | scene_position = self.mapToScene(click_position)
453 | self.origin = scene_position
454 | self.is_drawing = True
455 |
456 | # 创建一个新的矩形
457 | self.drawing_rect = QGraphicsRectItem(QRectF(self.origin, self.origin))
458 | self.scene().addItem(self.drawing_rect)
459 |
460 | def showRectCoordinates(self, rect_item):
461 | # 获取矩形的左上角和右下角相对于图片的坐标
462 | rect_top_left = rect_item.rect().topLeft()
463 | rect_bottom_right = rect_item.rect().bottomRight()
464 | # 将坐标信息显示在矩形的左上角和右下角
465 | # 在矩形的左上角显示坐标信息
466 | text_item_top_left = QGraphicsTextItem(f"({int(rect_top_left.x())}, {int(rect_top_left.y())})")
467 | text_item_top_left.setFont(QFont('Arial', 10))
468 | text_item_top_left.setDefaultTextColor(Qt.GlobalColor.red)
469 | text_item_top_left.setPos(rect_top_left.x() + 5, rect_top_left.y() - 20)
470 | self.scene().addItem(text_item_top_left)
471 | # 在矩形的右下角显示坐标信息
472 | text_item_bottom_right = QGraphicsTextItem(f"({int(rect_bottom_right.x())}, {int(rect_bottom_right.y())})")
473 | text_item_bottom_right.setFont(QFont('Arial', 10))
474 | text_item_bottom_right.setDefaultTextColor(Qt.GlobalColor.red)
475 | text_item_bottom_right.setPos(rect_bottom_right.x() - 50, rect_bottom_right.y() + 5)
476 | self.scene().addItem(text_item_bottom_right)
477 | # 将矩形对象作为键,将坐标信息文本项存储到字典中
478 | rect_key = id(rect_item)
479 | self.coordinate_text_items[rect_key] = [text_item_top_left, text_item_bottom_right]
480 |
481 | def removeCoordinateTextItems(self, text_items):
482 | # 从场景中删除坐标信息文本项
483 | for text_item in text_items:
484 | self.scene().removeItem(text_item)
485 |
486 | # 清空字典中的坐标信息
487 | text_items.clear()
488 | def addTextItem(self, text,
489 | bg_path='./bgs/letter.png',
490 | font_path="./fonts/hand.ttf",font_size=12,
491 | font_color='black',
492 | font_weight=600,
493 | x=100,y=100,
494 | font_spacing=0, line_spacing=1.2,
495 | rect_width=500, rect_height=50):
496 | # 清除先前的文本项
497 | self.scene().clear()
498 | #加载背景图片
499 | pixmap = QPixmap(bg_path)
500 | item = QGraphicsPixmapItem(pixmap)
501 | self.scene().addItem(item)
502 | self.scene().setSceneRect(0, 0, 5000, 5000)
503 | # 创建一个QGraphicsTextItem
504 | text_item = QGraphicsTextItem()
505 | text_item.setPos(x, y)
506 | # 加载本地字体文件,设置字体大小
507 | font_id = QFontDatabase.addApplicationFont(font_path)
508 | font_family = QFontDatabase.applicationFontFamilies(font_id)[0]
509 | font = QFont(font_family,font_size)
510 | text_item.setFont(font)
511 | # 使用 HTML 样式设置文本,包括换行和调整行间距、文字间距
512 | html_text = f"