吾爱破解 - 52pojie.cn

 找回密码
 注册[Register]

QQ登录

只需一步,快速开始

查看: 616|回复: 25
上一主题 下一主题
收起左侧

[Python 原创] 图片批量转PDF工具-源码

  [复制链接]
跳转到指定楼层
楼主
killerzeno 发表于 2025-3-28 13:03 回帖奖励


[Python] 纯文本查看 复制代码
001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
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
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
import os
import sys
from tkinter import Tk, Label, Button, Listbox, Checkbutton, IntVar, filedialog, messagebox, ttk
from tkinter import END, LEFT, RIGHT, BOTH, X, Y, W, E, TOP
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from PIL import Image
 
class ImageToPDFConverter:
    def __init__(self, root):
        self.root = root
        self.root.title('图片批量转PDF工具-By:Killerzeno')
        self.root.geometry('800x700')
 
 
        def resource_path(relative_path):
            try:
                base_path = sys._MEIPASS  # 打包后资源文件的临时目录
            except Exception:
                base_path = os.path.abspath("."# 开发环境下的当前目录
            return os.path.join(base_path, relative_path)
 
        # 修改设置窗口图标代码
        try:
            self.root.iconbitmap(resource_path('logo.ico'))  # 使用 resource_path 函数获取图标路径
        except Exception as e:
            messagebox.showwarning('警告', f'无法加载图标文件 logo.ico: {str(e)}')
 
 
 
        # 标题
        title_label = Label(self.root, text='图片批量转PDF工具', font=('Arial', 30, 'bold'), fg='green')
        title_label.pack(pady=10)
 
        # 说明标签
        info_label = Label(self.root, text='点击"添加图片"按钮选择图片文件', font=('Arial', 12))
        info_label.pack(pady=5)
 
        # 图片列表
        self.listbox = Listbox(self.root, selectmode='extended', height=20, width=100)
        self.listbox.pack(pady=10, padx=10, fill=BOTH, expand=True)
 
        # 按钮区域
        buttons_frame = ttk.Frame(self.root)
        buttons_frame.pack(fill=X, padx=10, pady=5)
 
        add_button = Button(buttons_frame, text='添加图片', command=self.add_images)
        add_button.pack(side=LEFT, padx=10)
 
        remove_button = Button(buttons_frame, text='移除选中', command=self.remove_selected)
        remove_button.pack(side=LEFT, padx=10)
 
        clear_button = Button(buttons_frame, text='清空列表', command=self.clear_list)
        clear_button.pack(side=LEFT, padx=10)
 
        # 上移和下移按钮
        move_up_button = Button(buttons_frame, text='上移图片', command=self.move_up)
        move_up_button.pack(side=LEFT, padx=10)
 
        move_down_button = Button(buttons_frame, text='下移图片', command=self.move_down)
        move_down_button.pack(side=LEFT, padx=10)
 
        # 选项区域
        options_frame = ttk.Frame(self.root)
        options_frame.pack(fill=X, padx=10, pady=5)
 
        self.single_pdf_var = IntVar(value=1)
        self.multi_pdf_var = IntVar()
        self.keep_original_size_var = IntVar()  # 新增变量,用于是否保留原始尺寸
 
        single_pdf_check = Checkbutton(options_frame, text='所有图片合并为一个PDF', variable=self.single_pdf_var,
                                       command=lambda: self.toggle_checkboxes(self.single_pdf_var, self.multi_pdf_var))
        single_pdf_check.pack(side=LEFT, padx=10)
 
        multi_pdf_check = Checkbutton(options_frame, text='每张图片生成单独PDF', variable=self.multi_pdf_var,
                                      command=lambda: self.toggle_checkboxes(self.multi_pdf_var, self.single_pdf_var))
        multi_pdf_check.pack(side=LEFT, padx=10)
 
        # 新增选项:是否保留原始尺寸
        keep_original_size_check = Checkbutton(options_frame, text='保留原始尺寸', variable=self.keep_original_size_var)
        keep_original_size_check.pack(side=LEFT, padx=10)
 
        # 转换按钮
        convert_button = Button(self.root, text='转换为PDF', bg='#4CAF50', fg='white', command=self.convert_to_pdf)
        convert_button.pack(fill=X, padx=10, pady=10)
 
        # 进度条
        self.progress = ttk.Progressbar(self.root, orient='horizontal', length=200, mode='determinate')
        self.progress.pack(pady=10)
 
    def toggle_checkboxes(self, selected_var, other_var):
        if selected_var.get() == 1:
            other_var.set(0)
 
    def add_images(self):
        files = filedialog.askopenfilenames(filetypes=[('图片文件', '*.jpg *.jpeg *.png *.bmp *.gif *.tiff')])
        for file in files:
            if self.is_image_file(file):
                self.listbox.insert(END, file)
 
    def remove_selected(self):
        selected_items = self.listbox.curselection()
        for item in selected_items[::-1]:  # 从后往前删除,避免索引变化
            self.listbox.delete(item)
 
    def clear_list(self):
        self.listbox.delete(0, END)
 
    def is_image_file(self, file_path):
        image_extensions = ['.jpg', '.jpeg', '.png', '.bmp', '.gif', '.tiff']
        return os.path.isfile(file_path) and os.path.splitext(file_path)[1].lower() in image_extensions
 
    def move_up(self):
        selected_items = self.listbox.curselection()
        for item in selected_items:
            if item > 0:
                self.listbox.insert(item - 1, self.listbox.get(item))
                self.listbox.delete(item + 1)
                self.listbox.selection_set(item - 1)
 
    def move_down(self):
        selected_items = self.listbox.curselection()
        for item in selected_items[::-1]:  # 从后往前处理
            if item < self.listbox.size() - 1:
                self.listbox.insert(item + 2, self.listbox.get(item))
                self.listbox.delete(item)
                self.listbox.selection_set(item + 1)
 
    def convert_to_pdf(self):
        if self.listbox.size() == 0:
            messagebox.showwarning('警告', '没有可转换的图片文件!')
            return
 
        output_dir = filedialog.askdirectory()
        if not output_dir:
            return
 
        try:
            if self.single_pdf_var.get():
                output_path = os.path.join(output_dir, 'combined.pdf')
                c = canvas.Canvas(output_path, pagesize=letter)
                for i in range(self.listbox.size()):
                    img_path = self.listbox.get(i)
                    self.add_image_to_pdf(c, img_path)
                    self.update_progress(i + 1, self.listbox.size())
                c.save()
                messagebox.showinfo('完成', f'已生成合并PDF文件: {output_path}')
            else:
                for i in range(self.listbox.size()):
                    img_path = self.listbox.get(i)
                    filename = os.path.splitext(os.path.basename(img_path))[0]
                    output_path = os.path.join(output_dir, f'{filename}.pdf')
                    c = canvas.Canvas(output_path, pagesize=letter)
                    self.add_image_to_pdf(c, img_path)
                    c.save()
                    self.update_progress(i + 1, self.listbox.size())
                messagebox.showinfo('完成', f'已生成{self.listbox.size()}个PDF文件到目录: {output_dir}')
        except Exception as e:
            messagebox.showerror('错误', f'转换过程中发生错误: {str(e)}')
 
    def add_image_to_pdf(self, c, img_path):
        try:
            img = Image.open(img_path)
            img_width, img_height = img.size
 
            if self.keep_original_size_var.get():  # 如果选择保留原始尺寸
                # 设置PDF页面大小为图片的原始尺寸
                c.setPageSize((img_width, img_height))
                # 在PDF页面上绘制图片
                c.drawImage(img_path, 0, 0, width=img_width, height=img_height)
            else# 否则自动调整大小以适应PDF页面
                pdf_width, pdf_height = letter
                width_ratio = pdf_width / img_width
                height_ratio = pdf_height / img_height
                scale = min(width_ratio, height_ratio)
 
                x = (pdf_width - img_width * scale) / 2
                y = (pdf_height - img_height * scale) / 2
 
                c.drawImage(img_path, x, y, width=img_width * scale, height=img_height * scale)
 
            c.showPage()
        except Exception as e:
            raise Exception(f'处理图片 {os.path.basename(img_path)} 时出错: {str(e)}')
 
    def update_progress(self, value, max_value):
        self.progress['value'] = (value / max_value) * 100
        self.root.update_idletasks()
 
if __name__ == '__main__':
    root = Tk()
    app = ImageToPDFConverter(root)
    root.mainloop()

免费评分

参与人数 7吾爱币 +10 热心值 +7 收起 理由
usevpn + 1 + 1 谢谢@Thanks!
苏紫方璇 + 7 + 1 欢迎分析讨论交流,吾爱破解论坛有你更精彩!
ironDuck + 1 + 1 nice
a19900531 + 1 我很赞同!
kelly4crack + 1 谢谢@Thanks!
shengruqing + 1 我很赞同!
stone12315 + 1 + 1 感谢发布原创作品,吾爱破解论坛因你更精彩!

查看全部评分

本帖被以下淘专辑推荐:

发帖前要善用论坛搜索功能,那里可能会有你要找的答案或者已经有人发布过相同内容了,请勿重复发帖。

推荐
manglang 发表于 2025-3-28 13:41
代码按指定文件名存储数据,这样的缺点就是每一个输出文件都会覆盖前面生成的文件。
将文件名改成当前日期加时间,这样就不会重复了:

[Python] 纯文本查看 复制代码
1
2
3
4
5
6
7
8
import os
from datetime import datetime
 
# 生成时间戳(格式示例:2023-10-05_15-30-45)
timestamp = datetime.now().strftime("%Y-%m-%d_%H-%M-%S")
 
# 动态生成带时间戳的文件名
output_path = os.path.join(output_dir, f'合并结果_{timestamp}.pdf')
沙发
SaulZane 发表于 2025-3-28 13:24
3#
xinbill2111 发表于 2025-3-28 13:30
5#
shsww 发表于 2025-3-28 13:52
感谢分享!!!         
6#
stone12315 发表于 2025-3-28 14:18
收藏一下,之前都是搜索在线的工具临时用下
7#
otho 发表于 2025-3-28 14:31
下载出来试试!感谢楼主分享
8#
jidesheng6 发表于 2025-3-28 15:04
manglang 发表于 2025-3-28 13:41
代码按指定文件名存储数据,这样的缺点就是每一个输出文件都会覆盖前面生成的文件。
将文件名改成当前日期 ...

其实重不重名根本不重要了,如果这个文件你需要重新生成,最好的办法就是直接覆盖,加了时间戳,大多数人根本分不太清哪个是哪个,程序需要二次转换就说明前一次生成的文件是不符合自己要求的
9#
binghe01 发表于 2025-3-28 15:26
感谢楼主的分享,感谢感谢,学到了
10#
kelly4crack 发表于 2025-3-28 15:30
我也搞了一个,想做成支持命令行模式,支持右键调用一键操作。但测试总是不理想,老哥这个能增加吗
您需要登录后才可以回帖 登录 | 注册[Register]

本版积分规则

返回列表

RSS订阅|小黑屋|处罚记录|联系我们|吾爱破解 - LCG - LSG ( 京ICP备16042023号 | 京公网安备 11010502030087号 )

GMT+8, 2025-4-3 02:01

Powered by Discuz!

Copyright © 2001-2020, Tencent Cloud.

快速回复 返回顶部 返回列表