├── README.md
├── main.py
├── png.ico
├── requirements.txt
├── test.py
├── tool.ico
├── tool.py
├── tools.png
├── tools_png.py
└── ui.py
/README.md:
--------------------------------------------------------------------------------
1 | ## 环境依赖
2 |
3 | 1. python3.X
4 | 2. Pillow:主要用于拼接图片,修改图片分辨率
5 |
6 | ```python
7 | pip install Pillow
8 | ```
9 |
10 | 3. pymupdf:用于将pdf转成图片
11 |
12 | ```python
13 | pip install pymupdf
14 | ```
15 |
16 | 4. PyQt5:用于GUI代码编写
17 |
18 | ```python
19 | pip install PyQt5
20 | ```
21 |
22 | 5. PyQt5-tools:GUI配套工具
23 |
24 | ```python
25 | pip install PyQt5-tools
26 | ```
27 |
28 | 6. Pyinstaller:用于打包python到应用程序
29 |
30 | ```python
31 | pip install pyinstaller
32 | ```
33 |
34 | - 一键安装依赖(上面单个安装和下面一键安装都行)
35 |
36 | ```python
37 | pip -r requirements.txt
38 | ```
39 |
40 | ## 目录结构
41 |
42 | ```shell
43 | - main.py 主程序入口
44 | - png.ico windows打包用的图标
45 | - README.md 使用说明文档
46 | - requirements.txt 依赖记录文件
47 | - tools.ico Mac打包用的图标,可忽略
48 | - tools.py 主要为pdf与图片操作的后端源代码,核心所在
49 | - tools.png 主程序菜单栏的图标,不可删除
50 | - ui.py UI设计界面
51 | - test.py 用于将图片转base64二进制码
52 | - tools_png.py 利用图片转成的py文件,里面存了一个base64字节码,main程序调用的时候会自动释放用来生成图片。
53 | ```
54 |
55 | ## 软件打包
56 |
57 | - 直接使用Pyinstaller打包主程序
58 |
59 | ```python
60 | pyinstaller -i png.ico -F -w main.py
61 | ```
62 |
63 |
64 | ## 其它建议
65 |
66 | - 如果对软件有更好的建议,可以直接给我发邮件371043382@qq.com
67 | - 如果你也是python的学习爱好者,欢迎加群一起学习:974759263
68 | - Python个人博客,不定期更新python学习教程:https://www.vbahome.cn/
69 |
70 |
--------------------------------------------------------------------------------
/main.py:
--------------------------------------------------------------------------------
1 | from ui import UI
2 | import sys
3 | from tool import *
4 | from os import path, listdir
5 | from PyQt5.QtWidgets import QApplication, QFileDialog, QMessageBox, QProgressDialog, QLabel, qApp
6 | from PyQt5.QtGui import QIcon
7 | import json
8 | import base64
9 | from tools_png import img
10 |
11 |
12 | class PdfMain(UI):
13 | def __init__(self):
14 | super(PdfMain, self).__init__()
15 | # --- 窗口1 --- #
16 | self.my_dialog1_1 = None # 会话1,展示pdf转png进度
17 | self.pdf_path = None
18 |
19 | # --- 窗口2 --- #
20 | self.pdf_dir1 = None
21 | self.my_dialog2_1 = None # 会话2_1,用于单列转长图
22 | self.my_dialog2_2 = None # 会话2_2,用于转矩阵长图
23 | self.dialog_line_edit1_value = None # 拼接数量
24 | self.dialog_line_edit2_value = None # 拼接行数
25 | self.dialog_line_edit3_value = None # 拼接列数
26 | self.dialog_line_edit4_value = None # 拼接间隙
27 |
28 | # --- 窗口3 --- #
29 | self.pdf_dir2 = None # 文件夹路径
30 | self.width_model = '普通' # 图片宽度模式
31 | self.picture_type = 'jpg' # 图片格式
32 | self.zip_num = None # 图片压缩率
33 | self.my_dialog3 = None # 会话3,用于压缩图片
34 |
35 | # -- 运行窗口 -- #
36 | self.init_action()
37 |
38 | def init_action(self):
39 | self.show_frame1()
40 |
41 | def show_frame1(self):
42 | """
43 | 重写窗口1的方法,加入按钮监控
44 | :return:
45 | """
46 | super(PdfMain, self).show_frame1()
47 | self.push_button1_1.clicked.connect(self.file_select) # 连接选择文件
48 | self.push_button1_2.clicked.connect(self.do_convert) # 连接开始转换
49 | self.push_button1_3.clicked.connect(qApp.quit) # 连接退出软件
50 |
51 | def show_frame2(self):
52 | super(PdfMain, self).show_frame2()
53 | self.push_button2_1.clicked.connect(self.dir1_select) # 连接选择文件夹
54 | self.push_button2_2.clicked.connect(self.one_step2long) # 连接一键长图
55 |
56 | def show_frame3(self):
57 | super(PdfMain, self).show_frame3()
58 |
59 | # 加入上次的输入框
60 | width_model = self.read_data_dict('width_model')
61 | picture_type = self.read_data_dict('picture_type')
62 | pdf_dir2 = self.read_data_dict('pdf_dir2')
63 | zip_num = self.read_data_dict('zip_num')
64 | if pdf_dir2 is not None:
65 | self.line_edit3_1.setText(pdf_dir2)
66 | self.pdf_dir2 = pdf_dir2
67 | if zip_num is not None:
68 | self.line_edit3_2.setText(zip_num)
69 | self.zip_num = zip_num
70 | else:
71 | self.line_edit3_2.setText('92')
72 | self.zip_num = '92'
73 | if width_model is not None:
74 | self.width_model = width_model
75 | self.combo_box3_1.setCurrentText(width_model)
76 | if picture_type is not None:
77 | self.picture_type = picture_type
78 | self.combo_box3_2.setCurrentText(picture_type)
79 | # 监控按键3-1:自定义路径
80 | self.push_button3_1.clicked.connect(self.dir2_select)
81 | # 检测下拉框:压缩宽度
82 | self.combo_box3_1.activated[str].connect(self.combo_box3_1_select) # 图片宽度模式
83 | self.combo_box3_2.activated[str].connect(self.combo_box3_2_select) # 图片格式
84 | self.line_edit3_2.textEdited.connect(self.line_edit3_2_change) # 压缩比
85 | # 连接一键压缩
86 | self.push_button3_2.clicked.connect(self.one_step_zip) # 连接一键压缩
87 |
88 | # 公用进度条
89 | def show_process_bar(self, label_text):
90 | """
91 | 显示进度条
92 | """
93 | self.progress = QProgressDialog() # 设定窗口
94 | # self.progress.setGeometry(320, 190, 250, 100)
95 | self.progress.resize(250, 100)
96 | self.progress.setWindowIcon(QIcon('tools.png'))
97 | self.progress.setMinimumSize(250, 100)
98 | label = QLabel(label_text, self.progress)
99 | label.move(12, 18)
100 | label.setStyleSheet("font-size:12px; font-weight:normal")
101 | self.progress.setWindowTitle('进度条')
102 | self.progress.setRange(0, 100)
103 | self.progress.show()
104 |
105 | # ----- 以下方法用于窗口1------------- #
106 | def file_select(self):
107 | """
108 | 文件选择,用于窗口1
109 | """
110 | f_dialog = QFileDialog()
111 | # f_dialog.setGeometry(350, 350, 300, 150)
112 | f_dialog.setWindowIcon(QIcon('tools.png'))
113 | f_dialog.setWindowTitle('选择文件')
114 | file = f_dialog.getOpenFileName()
115 | if bool(file[0]):
116 | self.line_edit1_1.setText(file[0])
117 | self.pdf_path = file[0]
118 |
119 | def do_convert(self):
120 | """
121 | 进度条, main Process
122 | :param
123 | """
124 | if self.pdf_path is None:
125 | pdf_path = self.read_data_dict('pdf_path')
126 | if pdf_path is None:
127 | text = '亲,你还没有选择文件路径'
128 | QMessageBox.warning(self, '错误', text,
129 | QMessageBox.No | QMessageBox.Yes, QMessageBox.No)
130 | else:
131 | text = '亲,确认使用上次的路径?'
132 | replay = QMessageBox.warning(self, '错误', text,
133 | QMessageBox.No | QMessageBox.Yes, QMessageBox.No)
134 | if replay != 65536:
135 | self.pdf_path = pdf_path
136 | self.pdf2png()
137 |
138 | else:
139 | file_name0 = path.split(self.pdf_path)[1]
140 | # pdf_name = path.splitext(file_name0)[0]
141 | file_type = path.splitext(file_name0)[1]
142 | if file_type.upper() != '.PDF':
143 | text = '亲,你选择的不是pdf文件'
144 | QMessageBox.warning(self, '错误', text,
145 | QMessageBox.No | QMessageBox.Yes, QMessageBox.No)
146 | else:
147 | self.write_data_dict('pdf_path', self.pdf_path) # 将pdf路径保存到字典
148 | self.pdf2png()
149 |
150 | def pdf2png(self):
151 | """
152 | 用于pdf转png
153 | :return:
154 | """
155 | pdf = PdfInit(self.pdf_path) # 处理pdf
156 | self.show_process_bar('正在将pdf转成单张图片, 请稍后')
157 | self.my_dialog1_1 = Pdf2Png(pdf)
158 | self.my_dialog1_1.start()
159 | self.my_dialog1_1.trigger.connect(self.process_pdf2png)
160 |
161 | def process_pdf2png(self, int1, int2):
162 | print(int1, int2)
163 | value = int((int1 + 1) * 100 / int2) # 这里的页面数量需要加1
164 | self.progress.setValue(value)
165 |
166 | # ----- 以下方法用于窗口2------------- #
167 | def dir1_select(self):
168 | """
169 | 自定义路径
170 | :return:
171 | """
172 | f_dialog2 = QFileDialog()
173 | # f_dialog.setGeometry(350, 350, 300, 150)
174 | f_dialog2.setWindowIcon(QIcon('tools.png'))
175 | f_dialog2.setWindowTitle('选择文件夹')
176 | dir1 = f_dialog2.getExistingDirectory()
177 | if bool(dir1):
178 | self.line_edit2_1.setText(dir1)
179 | self.pdf_dir1 = dir1
180 |
181 | def one_step2long(self):
182 | """
183 | 一键生成长图
184 | :return:
185 | """
186 | text_list = listdir(self.pdf_dir1)
187 | text_list2 = [fn for fn in text_list if fn.endswith('.png') or fn.endswith('jpg')]
188 | if len(text_list2) == 0:
189 | text = "你当前路径下没有任何png或者jpg图片"
190 | QMessageBox.warning(self, '警告', text,
191 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
192 | else:
193 | if self.pdf_dir1 is not None:
194 | png_list = listdir(self.pdf_dir1)
195 | png_num = len(png_list) # 获取图片数量
196 | parent_path = path.split(self.pdf_dir1)[0] # 获取父目录
197 | out_path = parent_path + '/一键长图'
198 | my_dialog2_1 = GenLongPng(png_num, self.pdf_dir1, out_path)
199 | my_dialog2_1.run()
200 | text = "长图生成成功,请到pdf同路径的”一键长图“文件夹查看"
201 | QMessageBox.warning(self, '恭喜', text,
202 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
203 |
204 | else:
205 | text = "亲!你还没有选择图片所在文件夹"
206 | QMessageBox.warning(self, '警告', text,
207 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
208 |
209 | def show_dialog1(self):
210 | """
211 | 重写会话1系统,用于单列拼接
212 | :return:
213 | """
214 | super(PdfMain, self).show_dialog1()
215 | # 加入上次的输入框
216 | dialog_line_edit1_value = self.read_data_dict('dialog_line_edit1_value')
217 | if dialog_line_edit1_value is not None:
218 | self.dialog_line_edit1.setText(dialog_line_edit1_value)
219 | self.dialog_line_edit1_value = dialog_line_edit1_value
220 | # 监控输入框变化
221 | self.dialog_line_edit1.textEdited.connect(self.dialog_line_edit1_change)
222 | # 检测按钮:一键转换单列长图
223 | self.dialog_push_button1.clicked.connect(self.customize_one_column_long_png)
224 | self.dialog1.show()
225 |
226 | def customize_one_column_long_png(self):
227 | text_list = listdir(self.pdf_dir1)
228 | text_list2 = [fn for fn in text_list if fn.endswith('.png') or fn.endswith('jpg')]
229 | if len(text_list2) == 0:
230 | text = "你当前路径下没有任何png或者jpg图片"
231 | QMessageBox.warning(self, '警告', text,
232 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
233 | else:
234 | if self.dialog_line_edit1_value is None:
235 | png_list = listdir(self.pdf_dir1)
236 | png_num = len(png_list) # 获取图片数量
237 | text = "亲!还没有输入”拼接数量“呢?最大不能超过图片总数{}哦".format(png_num)
238 | QMessageBox.warning(self, '警告', text,
239 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
240 | else:
241 | parent_path = path.split(self.pdf_dir1)[0] # 获取父目录
242 | out_path = parent_path + '/单列长图'
243 | self.write_data_dict('dialog_line_edit1_value', self.dialog_line_edit1_value) # 存入字典
244 | self.show_process_bar('正在将图片拼接成多张长图, 请稍后')
245 | self.my_dialog2_1 = GenLongPng(int(self.dialog_line_edit1_value), self.pdf_dir1, out_path)
246 | self.my_dialog2_1.start()
247 | self.my_dialog2_1.trigger.connect(self.process_pdf2png)
248 |
249 | def dialog_line_edit1_change(self, value):
250 | if self.is_number(value) and '.' not in value: # 如果属于数字并且为整数
251 | png_list = listdir(self.pdf_dir1)
252 | png_num = len(png_list) # 获取图片数量
253 | if int(float(value)) > png_num:
254 | text = "亲!最大不能超过图片数量,当前文件夹只有{}张图片。".format(png_num)
255 | QMessageBox.warning(self, '警告', text,
256 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
257 | self.dialog_line_edit1.setText(None)
258 | else:
259 | self.dialog_line_edit1_value = str(value)
260 | else:
261 | text = "亲!只能输入整数"
262 | QMessageBox.warning(self, '警告', text,
263 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
264 | self.dialog_line_edit1.setText(None)
265 |
266 | @staticmethod
267 | def is_number(s):
268 | """
269 | 检测是否为数字
270 | :param s:
271 | :return:
272 | """
273 | try:
274 | float(s)
275 | return True
276 | except ValueError:
277 | pass
278 |
279 | try:
280 | import unicodedata
281 | unicodedata.numeric(s)
282 | return True
283 | except (TypeError, ValueError):
284 | pass
285 |
286 | return False
287 |
288 | def show_dialog2(self):
289 | """
290 | 重写会话2系统,用于矩阵拼接
291 | :return:
292 | """
293 | super(PdfMain, self).show_dialog2()
294 | # 加入上次的输入框
295 | dialog_line_edit2_value = self.read_data_dict('dialog_line_edit2_value')
296 | dialog_line_edit3_value = self.read_data_dict('dialog_line_edit3_value')
297 | dialog_line_edit4_value = self.read_data_dict('dialog_line_edit4_value')
298 | if dialog_line_edit2_value is not None:
299 | self.dialog_line_edit2.setText(dialog_line_edit2_value)
300 | self.dialog_line_edit2_value = dialog_line_edit2_value
301 | if dialog_line_edit3_value is not None:
302 | self.dialog_line_edit3.setText(dialog_line_edit3_value)
303 | self.dialog_line_edit3_value = dialog_line_edit3_value
304 | else:
305 | self.dialog_line_edit3.setText('1')
306 | self.dialog_line_edit3_value = '1'
307 | if dialog_line_edit4_value is not None:
308 | self.dialog_line_edit4.setText(dialog_line_edit4_value)
309 | self.dialog_line_edit4_value = dialog_line_edit4_value
310 | else:
311 | self.dialog_line_edit4.setText('0')
312 | self.dialog_line_edit4_value = '0'
313 | # 监控输入框变化
314 | self.dialog_line_edit2.textEdited.connect(self.dialog_line_edit2_change) # 检测行数
315 | self.dialog_line_edit3.textEdited.connect(self.dialog_line_edit3_change) # 检测列数
316 | self.dialog_line_edit4.textEdited.connect(self.dialog_line_edit4_change) # 检测px像素
317 | self.dialog_push_button2.clicked.connect(self.matrix_long_png) # 矩阵拼图
318 | self.dialog2.show()
319 |
320 | def dialog_line_edit2_change(self, value):
321 | """
322 | 检测列数量
323 | :param value:
324 | :return:
325 | """
326 | if self.is_number(value) and '.' not in value: # 如果属于数字并且为整数
327 | png_list = listdir(self.pdf_dir1)
328 | png_num = len(png_list) # 获取图片数量
329 | if int(float(value)) > png_num:
330 | text = "亲!最大不能超过图片数量,当前文件夹只有{}张图片。".format(png_num)
331 | QMessageBox.warning(self, '警告', text,
332 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
333 | self.dialog_line_edit2.setText(None)
334 | else:
335 | self.dialog_line_edit2_value = str(value)
336 | else:
337 | text = "亲!只能输入整数"
338 | QMessageBox.warning(self, '警告', text,
339 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
340 | self.dialog_line_edit2.setText(None)
341 |
342 | def dialog_line_edit3_change(self, value):
343 | """
344 | 检测行数量
345 | :param value:
346 | :return:
347 | """
348 | if self.is_number(value) and '.' not in value: # 如果属于数字并且为整数
349 | png_list = listdir(self.pdf_dir1)
350 | png_num = len(png_list) # 获取图片数量
351 | if int(float(value)) > png_num:
352 | text = "亲!最大不能超过图片数量,当前文件夹只有{}张图片。".format(png_num)
353 | QMessageBox.warning(self, '警告', text,
354 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
355 | self.dialog_line_edit3.setText(None)
356 | else:
357 | self.dialog_line_edit3_value = str(value)
358 | else:
359 | text = "亲!只能输入整数"
360 | QMessageBox.warning(self, '警告', text,
361 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
362 | self.dialog_line_edit3.setText(None)
363 |
364 | def dialog_line_edit4_change(self, value):
365 | """
366 | 检测像素间隔px值
367 | :param value:
368 | :return:
369 | """
370 | if self.is_number(value) and '.' not in value: # 如果属于数字并且为整数
371 | self.dialog_line_edit4_value = str(value)
372 | else:
373 | text = "亲!只能输入整数"
374 | QMessageBox.warning(self, '警告', text,
375 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
376 | self.dialog_line_edit4.setText(None)
377 |
378 | def matrix_long_png(self):
379 | """
380 | 自定义拼图之矩阵拼图
381 | :return:
382 | """
383 | text_list = listdir(self.pdf_dir1)
384 | text_list2 = [fn for fn in text_list if fn.endswith('.png') or fn.endswith('jpg')]
385 | if len(text_list2) == 0:
386 | text = "你当前路径下没有任何png或者jpg图片"
387 | QMessageBox.warning(self, '警告', text,
388 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
389 | else:
390 | result = False
391 | png_list = listdir(self.pdf_dir1)
392 | png_num = len(png_list) # 获取图片数量
393 | if self.dialog_line_edit2_value is None or self.dialog_line_edit3_value is None or \
394 | self.dialog_line_edit3_value is None:
395 | text = "亲!还有三个空没填全,没法开始"
396 | QMessageBox.warning(self, '警告', text,
397 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
398 | elif int(float(self.dialog_line_edit2_value)) * int(float(self.dialog_line_edit3_value)) > png_num:
399 | text = "行与列之积大于总图片数量,将会产生较多空白,是否继续?"
400 | replay = QMessageBox.warning(self, '警告', text,
401 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
402 | if replay != 65536: # 如果选择”yes“
403 | result = True
404 | else:
405 | result = True
406 | if bool(result):
407 | self.write_data_dict('dialog_line_edit2_value', self.dialog_line_edit2_value)
408 | self.write_data_dict('dialog_line_edit3_value', self.dialog_line_edit3_value)
409 | self.write_data_dict('dialog_line_edit4_value', self.dialog_line_edit4_value)
410 | row = int(self.dialog_line_edit2_value)
411 | column = int(self.dialog_line_edit3_value)
412 | interval = int(self.dialog_line_edit4_value)
413 | parent_path = path.split(self.pdf_dir1)[0] # 获取父目录
414 | out_path = parent_path + '/矩阵长图'
415 | self.show_process_bar('正在将图片拼接成多张长图, 请稍后')
416 | self.my_dialog2_2 = GenLongPng2(row, column, interval, self.pdf_dir1, out_path)
417 | self.my_dialog2_2.start()
418 | self.my_dialog2_2.trigger.connect(self.process_pdf2png)
419 |
420 | # --- 以下代码用于窗口3 --- #
421 | def dir2_select(self):
422 | """
423 | 自定义路径
424 | :return:
425 | """
426 | f_dialog2 = QFileDialog()
427 | # f_dialog.setGeometry(350, 350, 300, 150)
428 | f_dialog2.setWindowIcon(QIcon('tools.png'))
429 | f_dialog2.setWindowTitle('选择文件夹')
430 | dir2 = f_dialog2.getExistingDirectory()
431 | if bool(dir2):
432 | self.line_edit3_1.setText(dir2)
433 | self.pdf_dir2 = dir2
434 |
435 | def combo_box3_1_select(self, text):
436 | """
437 | 此方法用于选择图片宽度
438 | :param text: 接收的文本
439 | :return:
440 | """
441 | self.width_model = str(text)
442 | print(text)
443 |
444 | def combo_box3_2_select(self, text):
445 | """
446 | 此方法用于选择图片格式
447 | :param text: 接收的文本
448 | :return:
449 | """
450 | self.picture_type = str(text)
451 | print(text)
452 |
453 | def line_edit3_2_change(self, value):
454 | if self.is_number(value) and '.' not in value: # 如果属于数字并且为整数
455 | self.zip_num = str(value)
456 | else:
457 | text = "亲!只能输入整数"
458 | QMessageBox.warning(self, '警告', text,
459 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
460 | self.line_edit3_2.setText(None)
461 |
462 | def one_step_zip(self):
463 | # 查看一下路径里面有没有图片
464 | text_list = listdir(self.pdf_dir2)
465 | text_list2 = [fn for fn in text_list if fn.endswith('.png') or fn.endswith('jpg')]
466 | if len(text_list2) == 0:
467 | text = "你当前路径下没有任何png或者jpg图片"
468 | QMessageBox.warning(self, '警告', text,
469 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
470 | else:
471 | text = "你的当前配置是:宽度模式:”{}“, 格式: ”{}“, 压缩比:”{}%“
路径:”{}“
是否确认?"\
472 | .format(self.width_model, self.picture_type, self.zip_num, self.pdf_dir2)
473 | replay = QMessageBox.warning(self, '提示', text,
474 | QMessageBox.Yes | QMessageBox.Yes, QMessageBox.No)
475 | print(replay)
476 | if replay != 65536:
477 | # -- 保存相关配置到字典中 -- #
478 | self.write_data_dict('width_model', self.width_model)
479 | self.write_data_dict('picture_type', self.picture_type)
480 | self.write_data_dict('zip_num', self.zip_num)
481 | self.write_data_dict('pdf_dir2', self.pdf_dir2)
482 | # -- 保存完毕 --- #
483 | self.show_process_bar('正在压缩图片, 请稍后')
484 | # print(self.width_model, self.picture_type, self.zip_num, self.pdf_dir2)
485 | self.my_dialog3 = ZipPng(self.width_model, self.picture_type, int(self.zip_num), self.pdf_dir2)
486 | self.my_dialog3.start()
487 | self.my_dialog3.trigger.connect(self.process_pdf2png)
488 |
489 |
490 | if __name__ == '__main__':
491 | # 创建一个data.json文件,用于储存变量参数
492 | if not path.exists('data.json'):
493 | data_dict = {}
494 | with open('data.json', 'wt', encoding='utf-8') as f:
495 | json.dump(data_dict, f)
496 | if not path.exists('tools.png'):
497 | img_data = base64.b64decode(img)
498 | f = open('tools.png', 'wb')
499 | f.write(img_data)
500 | f.close()
501 | app = QApplication(sys.argv)
502 | pdf_main = PdfMain()
503 | sys.exit(app.exec_())
--------------------------------------------------------------------------------
/png.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tlntin/PyQt5_PdfTools/74bad54dc3e75c075595695d3b5c1b6f0e2ba5f1/png.ico
--------------------------------------------------------------------------------
/requirements.txt:
--------------------------------------------------------------------------------
1 | altgraph==0.17
2 | certifi==2023.7.22
3 | click==7.1.2
4 | future==0.18.3
5 | pefile==2019.4.18
6 | Pillow>=8.1.1
7 | PyInstaller==3.6
8 | PyMuPDF==1.16.18
9 | PyQt5==5.14.2
10 | PyQt5-sip==12.7.2
11 | pyqt5-tools==5.14.2.1.7b3
12 | PySimpleGUI==4.14.1
13 | python-dotenv==0.13.0
14 | pywin32-ctypes==0.2.0
15 | wincertstore==0.2
16 |
--------------------------------------------------------------------------------
/test.py:
--------------------------------------------------------------------------------
1 | import base64
2 |
3 |
4 | def pic2py(picture_name):
5 | """
6 | 将图像文件转换为py文件
7 | :param picture_name:
8 | :return:
9 | """
10 | open_pic = open("%s" % picture_name, 'rb')
11 | b64str = base64.b64encode(open_pic.read())
12 | open_pic.close()
13 | # 注意这边b64str一定要加上.decode()
14 | write_data = 'img = "%s"' % b64str.decode()
15 | f = open('%s.py' % picture_name.replace('.', '_'), 'w+')
16 | f.write(write_data)
17 | f.close()
18 |
19 |
20 | if __name__ == '__main__':
21 | pics = ["tools.png"]
22 | for i in pics:
23 | pic2py(i)
--------------------------------------------------------------------------------
/tool.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tlntin/PyQt5_PdfTools/74bad54dc3e75c075595695d3b5c1b6f0e2ba5f1/tool.ico
--------------------------------------------------------------------------------
/tool.py:
--------------------------------------------------------------------------------
1 | from os import path, mkdir, getcwd, listdir, remove
2 | from PIL import Image
3 | import fitz
4 | from PyQt5.QtCore import pyqtSignal, QThread
5 | from math import ceil, sqrt
6 |
7 |
8 | class PdfInit(object):
9 | """
10 | pdf初始化
11 | """
12 |
13 | def __init__(self, file_path):
14 | self.file_path = file_path # 图片路径
15 | self.out_put_dir = None # 输出路径
16 | self.file_name = None # 文件名
17 | self.page_num = None
18 | self.doc = None
19 | self.get_page_num() # 初始化
20 |
21 | def get_page_num(self):
22 | """
23 | 此方法用于获取pdf页面数量,并且计算导出路径
24 | :param
25 | """
26 | dir_path = path.split(self.file_path)[0] # 获取路径所在文件夹
27 | b = path.join(dir_path, '导出图片')
28 | self.out_put_dir = b
29 | if not path.exists(b): # 如果路径不存在
30 | mkdir(b)
31 | # 打开PDF文件,生成一个对象
32 | self.doc = fitz.open(self.file_path)
33 | self.page_num = self.doc.pageCount
34 |
35 |
36 | class Pdf2Png(QThread):
37 | """
38 | 这个类用于将pdf转成png图片
39 | """
40 | trigger = pyqtSignal(int, int) # 创建信号池,共发射两个信号
41 |
42 | def __init__(self, pdf_init):
43 | super(Pdf2Png, self).__init__()
44 | self.file_path = pdf_init.file_path
45 | self.doc = pdf_init.doc
46 | self.page_num = pdf_init.page_num
47 | self.output_dir = pdf_init.out_put_dir
48 | # 设置窗口
49 |
50 | def run(self):
51 | for pg in range(self.page_num):
52 | # print('正在导出第{}张图片'.format(pg))
53 | page = self.doc[pg]
54 | rotate = int(0)
55 | # 每个尺寸的缩放系数为2,这将为我们生成分辨率提高四倍的图像。
56 | zoom_x = 2.0
57 | zoom_y = 2.0
58 | trans = fitz.Matrix(zoom_x, zoom_y).preRotate(rotate)
59 | pm = page.getPixmap(matrix=trans, alpha=False)
60 | pm.writePNG('%s/page_%s.png' % (self.output_dir, pg)) # 保存图片
61 | self.trigger.emit(pg, self.page_num) # 发射信号
62 | print('图片导出成功')
63 |
64 |
65 | class GenLongPng(QThread):
66 | """
67 | 这个类用于将单张png转成长图
68 | :param
69 | """
70 | trigger = pyqtSignal(int, int) # 构建触发器,用于后面发送消息.第一个信号为当前进度,第二个信号为总进度
71 |
72 | def __init__(self, png_num, png_dir, out_dir):
73 | """
74 | :param png_num: 拼接的图片数量
75 | :param png_dir: 图片所在路径
76 | :param out_dir: 导出图片路径
77 | """
78 | super(GenLongPng, self).__init__()
79 | self.png_num = png_num
80 | self.png_dir = png_dir # 图片地址
81 | self.out_dir = out_dir # 导出的长图地址
82 | self.long_png_path = None # 长图路径
83 |
84 | def run(self):
85 | """
86 | 用于图片拼接
87 | :return:
88 | """
89 | if not path.exists(self.out_dir):
90 | mkdir(self.out_dir)
91 | else:
92 | list1 = listdir(self.out_dir)
93 | data = [remove(self.out_dir + '/' + li) for li in list1] # 清空原有文件
94 | self.long_png_path = self.out_dir + '/' + 'page_{}.png' # 长图地址
95 | png_list = listdir(self.png_dir) # 获取所有图片
96 | try: # 尝试排序
97 | png_list.sort(key=lambda m: int(m[5: len(m) - 4]))
98 | except Exception as err:
99 | print('排序失败')
100 | print(err)
101 | ims = [Image.open(path.join(self.png_dir, fn)) for fn in png_list if fn.endswith('.png')] # 获取所有图片信息
102 | number = ceil(len(ims) / self.png_num) # 向上取整,判断可以分成的长图的个数
103 | remain = len(ims) % self.png_num # 余数,判断最后一张长图剩余数
104 | for x in range(number): # 开始循环生成长图
105 | if remain > 0: # 如果余数大于0
106 | if x < number - 1: # 如果不是最后一张图
107 | self.paste_png(ims, self.png_num, x) # 按最大拼接拼接图片
108 | else: # 如果是最后一张图
109 | self.paste_png(ims, remain, x) # 按余数拼接图片
110 | elif remain == 0: # 如果余数为零
111 | self.paste_png(ims, self.png_num, x) # 按最大拼接图片,不用考虑最后一张图
112 | self.trigger.emit(x, number) # 发射信号
113 |
114 | def paste_png(self, ims, n1, x):
115 | """
116 | 此方法用于粘贴单个长图
117 | :param ims: 所有图片的信息
118 | :param n1: 本次预计拼接的图片数量
119 | :param x: x为当前图片的页码数减1
120 | """
121 | width, height = ims[0].size # 获取单张图片大小
122 | whiter_picture1 = Image.new(ims[0].mode, (width, height * n1)) # 创建空白图,长度为n1的长度
123 | for y, im in enumerate(ims[x * self.png_num: self.png_num * x + n1]):
124 | whiter_picture1.paste(im, box=(0, y * height)) # 图片粘贴拼凑
125 | whiter_picture1.save(self.long_png_path.format(x)) # 长图保存
126 |
127 |
128 | class GenLongPng2(QThread):
129 | """
130 | 这个类用于将单张png转成长图,包含矩阵算法
131 | :param
132 | """
133 | trigger = pyqtSignal(int, int) # 构建触发器,用于后面发送消息.第一个信号为当前进度,第二个信号为总进度
134 |
135 | def __init__(self, png_row, png_column, png_interval, png_dir, out_dir):
136 | """
137 | :param png_row: 拼接的图片的行数
138 | :param png_column: 拼接图片的列数
139 | :param png_interval:凭借图片的间隙
140 | :param png_dir: 图片的路径
141 | :param out_dir: 导出图片路径
142 | """
143 | super(GenLongPng2, self).__init__()
144 | self.png_row = png_row
145 | self.png_column = png_column
146 | self.png_interval = png_interval
147 | self.png_dir = png_dir # 图片地址
148 | self.out_dir = out_dir # 导出的长图地址
149 | self.long_png_path = None # 长图路径
150 |
151 | def run(self):
152 | """
153 | 用于图片拼接
154 | :return:
155 | """
156 | if not path.exists(self.out_dir):
157 | mkdir(self.out_dir)
158 | else:
159 | list1 = listdir(self.out_dir)
160 | data = [remove(self.out_dir + '/' + li) for li in list1] # 清空原有文件
161 | self.long_png_path = self.out_dir + '/' + 'page_{}.png' # 长图地址
162 | png_list = listdir(self.png_dir) # 获取所有图片
163 | try: # 尝试排序
164 | png_list.sort(key=lambda m: int(m[5: len(m) - 4]))
165 | except Exception as err:
166 | print('排序失败')
167 | print(err)
168 | ims = [Image.open(path.join(self.png_dir, fn)) for fn in png_list if fn.endswith('.png')] # 获取所有图片信息
169 | if len(ims) > (self.png_row * self.png_column):
170 | number = ceil(len(ims) / (self.png_row * self.png_column)) # 向上取整,判断可以分成的长图的个数
171 | if number > 1:
172 | remain = len(ims) % (self.png_row * self.png_column) # 余数,判断最后一张长图剩余数
173 | else:
174 | remain = 0
175 | else:
176 | number = 1
177 | remain = len(ims)
178 | for x in range(number): # 开始循环生成长图
179 | if remain > 0: # 如果余数大于0
180 | if x < number - 1: # 如果不是最后一张图
181 | self.paste_png(ims, self.png_row * self.png_column, x) # 按最大拼接拼接图片
182 | else: # 如果是最后一张图
183 | self.paste_png(ims, remain, x) # 按余数拼接图片
184 | elif remain == 0: # 如果余数为零
185 | self.paste_png(ims, self.png_row * self.png_column, x) # 按最大拼接图片,不用考虑最后一张图
186 | self.trigger.emit(x, number) # 发射信号
187 |
188 | def paste_png(self, ims, n1, x):
189 | """
190 | 此方法用于粘贴单个长图
191 | :param ims: 所有图片的信息
192 | :param n1: 本次预计拼接的图片数量
193 | :param x: x为当前图片的页码数减1
194 | """
195 | width, height = ims[0].size # 获取单张图片大小
196 | # 创建空白白图备用
197 | whiter_picture2 = Image.new("RGB", (width, height), "#FFFFFF")
198 | # 判断本次是否会产生空白图
199 | # -- 如果没有空白 -- #
200 | if n1 == self.png_column * self.png_row:
201 | new_width = width * self.png_column + (self.png_column - 1) * self.png_interval
202 | new_height = height * self.png_row + (self.png_row - 1) * self.png_interval
203 | else:
204 | # 如果只有一行图
205 | if n1 <= self.png_column:
206 | new_width = width * n1 + (n1 - 1) * self.png_interval
207 | new_height = height
208 | else:
209 | rows = ceil(n1 / self.png_column) # 计算总行数
210 | new_width = width * self.png_column + (self.png_column - 1) * self.png_interval
211 | new_height = height * rows + (rows - 1) * self.png_interval
212 | if self.png_column != 1: # 如果存在多余空白框
213 | # -- 用于填充---
214 | need_n = self.png_column * self.png_row - n1
215 | n1 = self.png_column * self.png_row
216 | # 批量插入白图
217 | for i in range(need_n):
218 | ims.append(whiter_picture2)
219 | print(len(ims))
220 | # 创建透明大图
221 | big_picture = Image.new(ims[0].mode, (new_width, new_height))
222 | for y, im in enumerate(ims[x * self.png_row * self.png_column: self.png_row * self.png_column * x + n1]):
223 | p = y + 1
224 | row = int(y / self.png_column) + 1
225 | p = p - self.png_column * (row - 1)
226 | big_picture.paste(im, box=((p-1) * (width + self.png_interval), (row-1) * (height + self.png_interval)))
227 | big_picture.save(self.long_png_path.format(x)) # 长图保存
228 |
229 |
230 | class ZipPng(QThread):
231 | trigger = pyqtSignal(int, int) # 设定信号发送器
232 |
233 | def __init__(self, width_model, picture_type, zip_num, png_dir):
234 | """
235 | 初始化构造函数
236 | :param width_model: 图片宽度模式,普通样式还是720p/1080p
237 | :param zip_num: 保存图片压缩率
238 | :param picture_type: 图片格式,png/jpg
239 | :param png_dir:待压缩图片来源
240 | """
241 | super().__init__()
242 | self.width_model = width_model
243 | self.picture_type = picture_type
244 | self.zip_num = zip_num
245 | self.png_dir = png_dir
246 |
247 | def run(self):
248 | """
249 | 用于压缩文件
250 | :return:
251 | """
252 | parent_dir = path.split(self.png_dir)[0] # 找到图片的父路径
253 | if self.picture_type == '720p':
254 | c = parent_dir + '/' + '720P图(压缩后)'
255 | elif self.picture_type == '1080p':
256 | c = parent_dir + '/' + '1080P图(压缩后)'
257 | else: # 如果是普通图片
258 | c = parent_dir + '/' + '普通图(压缩后)'
259 | if not path.exists(c):
260 | mkdir(c)
261 | else:
262 | list1 = listdir(c)
263 | for li in list1:
264 | remove(c + '/' + li)
265 | png_list = listdir(self.png_dir)
266 | zip_picture = c + '/' + 'page_{}.' + self.picture_type # 压缩图输出路径
267 | png_list = listdir(self.png_dir) # 计算未压缩的长图路径里面的图片数量
268 | try:
269 | png_list.sort(key=lambda m: int(m[5: len(m) - 4])) # 文件排序
270 | except Exception as err:
271 | print('排序失败')
272 | print(err)
273 | png_0 = self.png_dir + '/' + png_list[0]
274 | png_file_size = path.getsize(png_0) # 第一张图片文件大小
275 | e = round(sqrt(png_file_size / (1024 ** 2)), 4) # 计算要压缩的倍数,平方根,取3位小数,这里取这里根据图片数量自动计算压缩倍数
276 | print(e)
277 | # 获取所有图片信息
278 | ims = [Image.open(self.png_dir + '/' + fn) for fn in png_list if fn.endswith('.png') or fn.endswith('jpg')]
279 | i = 0
280 | for im in ims:
281 | w, h = im.size # 获取文件的宽、高
282 | if self.picture_type == '720p':
283 | w1 = 720
284 | h1 = 720 * h / w
285 | elif self.picture_type == '1080p':
286 | w1 = 1080
287 | h1 = 1080 * h / w
288 | else: # 如果是普通模式
289 | w1 = w / e
290 | h1 = h / e
291 | im.thumbnail((int(w1), int(h1))) # 缩放并取整
292 | im.save(zip_picture.format(i), quality=int(self.zip_num)) # 保存缩放后的图片,保存质量92%
293 | i += 1
294 | self.trigger.emit(i, len(png_list)) # 发送信号
295 |
296 |
297 | if __name__ == '__main__':
298 | pass
299 |
--------------------------------------------------------------------------------
/tools.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Tlntin/PyQt5_PdfTools/74bad54dc3e75c075595695d3b5c1b6f0e2ba5f1/tools.png
--------------------------------------------------------------------------------
/tools_png.py:
--------------------------------------------------------------------------------
1 | img = "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"
--------------------------------------------------------------------------------
/ui.py:
--------------------------------------------------------------------------------
1 | from PyQt5.QtWidgets import QMainWindow, QMenuBar, QApplication, QAction, QWidget, QPushButton, QLabel, QLineEdit,\
2 | QComboBox, QDialog, QDesktopWidget
3 | from PyQt5.QtGui import QIcon, QFont
4 | from PyQt5.QtCore import Qt
5 | import sys
6 | import json
7 | from os import path, getcwd
8 |
9 |
10 | class UI(QMainWindow):
11 | def __init__(self):
12 | super(UI, self).__init__()
13 | # -- 基础设置 -- #
14 | self.cp = QDesktopWidget().availableGeometry().center()
15 | qr = self.frameGeometry()
16 | qr.moveCenter(self.cp)
17 | self.move(qr.topLeft())
18 | self.resize(340, 150)
19 | self.setMinimumSize(340, 150)
20 | self.setMaximumSize(340, 150)
21 | self.setWindowTitle('pdf转长图助手')
22 | self.setWindowIcon(QIcon('tools.png'))
23 | # --字体设置--#
24 | # 字体8号
25 | self.font_8 = QFont()
26 | self.font_8.setPointSize(8)
27 | # 字体9号
28 | self.font_9 = QFont()
29 | self.font_9.setPointSize(9)
30 |
31 | # --菜单控件设置 -- #
32 | self.menubar = QMenuBar() # 这里暂时不设置父类
33 | self.menubar.setFont(self.font_8)
34 | menu = self.menubar.addMenu('&菜单')
35 | self.menu_about = self.menubar.addMenu('&关于')
36 | self.action4 = QAction('版本号', self)
37 | self.action4.setFont(self.font_8)
38 | self.menu_about.addAction(self.action4)
39 | self.action4.triggered.connect(self.about_dialog) # 菜单栏4触发器
40 | self.action1 = QAction('使用说明', self)
41 | self.action1.setFont(self.font_8)
42 | self.action2 = QAction('更新记录', self)
43 | self.action2.setFont(self.font_8)
44 | self.action3 = QAction('我要反馈', self)
45 | self.action3.setFont(self.font_8)
46 | menu.addAction(self.action1)
47 | menu.addAction(self.action2)
48 | menu.addAction(self.action3)
49 |
50 | # -- 菜单控制连接器
51 | self.action1.triggered.connect(self.notice_dialog) # 菜单栏1触发器
52 | self.action2.triggered.connect(self.update_dialog) # 菜单栏2触发器
53 | self.action3.triggered.connect(self.feedback_dialog) # 菜单栏3触发器
54 |
55 | # -- 窗口1
56 | self.frame1 = None
57 | self.line_edit1_1 = None # 窗口1的文件夹路径
58 | self.pdf_path = None # 窗口1的pdf路径
59 | self.push_button1_1 = QPushButton() # 按钮1_1,选择文件
60 | self.push_button1_2 = QPushButton() # 按钮1_2,pdf转png
61 | self.push_button1_3 = QPushButton() # 按钮1_3,我要退出
62 |
63 | # --窗口2
64 | self.frame2 = None
65 | self.line_edit2_1 = None # 输入框
66 | self.pdf_dir1 = None # pdf转成图片后的文件夹
67 | self.push_button2_1 = QPushButton() # 按钮2_1:自定义路径
68 | self.push_button2_2 = QPushButton() # 按钮2_2:一键长图
69 | self.push_button2_3 = QPushButton() # 按钮2_3:自定义拼接
70 |
71 | # --窗口3
72 | self.frame3 = None
73 | self.pdf_dir2 = None
74 | self.line_edit3_1 = None # 输入框
75 | self.combo_box3_1 = None # 多选框3_1
76 | self.combo_box3_2 = None # 多选框3_2
77 | self.line_edit3_2 = None # 输入框百分比
78 | self.push_button3_1 = QPushButton() # 自定义路径
79 | self.push_button3_2 = QPushButton() # 一键压缩
80 | self.push_button3_3 = QPushButton() # 退出软件
81 |
82 | # --- dialog会话 --
83 | self.dialog_line_edit1 = None # 会话输入框1:拼接数量
84 | self.dialog_line_edit2 = None # 会话输入框2:拼接列数
85 | self.dialog_line_edit3 = None # 会话输入框3:拼接行数
86 | self.dialog_line_edit4 = None # 会话输入框4:拼接间隙
87 | self.dialog_push_button1 = None # 会话按钮1:开始单列拼接
88 | self.dialog_push_button2 = None # 会话按钮1:开始矩阵拼接
89 | self.dialog1 = None # 单列拼接
90 | self.dialog2 = None # 矩阵拼接
91 |
92 | # --运行主界面--#
93 | self.init_ui()
94 |
95 | def init_ui(self):
96 | self.show_frame1()
97 | self.show()
98 |
99 | def show_frame1(self):
100 | self.frame1 = QWidget(self)
101 | super(QWidget, self.frame1).__init__()
102 | # --按钮标签1:格式转换,用来代替按钮1
103 | button_label1 = QLabel(self.frame1)
104 | button_label1.setGeometry(90, 0, 80, 24)
105 | button_label1.setFont(self.font_8)
106 | button_label1.setText('格式转换')
107 | button_label1.setAlignment(Qt.AlignCenter)
108 | # 转换按键
109 | # --按钮2:图片拼接
110 | push_button2 = QPushButton(self.frame1)
111 | push_button2.setGeometry(170, 0, 80, 24)
112 | push_button2.setFont(self.font_8)
113 | push_button2.setText('图片拼接')
114 | push_button2.clicked.connect(self.show_frame2) # 连接件显示窗口2
115 | # --按钮3:图片压缩
116 | push_button3 = QPushButton(self.frame1)
117 | push_button3.setGeometry(250, 0, 80, 24)
118 | push_button3.setFont(self.font_8)
119 | push_button3.setText('图片压缩')
120 | push_button3.clicked.connect(self.show_frame3) # 连接件显示窗口3
121 |
122 | # --标签1:pdf路径
123 | label1_1 = QLabel(self.frame1)
124 | label1_1.setText('pdf路径')
125 | label1_1.setFont(self.font_8)
126 | label1_1.setAlignment(Qt.AlignCenter)
127 | label1_1.setGeometry(15, 40, 69, 20)
128 |
129 | # --路径1:pdf路径
130 | self.line_edit1_1 = QLineEdit(self.frame1)
131 | self.line_edit1_1.setFont(self.font_8)
132 | self.line_edit1_1.setGeometry(90, 40, 220, 26)
133 | # 加入上次的路径保留
134 | pdf_path = self.read_data_dict('pdf_path')
135 | if pdf_path is not None:
136 | self.line_edit1_1.setText(pdf_path)
137 |
138 | # -- 按钮1_1:选择pdf文件
139 | self.push_button1_1 = QPushButton(self.frame1)
140 | self.push_button1_1.setGeometry(10, 95, 93, 29)
141 | self.push_button1_1.setText('选择文件')
142 | self.push_button1_1.setFont(self.font_9)
143 | # -- 按钮1_2:pdf转png
144 | self.push_button1_2 = QPushButton(self.frame1)
145 | self.push_button1_2.setGeometry(115, 95, 93, 29)
146 | self.push_button1_2.setText('pdf转png')
147 | self.push_button1_2.setFont(self.font_9)
148 | # -- 按钮1_3:我要退出
149 | self.push_button1_3 = QPushButton(self.frame1)
150 | self.push_button1_3.setGeometry(220, 95, 93, 29)
151 | self.push_button1_3.setText('退出软件')
152 | self.push_button1_3.setFont(self.font_9)
153 |
154 | # 移动其它控件
155 | self.menubar.setParent(self.frame1) # 设置菜单栏依赖于窗口1
156 | self.setCentralWidget(self.frame1) # 设置主窗口的当前窗口为窗口1
157 | self.frame1.setVisible(True)
158 |
159 | def show_frame2(self):
160 | # 重新定义构件
161 | self.frame2 = QWidget(self)
162 | super(QWidget, self.frame2).__init__()
163 | # --按钮1:格式转换
164 | push_button1 = QPushButton(self.frame2)
165 | push_button1.setGeometry(90, 0, 80, 24)
166 | push_button1.setFont(self.font_8)
167 | push_button1.setText('格式转换')
168 | push_button1.clicked.connect(self.show_frame1)
169 |
170 | # --按钮标签2:格式转换,用来代替按钮2
171 | button_label2 = QLabel(self.frame2) # 暂时不设置父标签
172 | button_label2.setGeometry(170, 0, 80, 24)
173 | button_label2.setFont(self.font_8)
174 | button_label2.setText('图片拼接')
175 | button_label2.setAlignment(Qt.AlignCenter)
176 | # --按钮3:图片压缩
177 | push_button3 = QPushButton(self.frame2)
178 | push_button3.setGeometry(250, 0, 80, 24)
179 | push_button3.setFont(self.font_8)
180 | push_button3.setText('图片压缩')
181 | push_button3.clicked.connect(self.show_frame3) # 连接件显示窗口3
182 |
183 | # -- 标签2_1:文件夹路径
184 | label2_1 = QLabel(self.frame2)
185 | label2_1.setGeometry(15, 40, 80, 20)
186 | label2_1.setText('文件夹路径')
187 | label2_1.setFont(self.font_8)
188 |
189 | # -- 输入框2_1:文件夹路径
190 | self.line_edit2_1 = QLineEdit(self.frame2)
191 | self.line_edit2_1.setGeometry(90, 40, 220, 26)
192 | self.line_edit2_1.setFont(self.font_8)
193 |
194 | # 加入默认路径
195 | pdf_path = self.read_data_dict('pdf_path')
196 | if pdf_path is not None:
197 | dir1 = path.split(pdf_path)[0]
198 | self.pdf_dir1 = dir1 + '/导出图片'
199 | self.line_edit2_1.setText(self.pdf_dir1)
200 |
201 | # -- 按钮2_1:自定义路径
202 | self.push_button2_1 = QPushButton(self.frame2)
203 | self.push_button2_1.setGeometry(10, 95, 93, 29)
204 | self.push_button2_1.setText('自定义路径')
205 | self.push_button2_1.setFont(self.font_9)
206 | # -- 按钮2_2:一键长图
207 | self.push_button2_2 = QPushButton(self.frame2)
208 | self.push_button2_2.setGeometry(115, 95, 93, 29)
209 | self.push_button2_2.setText('一键长图')
210 | self.push_button2_2.setFont(self.font_9)
211 | # -- 按钮2_3:自定义拼接
212 | self.push_button2_3 = QPushButton(self.frame2)
213 | self.push_button2_3.setGeometry(220, 95, 93, 29)
214 | self.push_button2_3.setText('自定义拼接')
215 | self.push_button2_3.setFont(self.font_9)
216 | self.push_button2_3.clicked.connect(self.show_dialog)
217 | # -- 移动其它控件
218 | self.menubar.setParent(self.frame2) # 设置菜单栏依赖于窗口2
219 | self.setCentralWidget(self.frame2)
220 | self.frame2.setVisible(True)
221 |
222 | def show_frame3(self):
223 | self.frame3 = QWidget(self)
224 | super(QWidget, self.frame3).__init__()
225 | # --按钮1:格式转换
226 | push_button1 = QPushButton(self.frame3)
227 | push_button1.setGeometry(90, 0, 80, 24)
228 | push_button1.setFont(self.font_8)
229 | push_button1.setText('格式转换')
230 | push_button1.clicked.connect(self.show_frame1)
231 |
232 | # --按钮2:图片拼接
233 | push_button2 = QPushButton(self.frame3)
234 | push_button2.setGeometry(170, 0, 80, 24)
235 | push_button2.setFont(self.font_8)
236 | push_button2.setText('图片拼接')
237 | push_button2.clicked.connect(self.show_frame2) # 连接件显示窗口2
238 | # -- 设置主窗口
239 | self.setCentralWidget(self.frame3)
240 |
241 | # -- 标签3:图片压缩
242 | button_label3 = QLabel(self.frame3)
243 | button_label3.setGeometry(250, 0, 80, 24)
244 | button_label3.setFont(self.font_8)
245 | button_label3.setText('图片压缩')
246 | button_label3.setAlignment(Qt.AlignCenter)
247 | # -- 标签3_1:文件夹路径
248 | label3_1 = QLabel(self.frame3)
249 | label3_1.setGeometry(15, 40, 80, 20)
250 | label3_1.setText('文件夹路径')
251 | label3_1.setFont(self.font_8)
252 | # -- 输入框3_1:文件夹路径
253 | self.line_edit3_1 = QLineEdit(self.frame3)
254 | self.line_edit3_1.setFont(self.font_8)
255 | self.line_edit3_1.setGeometry(90, 40, 220, 26)
256 | # 加入默认路径
257 | pdf_path = self.read_data_dict('pdf_path')
258 | if pdf_path is not None:
259 | dir1 = path.split(pdf_path)[0]
260 | self.pdf_dir2 = dir1 + '/单列长图'
261 | self.line_edit3_1.setText(self.pdf_dir2)
262 | # -- 标签3_2:宽度
263 | label3_2 = QLabel(self.frame3)
264 | label3_2.setGeometry(10, 80, 35, 20)
265 | label3_2.setText('宽度')
266 | label3_2.setFont(self.font_8)
267 | # -- 多选框3_1
268 | self.combo_box3_1 = QComboBox(self.frame3)
269 | self.combo_box3_1.setGeometry(45, 80, 60, 25)
270 | self.combo_box3_1.addItems(['普通', '720p', '1080p'])
271 | self.combo_box3_1.setFont(self.font_8)
272 | # -- 多选框3_2
273 | self.combo_box3_2 = QComboBox(self.frame3)
274 | self.combo_box3_2.setGeometry(155, 80, 50, 25)
275 | self.combo_box3_2.addItems(['jpg', 'png'])
276 | self.combo_box3_2.setFont(self.font_8)
277 | # -- 标签3_3
278 | label3_3 = QLabel(self.frame3)
279 | label3_3.setGeometry(120, 80, 40, 20)
280 | label3_3.setText('格式')
281 | label3_3.setFont(self.font_8)
282 | # -- 标签3_4
283 | label3_4 = QLabel(self.frame3)
284 | label3_4.setGeometry(220, 80, 51, 20)
285 | label3_4.setText('压缩比')
286 | label3_4.setFont(self.font_8)
287 | # -- 输入框3_2:压缩百分比
288 | self.line_edit3_2 = QLineEdit(self.frame3)
289 | self.line_edit3_2.setGeometry(265, 80, 25, 25)
290 | self.line_edit3_2.setFont(self.font_8)
291 | # -- 标签3_5
292 | label3_4 = QLabel(self.frame3)
293 | label3_4.setGeometry(295, 80, 14, 20)
294 | label3_4.setText('%')
295 | label3_4.setFont(self.font_8)
296 | # -- 按键3_1:自定义路径
297 | self.push_button3_1 = QPushButton(self.frame3)
298 | self.push_button3_1.setGeometry(10, 115, 93, 29)
299 | self.push_button3_1.setText('自定义路径')
300 | self.push_button3_1.setFont(self.font_9)
301 | # -- 按键3_2:一键压缩
302 | self.push_button3_2 = QPushButton(self.frame3)
303 | self.push_button3_2.setGeometry(115, 115, 93, 29)
304 | self.push_button3_2.setText('一键压缩')
305 | self.push_button3_2.setFont(self.font_9)
306 | # -- 按键3_3:退出软件
307 | self.push_button3_3 = QPushButton(self.frame3)
308 | self.push_button3_3.setGeometry(220, 115, 93, 29)
309 | self.push_button3_3.setText('我要退出')
310 | self.push_button3_3.setFont(self.font_9)
311 | # -- 设置其它依赖转移过来
312 | self.menubar.setParent(self.frame3) # 设置菜单栏依赖于窗口3
313 | self.frame3.setVisible(True)
314 |
315 | def show_dialog(self):
316 | self.show_dialog1()
317 |
318 | def show_dialog1(self):
319 | if self.dialog2 is not None:
320 | self.dialog2.close()
321 | self.dialog1 = QDialog(self)
322 | self.dialog1.resize(340, 150)
323 | self.dialog1.setMinimumSize(340, 150)
324 | self.dialog1.setMaximumSize(340, 150)
325 | self.dialog1.setWindowIcon(QIcon('tools.png'))
326 | self.dialog1.setWindowTitle('自定义拼接')
327 | self.dialog1.setFont(self.font_8)
328 |
329 | # -- 设置标签1---
330 | label1 = QLabel(self.dialog1)
331 | label1.setGeometry(40, 10, 70, 29)
332 | label1.setText('单列拼接')
333 | label1.setAlignment(Qt.AlignCenter)
334 | # -- 设置按键2 ---
335 | push_button2 = QPushButton(self.dialog1)
336 | push_button2.setGeometry(40, 70, 70, 29)
337 | push_button2.setText('矩阵拼接')
338 | push_button2.clicked.connect(self.show_dialog2)
339 |
340 | # -- 标签2:拼接数量
341 | label2 = QLabel(self.dialog1)
342 | label2.setText('拼接数量')
343 | label2.setGeometry(150, 20, 51, 20)
344 |
345 | # -- 输入框:单列拼接数量
346 | self.dialog_line_edit1 = QLineEdit(self.dialog1)
347 | self.dialog_line_edit1.setGeometry(210, 20, 30, 20)
348 | self.dialog_push_button1 = QPushButton(self.dialog1)
349 | self.dialog_push_button1.setGeometry(150, 60, 93, 25)
350 | self.dialog_push_button1.setText('开始单列拼接')
351 |
352 | def show_dialog2(self):
353 | if self.dialog1 is not None:
354 | self.dialog1.close() # 关闭会话1
355 | self.dialog2 = QDialog(self)
356 | self.dialog2.resize(340, 150)
357 | self.dialog2.setFont(self.font_8)
358 | self.dialog2.setMinimumSize(340, 150)
359 | self.dialog2.setMaximumSize(340, 150)
360 | self.dialog2.setWindowIcon(QIcon('tools.png'))
361 | self.dialog2.setWindowTitle('矩阵拼接')
362 | # -- 设置按键1---
363 | push_button1 = QPushButton(self.dialog2)
364 | push_button1.setGeometry(40, 10, 70, 29)
365 | push_button1.setText('单列拼接')
366 | push_button1.clicked.connect(self.show_dialog1)
367 |
368 | # -- 设置标签2---
369 | label1 = QLabel(self.dialog2)
370 | label1.setGeometry(40, 70, 70, 29)
371 | label1.setText('矩阵拼接')
372 | label1.setAlignment(Qt.AlignCenter)
373 |
374 | # -- 标签2:拼接列数
375 | label2 = QLabel(self.dialog2)
376 | label2.setText('拼接行数')
377 | label2.setGeometry(160, 20, 51, 20)
378 | # -- 标签3:拼接行数
379 | label3 = QLabel(self.dialog2)
380 | label3.setText('拼接列数')
381 | label3.setGeometry(160, 45, 51, 20)
382 | # -- 标签4:拼接行数
383 | label4 = QLabel(self.dialog2)
384 | label4.setText('拼接间隙')
385 | label4.setGeometry(160, 70, 51, 20)
386 |
387 | # -- 标签5:行数
388 | label4 = QLabel(self.dialog2)
389 | label4.setText('行')
390 | label4.setGeometry(260, 20, 41, 20)
391 |
392 | # -- 标签6:列数
393 | label4 = QLabel(self.dialog2)
394 | label4.setText('列')
395 | label4.setGeometry(260, 50, 41, 20)
396 |
397 | # -- 标签7:px像素
398 | label4 = QLabel(self.dialog2)
399 | label4.setText('px')
400 | label4.setGeometry(260, 70, 41, 20)
401 |
402 | # -- 输入框:拼接列数
403 | self.dialog_line_edit2 = QLineEdit(self.dialog2)
404 | self.dialog_line_edit2.setGeometry(220, 20, 30, 20)
405 | # -- 输入框:拼接行数
406 | self.dialog_line_edit3 = QLineEdit(self.dialog2)
407 | self.dialog_line_edit3.setGeometry(220, 45, 30, 20)
408 | # -- 输入框:拼接间隙
409 | self.dialog_line_edit4 = QLineEdit(self.dialog2)
410 | self.dialog_line_edit4.setGeometry(220, 70, 30, 20)
411 |
412 | self.dialog_push_button2 = QPushButton(self.dialog2)
413 | self.dialog_push_button2.setGeometry(160, 100, 93, 25)
414 | self.dialog_push_button2.setText('开始矩阵拼接')
415 |
416 | def notice_dialog(self):
417 | dialog = QDialog(self)
418 | dialog.resize(500, 450)
419 | dialog.setMinimumSize(340, 150)
420 | text = """\
421 | 使用说明:
422 | 主要功能有格式转换、图片拼接,图片压缩三项
423 | 格式转换:目前只支持pdf转png
424 | 图片拼接:
425 | 1.支持自定义拼接路径。
426 | 2.默认路径是你转成png图片后的路径。
427 | 3.可以设置为一键拼接成一张长图。
428 | 4.自定义拼接还可以按单列拼成长图,或者按矩阵进行拼接。
429 | 5.单列拼接指的是按多张图拼接成一张图,比如15张图,
430 | 可以按5张图拼成一张长图,这样就获得了3张长图。
431 | 6.矩阵拼接类似微信的九宫格,比如3行三列为一张长图,
432 | 中间可以设置10像素的间隙,然后可以获得多张这样的长图。
433 | 7.矩阵拼接兼容单列拼接,即列为1,间隙为0时即为矩阵拼接。
434 | 图片压缩:
435 | 1.关于宽度
436 | 普通模式即自动压缩成1M以内,
437 | 720p和1080p则自动压缩图片为这个宽度
438 | 2.关于格式
439 | 即压缩后图片的格式是jpg还是png
440 | 3.关于压缩比
441 | 即压缩成jpg格式时,图片的质量百分比。
442 | """
443 | dialog.setWindowTitle('使用说明')
444 | label = QLabel(text, dialog)
445 | label.setFont(self.font_9)
446 | dialog.show()
447 |
448 | def update_dialog(self):
449 | """
450 | 更新记录
451 | """
452 | dialog = QDialog(self)
453 | dialog.resize(500, 450)
454 | dialog.setMinimumSize(340, 150)
455 | text = """\
456 | V1.1版更新记录:
457 | 1.增加窗口抽屉功能,将图片转换、图片拼接、图片压缩功能拆分。
458 | 2.增加更多自定义功能,可以自定义图片文件夹来源,
459 | 还可以自定义拼接方式了。
460 | 3.优化了压缩图片算法的一个小bug,增加了压缩图片的最终格式自定义,
461 | 可以选择压缩为jpg或者png。
462 | 4.自定义拼接中,单列拼接与矩阵拼接多了一个翻转的过度动画。
463 | 5.加入操作历史记录保留,自动保留上次的操作的方式
464 | 注意,只会保留你的最后一次转图片、拼接图片、压缩图片的记录,
465 | 选择文件的记录不在此列
466 | 6.导出路径更改为与原pdf路径同级
467 | 7.导出图片时自动删除上次导出的图片
468 | 7.其他更新请阅读使用说明
469 |
470 | V1.0版更新记录:
471 | 1.使用PyQt5重构了界面
472 | 2.增加了进度条,减少等待时间
473 | 3.选择pdf文件时,默认上次的路径
474 | 4.增加了二次确认操作
475 | 5.使用多线程,提高了软件速度
476 | 6.美化了GUI,变得好看了
477 | """
478 |
479 | dialog.setWindowTitle('更新记录')
480 | label = QLabel(text, dialog)
481 | label.setFont(self.font_9)
482 | dialog.show()
483 |
484 | def feedback_dialog(self):
485 | """
486 | 我要反馈
487 | """
488 | dialog = QDialog(self)
489 | dialog.resize(500, 50)
490 | dialog.setMinimumSize(340, 150)
491 | text = """\
492 | qq群:974759263
493 | """
494 |
495 | dialog.setWindowTitle('我要反馈')
496 | label = QLabel(text, dialog)
497 | label.setFont(self.font_9)
498 | dialog.show()
499 |
500 | def about_dialog(self):
501 | dialog = QDialog(self)
502 | dialog.resize(500, 50)
503 | dialog.setMinimumSize(340, 150)
504 | text = """\
505 | 版本号:V1.1
506 | 编译日期:2020年6月3日
507 | """
508 | dialog.setWindowTitle('关于')
509 | label = QLabel(text, dialog)
510 | label.setFont(self.font_9)
511 | dialog.show()
512 |
513 | # 公用读取字典
514 | @staticmethod
515 | def read_data_dict(key, data_path='./data.json'):
516 | """
517 | 根据索引读取data.json的内容
518 | :param key: 索引
519 | :param data_path: json所在路径
520 | :return: data:读取到的值
521 | """
522 | with open(data_path, 'rt', encoding='utf-8') as f1:
523 | data_dict1 = json.load(f1)
524 | data = data_dict1.get(key, None) # 没有内容则为None
525 | return data
526 |
527 | # 公用写入字典
528 | @staticmethod
529 | def write_data_dict(key, value2, data_path='./data.json'):
530 | """
531 | 根据索引读取data.json的内容
532 | :param key: 写入键
533 | :return: value2:写入值
534 | :param data_path: json所在路径
535 | """
536 | f1 = open(data_path, 'rt', encoding='utf-8')
537 | data_dict1 = json.load(f1)
538 | f1.close()
539 | with open(data_path, 'wt', encoding='utf-8') as f2:
540 | data_dict1[key] = value2
541 | json.dump(data_dict1, f2)
542 |
543 |
544 | if __name__ == '__main__':
545 | # 创建一个data.json文件,用于储存变量参数
546 | if not path.exists('data.json'):
547 | data_dict = {}
548 | with open('data.json', 'wt', encoding='utf-8') as f:
549 | json.dump(data_dict, f)
550 | app = QApplication(sys.argv)
551 | ui = UI()
552 | sys.exit(app.exec_())
553 |
554 |
555 |
--------------------------------------------------------------------------------