PDF转图片工具

背景:

今天有个朋友找我:"我有个文件需要更改,但是文档是PDF的,需要你帮我改下内容,你是搞软件的,这个对你应该是轻车熟路了吧,帮我弄弄吧",听到这话我本想反驳,我是开发不是美工,然后跟他科普科普两者的分工和区别。后来想想还是算了,隔行如隔山,讲了可能也是白讲。干脆给他干了得了。毕竟这种类似"程序员=修电脑的"印象在亲戚朋友中早已广为流传。

起因:

一开始觉得做这个工作很简单,打开WPS,直接按他的要求编辑下就算完成就可以的,可当我打开文档编辑的时候:

呵呵,这特么干个免费的活,感情还要自己掏腰包?

于是,一个想法冒出来了,把文档转成图片,再用PS改得了,于是我又尝试转换成图片

挣扎:

我了个擦,要点脸不,也不知道啥时候起金山也养成了企鹅家的作风。于是我想想既然是帮人干活,这个钱怎么也不至于我掏吧,对,让他掏!!可话又说回来,就这么点屁事,让人花几十上百也是有点坑。

既然WPS处处要花钱,那就不用了,自己写一个不就OK

python 复制代码
import fitz
import os
from PIL import Image
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter


def pdf_to_images(pdf_path, zoom_x=2.0, zoom_y=2.0):
    # 创建输出文件夹
    pdf_dir = os.path.dirname(pdf_path)
    sub_folder = os.path.basename(pdf_path).split(".")[0]
    output_folder = '{}/{}/imgs'.format(pdf_dir, sub_folder)
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)

    # 打开PDF文件
    pdf_document = fitz.open(pdf_path)
    for page_num in range(len(pdf_document)):
        # 获取页面
        page = pdf_document.load_page(page_num)
        # 设置变换矩阵以增加图像分辨率
        mat = fitz.Matrix(zoom_x, zoom_y)
        # 转换页面为图像
        pix = page.get_pixmap(matrix=mat)
        # 保存图像
        output_image_path = os.path.join(output_folder, f'page_{page_num + 1}.png')
        pix.save(output_image_path)

    print(f"PDF {pdf_path} 已成功转换为图像,并保存到文件夹 {output_folder}")


def images_to_pdf(images_folder, output_pdf_path):
    # 获取所有图片文件
    image_files = [f for f in os.listdir(images_folder) if f.endswith(('png', 'jpg', 'jpeg'))]
    image_files.sort()  # 按名称排序,确保顺序正确

    if not image_files:
        print("没有找到图片文件。")
        return

    # 创建一个空白的 PDF 文件
    c = canvas.Canvas(output_pdf_path, pagesize=letter)

    for image_file in image_files:
        image_path = os.path.join(images_folder, image_file)
        # 打开图片并获取其尺寸
        with Image.open(image_path) as img:
            img_width, img_height = img.size
            # 将图片按比例缩放以适应页面
            page_width, page_height = letter
            scale = min(page_width / img_width, page_height / img_height)
            img_width *= scale
            img_height *= scale
            # 将图片绘制到 PDF 页面上
            c.drawImage(image_path, 0, page_height - img_height, width=img_width, height=img_height)
            c.showPage()  # 开始一个新页面

    c.save()
    print(f"图片已成功合并为 PDF 文件:{output_pdf_path}")


if __name__ == "__main__":
    # 输入 PDF 文档路径
    # pdf_path = input("请输入 PDF 文档的路径:")
    # pdf_to_images(pdf_path)
    images_folder = r'E:\PDF_PROJECT\马赛克\images_output'  # 图片文件夹路径
    output_pdf_path = r'E:\PDF_PROJECT\马赛克\马赛克.pdf'  # 输出PDF文件路径
    images_to_pdf(images_folder, output_pdf_path)

转成图片修改好以后,再给合回去,60+行代码换了100多的会员,头一次感受到了原来技术也不是一文不值,O(∩_∩)O哈哈~!

输出:

完事后,想想这个东西既然花了时间写出来,干脆加个界面,打包成程序提供给有需要的人用,岂不是更能发挥它的价值?

说干就干:

python 复制代码
import os
import fitz
import tkinter as tk
from tkinter import ttk, filedialog, messagebox
from PIL import Image
from reportlab.pdfgen import canvas
from reportlab.lib.pagesizes import letter
from datetime import datetime


class PDFImageConverterApp(tk.Tk):
    def __init__(self):
        super().__init__()
        self.title("PDF-图片 转换工具")
        self.geometry("650x500")
        self.create_widgets()

    def create_widgets(self):
        self.tabControl = ttk.Notebook(self)
        self.pdf_to_img_tab = ttk.Frame(self.tabControl)
        self.img_to_pdf_tab = ttk.Frame(self.tabControl)

        self.tabControl.add(self.pdf_to_img_tab, text="PDF转图片")
        self.tabControl.add(self.img_to_pdf_tab, text="图片转PDF")

        self.create_pdf_to_img_widgets()
        self.create_img_to_pdf_widgets()

        self.tabControl.pack(expand=1, fill="both")

    def create_pdf_to_img_widgets(self):
        ttk.Label(self.pdf_to_img_tab, text="请选择PDF文件路径:").grid(column=0, row=0, padx=10, pady=10)
        self.pdf_path = tk.StringVar()
        ttk.Entry(self.pdf_to_img_tab, width=50, textvariable=self.pdf_path).grid(column=1, row=0, padx=10, pady=10)
        ttk.Button(self.pdf_to_img_tab, text="Browse", command=self.browse_pdf).grid(column=2, row=0, padx=10, pady=10)

        ttk.Label(self.pdf_to_img_tab, text="请选择图片输出目录:").grid(column=0, row=1, padx=10, pady=10)
        self.img_output_folder = tk.StringVar()
        ttk.Entry(self.pdf_to_img_tab, width=50, textvariable=self.img_output_folder).grid(column=1, row=1, padx=10,
                                                                                           pady=10)
        ttk.Button(self.pdf_to_img_tab, text="Browse", command=self.browse_img_output_folder).grid(column=2, row=1,
                                                                                                   padx=10, pady=10)

        ttk.Label(self.pdf_to_img_tab, text="图片质量:").grid(column=0, row=2, padx=10, pady=10)
        self.img_quality = tk.StringVar(value="标清")
        ttk.Combobox(self.pdf_to_img_tab, textvariable=self.img_quality, values=["标清", "高清", "超清"]).grid(
            column=1, row=2, padx=10, pady=10)

        self.pdf_to_img_progress = ttk.Progressbar(self.pdf_to_img_tab, orient="horizontal", length=400,
                                                   mode="determinate")
        self.pdf_to_img_progress.grid(column=0, row=3, columnspan=3, padx=10, pady=10)

        self.pdf_to_img_log = tk.Text(self.pdf_to_img_tab, height=10, width=70)
        self.pdf_to_img_log.grid(column=0, row=4, columnspan=3, padx=10, pady=10)

        ttk.Button(self.pdf_to_img_tab, text="转换", command=self.convert_pdf_to_images).grid(column=0, row=5,
                                                                                            columnspan=3, padx=10,
                                                                                            pady=10)

    def create_img_to_pdf_widgets(self):
        ttk.Label(self.img_to_pdf_tab, text="请选择图片目录:").grid(column=0, row=0, padx=10, pady=10)
        self.images_folder = tk.StringVar()
        ttk.Entry(self.img_to_pdf_tab, width=50, textvariable=self.images_folder).grid(column=1, row=0, padx=10,
                                                                                       pady=10)
        ttk.Button(self.img_to_pdf_tab, text="Browse", command=self.browse_images_folder).grid(column=2, row=0, padx=10,
                                                                                               pady=10)

        ttk.Label(self.img_to_pdf_tab, text="请选择PDF输出目录:").grid(column=0, row=1, padx=10, pady=10)
        self.pdf_output_path = tk.StringVar()
        ttk.Entry(self.img_to_pdf_tab, width=50, textvariable=self.pdf_output_path).grid(column=1, row=1, padx=10,
                                                                                         pady=10)
        ttk.Button(self.img_to_pdf_tab, text="Browse", command=self.browse_pdf_output_path).grid(column=2, row=1,
                                                                                                 padx=10, pady=10)

        self.img_to_pdf_progress = ttk.Progressbar(self.img_to_pdf_tab, orient="horizontal", length=400,
                                                   mode="determinate")
        self.img_to_pdf_progress.grid(column=0, row=2, columnspan=3, padx=10, pady=10)

        self.img_to_pdf_log = tk.Text(self.img_to_pdf_tab, height=10, width=70)
        self.img_to_pdf_log.grid(column=0, row=3, columnspan=3, padx=10, pady=10)

        ttk.Button(self.img_to_pdf_tab, text="转换", command=self.convert_images_to_pdf).grid(column=0, row=4,
                                                                                            columnspan=3, padx=10,
                                                                                            pady=10)

    def browse_pdf(self):
        file_path = filedialog.askopenfilename(filetypes=[("PDF files", "*.pdf")])
        if file_path:
            self.pdf_path.set(file_path)

    def browse_img_output_folder(self):
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.img_output_folder.set(folder_path)

    def browse_images_folder(self):
        folder_path = filedialog.askdirectory()
        if folder_path:
            self.images_folder.set(folder_path)

    def browse_pdf_output_path(self):
        file_folder = filedialog.askdirectory()
        if file_folder:
            timestamp = datetime.now().strftime("%y-%m-%d_%H%M%S")
            output_pdf_path = os.path.join(file_folder, f"output_{timestamp}.pdf")
            self.pdf_output_path.set(output_pdf_path)

    def log_message(self, log_widget, message):
        log_widget.insert(tk.END, message + "\n")
        log_widget.see(tk.END)

    def convert_pdf_to_images(self):
        pdf_path = self.pdf_path.get()
        output_folder = self.img_output_folder.get()
        quality = self.img_quality.get()

        if not pdf_path or not output_folder or not quality:
            messagebox.showwarning("Warning", "请选择所有输入项.")
            return

        zoom_x, zoom_y = 1.0, 1.0
        if quality == "高清":
            zoom_x, zoom_y = 2.0, 2.0
        elif quality == "超清":
            zoom_x, zoom_y = 3.0, 3.0

        self.pdf_to_img_progress['value'] = 0
        self.update()

        pdf_document = fitz.open(pdf_path)
        total_pages = len(pdf_document)
        for page_num in range(total_pages):
            page = pdf_document.load_page(page_num)
            mat = fitz.Matrix(zoom_x, zoom_y)
            pix = page.get_pixmap(matrix=mat)
            output_image_path = os.path.join(output_folder, f'page_{page_num + 1}.png')
            pix.save(output_image_path)
            self.pdf_to_img_progress['value'] = (page_num + 1) / total_pages * 100
            self.log_message(self.pdf_to_img_log, f"Page {page_num + 1}/{total_pages} converted.")
            self.update()

        messagebox.showinfo("Info", "图片输出完成.")

    def convert_images_to_pdf(self):
        images_folder = self.images_folder.get()
        output_pdf_path = self.pdf_output_path.get()

        if not images_folder or not output_pdf_path:
            messagebox.showwarning("Warning", "请选择所有输入项.")
            return

        self.img_to_pdf_progress['value'] = 0
        self.update()

        image_files = [f for f in os.listdir(images_folder) if f.endswith(('png', 'jpg', 'jpeg'))]
        image_files.sort()
        total_images = len(image_files)

        if not image_files:
            messagebox.showwarning("Warning", "该文件夹下没有图片,请重新选择!")
            return

        c = canvas.Canvas(output_pdf_path, pagesize=letter)
        for idx, image_file in enumerate(image_files):
            image_path = os.path.join(images_folder, image_file)
            with Image.open(image_path) as img:
                img_width, img_height = img.size
                page_width, page_height = letter
                scale = min(page_width / img_width, page_height / img_height)
                img_width *= scale
                img_height *= scale
                c.drawImage(image_path, 0, page_height - img_height, width=img_width, height=img_height)
                c.showPage()
                self.img_to_pdf_progress['value'] = (idx + 1) / total_images * 100
                self.log_message(self.img_to_pdf_log, f"Image {idx + 1}/{total_images} added to PDF.")
                self.update()

        c.save()
        messagebox.showinfo("Info", "PDF转换完成!")


if __name__ == "__main__":
    app = PDFImageConverterApp()
    app.mainloop()
打包exe传送门:

https://download.csdn.net/download/Hfengxiang/89409663

结语:

突然冒出个想法,朋友们,生活或工作中遇到类似这样的痛点,欢迎在评论区讨论,一起研究研究看看能否用代码解决^_^

相关推荐
AIAdvocate41 分钟前
Pandas_数据结构详解
数据结构·python·pandas
小言从不摸鱼42 分钟前
【AI大模型】ChatGPT模型原理介绍(下)
人工智能·python·深度学习·机器学习·自然语言处理·chatgpt
FreakStudio3 小时前
全网最适合入门的面向对象编程教程:50 Python函数方法与接口-接口和抽象基类
python·嵌入式·面向对象·电子diy
redcocal4 小时前
地平线秋招
python·嵌入式硬件·算法·fpga开发·求职招聘
artificiali4 小时前
Anaconda配置pytorch的基本操作
人工智能·pytorch·python
RaidenQ4 小时前
2024.9.13 Python与图像处理新国大EE5731课程大作业,索贝尔算子计算边缘,高斯核模糊边缘,Haar小波计算边缘
图像处理·python·算法·课程设计
花生了什么树~.5 小时前
python基础知识(六)--字典遍历、公共运算符、公共方法、函数、变量分类、参数分类、拆包、引用
开发语言·python
Trouvaille ~5 小时前
【Python篇】深度探索NumPy(下篇):从科学计算到机器学习的高效实战技巧
图像处理·python·机器学习·numpy·信号处理·时间序列分析·科学计算
爆更小小刘5 小时前
Python基础语法(3)下
开发语言·python
哪 吒5 小时前
华为OD机试 - 第 K 个字母在原来字符串的索引(Python/JS/C/C++ 2024 E卷 100分)
javascript·python·华为od