用wxPython和PyMuPDF将PNG图像合并为PDF文件

news2024/11/13 11:53:23

在日常工作中,我们经常需要将多个图像文件合并到一个PDF文档中,以便于查看、共享或存档。虽然现有的一些工具可以实现这一功能,但开发一个自定义的GUI工具可以更好地满足特定需求,并提供更好的用户体验。

在本文中,我将介绍如何使用Python、wxPython和PyMuPDF库创建一个简单的图形界面程序,用于将指定文件夹中的PNG图像合并为一个PDF文件。

程序概述

我们的程序包含以下主要部分:

1. **wxPython GUI** - 提供用户界面,包括文件选择器、图像预览和文件列表控件。
2. **PyMuPDF库** - 用于创建和操作PDF文件,将PNG图像插入到PDF页面中。
3. **Python文件操作** - 用于遍历文件夹和获取文件信息。

下面是程序的用户界面截图:

使用步骤:

1. 运行程序后,选择包含PNG图像的文件夹
2. 在左侧的列表框中,所有PNG文件名将被列出。单击任一文件名,右侧区域会显示该图像的预览。
3. 选中要合并到PDF中的PNG文件,点击">>"按钮将其移动到右侧列表框中。
4. 点击"生成PDF"按钮,选择PDF文件的保存路径。
5. 程序将按照右侧列表框中的顺序,将PNG图像合并到一个新的PDF文件中。
6. 合并完成后,会弹出一个对话框,显示PDF文件的保存路径。

C:\pythoncode\new\pngToPdf.py

代码解析

import os
import wx
import fitz  # PyMuPDF库

class PDFMergeApp(wx.App):
    def __init__(self):
        super().__init__()
        self.frame = PDFMergeFrame(None)
        self.frame.Show()

class PDFMergeFrame(wx.Frame):
    def __init__(self, parent):
        super().__init__(parent, title="PDF合并工具")
        panel = wx.Panel(self)
        
        # 创建控件
        self.dir_picker = wx.DirPickerCtrl(panel, message="选择PNG文件夹")
        self.list_box1 = wx.ListBox(panel, style=wx.LB_SINGLE)
        self.picture = wx.StaticBitmap(panel)
        self.list_box2 = wx.ListBox(panel, style=wx.LB_EXTENDED)
        move_btn = wx.Button(panel, label=">>")
        generate_btn = wx.Button(panel, label="生成PDF")
        
        # 绑定事件处理函数
        self.dir_picker.Bind(wx.EVT_DIRPICKER_CHANGED, self.update_list_box1)
        self.list_box1.Bind(wx.EVT_LISTBOX, self.display_image)
        move_btn.Bind(wx.EVT_BUTTON, self.move_to_list_box2)
        generate_btn.Bind(wx.EVT_BUTTON, self.generate_pdf)
        
        # 布局
        sizer = wx.BoxSizer(wx.HORIZONTAL)
        left_sizer = wx.BoxSizer(wx.VERTICAL)
        right_sizer = wx.BoxSizer(wx.VERTICAL)
        left_sizer.Add(self.dir_picker, 0, wx.EXPAND | wx.ALL, 5)
        left_sizer.Add(self.list_box1, 1, wx.EXPAND | wx.ALL, 5)
        right_sizer.Add(self.picture, 1, wx.EXPAND | wx.ALL, 5)
        right_sizer.Add(self.list_box2, 1, wx.EXPAND | wx.ALL, 5)
        right_sizer.Add(generate_btn, 0, wx.ALIGN_CENTER | wx.ALL, 5)
        sizer.Add(left_sizer, 1, wx.EXPAND | wx.ALL, 5)
        sizer.Add(move_btn, 0, wx.ALIGN_CENTER_VERTICAL | wx.ALL, 5)
        sizer.Add(right_sizer, 1, wx.EXPAND | wx.ALL, 5)
        panel.SetSizer(sizer)
        
    def update_list_box1(self, event):
        self.list_box1.Clear()
        dir_path = self.dir_picker.GetPath()
        for filename in os.listdir(dir_path):
            if filename.endswith(".png"):
                self.list_box1.Append(filename)
        
    def display_image(self, event):
        selection = event.GetSelection()
        filename = self.list_box1.GetString(selection)
        dir_path = self.dir_picker.GetPath()
        image = wx.Image(os.path.join(dir_path, filename), wx.BITMAP_TYPE_PNG)
        self.picture.SetBitmap(wx.Bitmap(image))
        
    def move_to_list_box2(self, event):
        selections = self.list_box1.GetSelections()
        items = [self.list_box1.GetString(sel) for sel in selections]
        for item in items:
            self.list_box2.Append(item)
            self.list_box1.Delete(self.list_box1.FindString(item))
        
    def generate_pdf(self, event):
        dir_path = self.dir_picker.GetPath()
        pdf_path = wx.FileSelector("保存PDF文件", wildcard="PDF 文件 (*.pdf)|*.pdf",
                                flags=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
        if pdf_path:
            pdf = fitz.open()
            for index in range(self.list_box2.GetCount()):
                filename = self.list_box2.GetString(index)
                image_path = os.path.join(dir_path, filename)
                img = fitz.Pixmap(image_path)
                page = pdf.new_page(width=img.width, height=img.height)
                page.insert_image(rect=page.rect, pixmap=img)
            pdf.save(pdf_path)
            pdf.close()
            wx.MessageBox(f"已成功生成PDF文件: {pdf_path}", "完成", wx.OK | wx.ICON_INFORMATION)
if __name__ == "__main__":
    app = PDFMergeApp()
    app.MainLoop()

这段代码的核心在于wxPython GUI的构建和PyMuPDF库的使用。

在创建GUI时,我们定义了各种控件,如文件夹选择器、列表框和图像预览区域,并将它们合理布局。通过事件绑定,实现了不同控件的交互功能,例如选择文件夹后更新文件列表、预览图像、在列表框之间移动文件等。

合并PNG到PDF的关键是使用PyMuPDF库。我们遍历右侧列表框中的PNG文件路径,使用`fitz.Pixmap`打开每个PNG图像。然后,为每个图像创建一个新的PDF页面,并使用`page.insert_image`方法将图像插入到该页面中。最后,将所有页面保存到一个新的PDF文件中。

总结

通过结合wxPython和PyMuPDF,我们创建了一个方便实用的工具,可以快速将PNG图像合并为PDF文档。该程序不仅操作简单,还具有预览功能,可以确认要合并的图像顺序。你可以根据自己的需求对代码进行进一步扩展和定制,例如支持其他图像格式、调整图像大小或添加水印等。无论是用于工作还是个人使用,这个小工具都将为你节省宝贵的时间和精力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1677889.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

idea SpringBoot + Gradle 打成zip包(包含配置文件等)

前言: 通过上一文章,我们可以通过ideagradle 构建Springboot项目并实现打成jar包,本文章测试通过gradle 打包成zip包并包含启动文件、配置文件等信息;可点击此处查看idea SpringBoot Gradle 环境配置到项目打包-CSDN博客 一、工…

Char类型、转义及字符集:Java中的字符串奥秘

在Java的8中基本数据类型中,char类型是较难掌握,处理char类型本身的用法之外,还要理解其与字符串的关系、转义序列、字符集。 本文将从基础概念出发,逐步深入探讨这些主题,并通过实例演示来巩固理解。 一、Char类型&…

(001)apidoc 的安装

安装 1.确定 node 和 npm 的匹配版本 node -vv10.14.1# 切换node 版本 nvm list nvm use 20.12.22.安装 apidoc。 npm install -g apidoc3.生成文档: apidoc -i ../ -o document/ -f ".java$"-i :指定扫描路径。-o:输出目录。…

短剧私域-快速引流变现

短剧的爆火,衍生出了很多周边项目。 比如免费看剧App,短剧搜索机器人,短剧付费圈子等等。 这些项目的本质,就是借助短剧的热度,把流量引到自己的鱼塘进行变现。 短剧机器人大家都知道,目前最火的一种玩法…

Nginx+Keepalived高可用集群

NginxKeepalived高可用集群 服务器准备 服务器名IP软件包主从n1RIP 192.168.99.111 VIP 192.168.99.200nginx keepaliveMASTERn2RIP192.168.99.122 VIP 192.168.99.200nginx keepalivedh1RIP 192.168.99.133 VIP 192.168.99.200httpdh2RIP 192.168.32.144 VIP 192.168.99.200h…

2024江苏省赛 H. 完蛋,我被房产包围了 【费用流、分时图】

完蛋,我被房产包围了 n ≤ 200 , ∑ n ≤ 1 0 4 n \leq 200, \sum n \leq 10^4 n≤200,∑n≤104 求出最大利润 思路 每个代理商每次买房狂潮只能卖出 1 1 1 套房子,小红卖出一套房子贬值 1 1 1 元,小绿卖出一套房子贬值 ⌈ a i 10 ⌉ \…

短视频世上无人再似她:成都鼎茂宏升文化传媒公司

短视频世上无人再似她 —— 记忆中的光影传奇 在短视频盛行的今天,每一位创作者都在用镜头捕捉生活,记录世界,但有那么一位艺术家,她的作品如同夜空中最亮的星,即便是在信息洪流中,也依然闪耀着独一无二的…

数字社交的先锋:探索Facebook的未来发展

在当今数字化时代,社交媒体已经成为人们日常生活中不可或缺的一部分。而在众多社交平台中,Facebook一直处于引领地位,不断探索和创新,塑造着数字社交的未来。本文将深入探讨Facebook作为数字社交的先锋,探索其未来发展…

天锐绿盾和bitlocker有啥区别?

#绿盾文档加密系统# 天锐绿盾和BitLocker是两种不同的数据加密解决方案,它们各自有不同的重点和应用场景,以下是它们之间的主要区别: PC地址: https://isite.baidu.com/site/wjz012xr/2eae091d-1b97-4276-90bc-6757c5dfedee 移动…

华为hcip是什么?华为hcip网络工程师值得考吗?

前面我们讲了华为认证各个方向hcie的内容,那么很多同学会问,华为hcip是什么?华为hcip网络工程师值得考吗? 华为HCIP是什么? 华为HCIP(Huawei Certified ICT Professional)认证是华为技术有限公…

这三个网站我愿称之为制作答辩PPT的神

很多快要毕业的同学在做答辩PPT的时候总是感觉毫无思路,一窍不通。但这并不是你们的错,对于平时没接触过相关方面,第一次搞答辩PPT的人来说,这是很正常的一件事。一个好的答辩PPT可以根据以下分为以下几部分来写。 1.研究的背景和…

Leetcode—3146. 两个字符串的排列差【简单】

2024每日刷题&#xff08;135&#xff09; Leetcode—3146. 两个字符串的排列差 实现代码 class Solution { public:int findPermutationDifference(string s, string t) {int maps[26];int mapt[26];for(int i 0; i < s.size(); i) {int idxs s[i] - a;int idxt t[i] …

精酿啤酒的未来:啤酒的发展与展望

随着人们生活水平的提高和对品质生活的追求&#xff0c;精酿啤酒逐渐受到了广泛的关注和喜爱。作为精酿啤酒的代表&#xff0c;Fendi club啤酒凭借其与众不同的酿造工艺与技术&#xff0c;逐渐在市场中树立了良好的口碑。然而&#xff0c;面对未来激烈的竞争和不断变化的市场需…

摸鱼大数据——Linux搭建大数据环境(安装zooKeeper和zookeeper shell命令)五

安装zookeeper软件 1.上传软件 使用CRT等客户端远程上传 zookeeper-3.4.6.tar.gz 文件到/export/software目录下 2.解压软件 [rootnode1 ~]# cd /export/software/ [rootnode1 software]# tar -xzvf zookeeper-3.4.6.tar.gz -C /export/server/ [rootnode1 software]# cd /ex…

CentOS上Zookeeper集群安装部署

简介 Zookeeper是一款分布式的集群化软件&#xff0c;可以在多台服务器上部署&#xff0c;并协同组成分布式集群一起工作。 ZooKeeper是一个分布式的&#xff0c;开放源码的分布式应用程序协调服务&#xff0c;是Hadoop和Hbase的重要组件。它是一个为分布式应用提供一致性服务的…

若依cloud-plus(RuoYi-Cloud-Plus)框架(后端)分析

文章目录 本文以mysql为例项目结构图环境(最起码的配置)数据库初始化文件位置配置服务启动架构图框架分析&#xff1a; 本文以mysql为例 官方文档&#xff1a; https://plus-doc.dromara.org/#/ruoyi-cloud-plus/home 项目结构图 RuoYi-Cloud-Plus ├─ ruoyi-api …

霸道龙尊短视频:成都鼎茂宏升文化传媒公司

霸道龙尊短视频&#xff1a;龙族的传奇与现代的交融 在数字化时代的浪潮中&#xff0c;短视频以其短小精悍、内容丰富的特点&#xff0c;迅速占领了人们的碎片时间。成都鼎茂宏升文化传媒公司而在这些短视频中&#xff0c;一股独特的“霸道龙尊”风潮正在悄然兴起&#xff0c;…

JavaScript基础(七)

isNaN //用来判断一个变量是不是一个非数字 不是来判断是不是number类型&#xff0c;而是判断当前值能不能转为number类型&#xff0c;OK&#xff1f;懂了。 还有同学不明白&#xff0c;来看实例: <script> //isNaN(非数字)→true &#xff08;数字&#xff09;→fal…

实战| 手把手教你实现俯卧撑实时计数:OpenCV+MediaPipe

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

No Cortex-M SW Device Found

将DIO和CLK管脚调换一下