第三方库 PyMuPDF 在 python 环境下对 PDF 文件的操作,特别是图片和pdf之间相互转换比较方便,并且能较方便的执行一些如追加删除之类的功能。开发文档见:https://pymupdf.readthedocs.io/en/latest/。

我写的一个查看 pdf文件demo已上传到我的资源中。界面左边栏为页面导航,点击缩略图后显示页面,按ctrl+鼠标滚轮后可缩放页面 ,使用了tkinter开发。CSDN资源下载:https://download.csdn.net/download/zhoury/12458793。欢迎下载参考。

Tkinter 是 Python 的标准 GUI 库。Python 使用 Tkinter 可以快速的创建 GUI 应用程序。

由于 Tkinter 是内置到 python 的安装包中、只要安装好 Python 之后就能 import Tkinter 库、而且 IDLE 也是用 Tkinter 编写而成、对于简单的图形界面 Tkinter 还是能应付自如。

与pyqt5相比,tkinter中如果想要构建一个GUI界面布局,就必须自己写代码,因为Tkinter没有提供一个图形界面设计器。这是tkinter中比较烦人的一个地方。还好本例界面还是比较简单的。

在本例中,我把界面部分和程序逻辑部分做了一些分离,界面类为class MyFrame(tk.Frame),主程序类为class PdfFrame(MyFrame),从MyFrame中继承界面元素后进行事件处理。下面分几部分简要介绍一下:

1、import库

import tkinter as tk
import tkinter.font as tf
from tkinter import messagebox, filedialog, simpledialog
from tkinter import ttk    
from PIL import Image, ImageTk

import sys
import os
import os.path
import time

import fitz    # pymupdf库

2、界面类

class MyFrame(tk.Frame):
    def __init__(self, master=None):
        tk.Frame.__init__(self, master) 
        self.root = master                 # root ,在主程序中 root = tk.Tk(),然后作为参数引入
        self.pack(fill=tk.BOTH, expand=True)
        self.font_en = tf.Font(self, size=14)

self.createICO()   #初始化图标
        self.create_menu()   #创建菜单
        self.createToolbar()  #创建工具栏
        self.create_widgets()   #创建主界面

菜单、工具栏生成这里就不写了,主要介绍一下主界面中缩略图列表和内容查看两个部分吧。

2.1缩略图列表

self.fm_left = tk.Frame(self)     # 左侧缩略图列表栏

# LabelFrame本身不带滚动条,在LabelFrame中放置label,并带滚动条的方法:
        # 1) 先新建一个canvas,在cavas上放置滚动条,2) 然后在canvas中放置labelframe,frame的长宽,紧跟canvas。
        # 3) 最后canvas.create_window,根据labelframe创建canvas窗口
        self.fm_list_scb_ver = tk.Frame(self.fm_left,width=230)  # 缩略图列表窗口
        vsb1 = tk.Scrollbar(self.fm_list_scb_ver,width=20)    # canvas垂直滚动条
        vsb1.pack(side=tk.RIGHT,fill=tk.Y)
        self.listCanvas = tk.Canvas(self.fm_list_scb_ver,bg = 'white',yscrollcommand=vsb1.set,width=220)  # 缩略图放置canvas
        self.listCanvas.pack(side=tk.LEFT,fill=tk.BOTH, expand=True)
        vsb1.config(command=self.listCanvas.yview)

self.labelframe = tk.LabelFrame(self.listCanvas)  # 把labelframe放在canvas里
        self.labelframe.pack(fill=tk.BOTH,expand=True)  # labelframe的长宽,和canvas差不多的

self.fm_list_scb_ver.pack(side=tk.TOP,fill=tk.Y,expand=True)    #放置缩略图列表窗口
        self.fm_left.pack(side=tk.LEFT,fill=tk.Y)    # 放置左侧缩略图列表栏
以上只是建立了一个空的缩略图窗口,还需要在主程序中生成label列表并放置后才能显示。

2.2 图片显示组件

self.fm_right = tk.Frame(self)    # 右侧查看窗口
        self.fm_canvas_scb_ver = tk.Frame(self.fm_right)  # canvas放置窗口
        vsb = tk.Scrollbar(self.fm_canvas_scb_ver)    # canvas滚动条
        vsb.pack(side=tk.RIGHT,fill=tk.Y) 
        hsb = tk.Scrollbar(self.fm_canvas_scb_ver,orient=tk.HORIZONTAL) 
        hsb.pack(side=tk.BOTTOM,fill=tk.X)
        # 创建canvas,并绑定滚动条
        self.cvCanvas = tk.Canvas(self.fm_canvas_scb_ver,bg = 'white',yscrollcommand=vsb.set,xscrollcommand=hsb.set,scrollregion=(0,0,1200,1200))
        self.cvCanvas.pack(fill=tk.BOTH, expand=True)
        self.cvCanvas.bind("<Control-MouseWheel>", self.canvasProcessWheel)   # 鼠标滚轮事件 CTRL + 滚轮
        vsb.config(command=self.cvCanvas.yview)
        hsb.config(command=self.cvCanvas.xview)
        self.fm_canvas_scb_ver.pack(fill=tk.BOTH, expand=True)  # 放置canvas放置窗口
        self.fm_right.pack(fill=tk.BOTH, expand=True)   # 放置右侧查看窗口

3、主程序

3.1 继承界面类

class PdfFrame(MyFrame):
    def __init__(self, master=None):
        super(PdfFrame,self).__init__(master)    # 调用父类初始化

3.2 打开pdf文件后刷新缩略图列表

3.2.1 读pdf页面,生成label列表
        for i in range(0, self.nPages):
            page = self.docDoc[i]  # 当前页
            zoom = int(100)    # mupdf输出页面缩放,100表示默认大小
            rotate = int(0)
            trans = fitz.Matrix(zoom / 100.0, zoom / 100.0).preRotate(rotate)
            pix = page.getPixmap(matrix=trans, alpha=False)    # 生成pixmap图片
            # set the mode depending on alpha
            mode = "RGBA" if pix.alpha else "RGB"
            w = 210    
            h = 297 
            img = Image.frombytes(mode, [pix.width, pix.height], pix.samples).resize((w,h))    # 生成当前页图
            merge_img = Image.new('RGB', (210, 297), 0xffffff)     # 空白缩略图
            merge_img.paste(img, (0, 0))    # 将图片贴到空白缩略图中

global My_Global_List_Imgs     # 一定要用global,否则canvas不显示图片
            My_Global_List_Imgs.append(ImageTk.PhotoImage(merge_img))          
            lb = tk.Label(self.labelframe, height=297, width=210 ,image=My_Global_List_Imgs[i])    # 产生缩略图label
            lb.bind("<Double-Button-1>",self.handlerAdaptor(self.clickList,curr=i))   # 绑定鼠标双击,传递参数curr为当前页码
            self.labelList.append(lb)

3.2.2  放置并显示

canvasHeight = 0  # 列表高度
        self.lbpageList = []    # 缩略图label列表,显示页码
        for j in range(0, self.nPages):
            l = self.labelList[j]        # 放置缩略图label
            l.pack()
            canvasHeight = canvasHeight + 297   # 计算缩略图高度
            lbpage = tk.Label(self.labelframe,text="第"+ str(j+1) + "页")    # 缩略图页码
            lbpage.pack()
            self.lbpageList.append(lbpage)
            canvasHeight = canvasHeight + 28    # 计算页码显示高度(默认行高)

self.listCanvas.config(scrollregion=(0,0,100,canvasHeight))    # 列表滚动区域
        self.listCanvas.create_window((110, int(canvasHeight/2)), window=self.labelframe)  # create_window
        self.fm_list_scb_ver.pack(side=tk.TOP,fill=tk.Y,expand=True)    # 只允许上下扩展
        self.btnShow.config(image=self.imgleft)       # 缩略图栏目缩放按钮图标
        self.listCanvas.update()  # force screen redraw/update
        time.sleep(0.25)    # pause, but don't block gui
3.3 显示当前页
        page = self.docDoc[self.nCurr]
        zoom = int(200)
        rotate = int(0)
        trans = fitz.Matrix(zoom / 100.0, zoom / 100.0).preRotate(rotate)
        pix = page.getPixmap(matrix=trans, alpha=False)  # 得到当前页

# set the mode depending on alpha
        mode = "RGBA" if pix.alpha else "RGB"
        self.m_pixmap = Image.frombytes(mode, [pix.width, pix.height], pix.samples)
        self.pixmapw = pix.width
        self.pixmaph = pix.height
        global My_Global_CanVas_Pic    # 要用global变量,否则canvas不显示图片
        My_Global_CanVas_Pic = ImageTk.PhotoImage(self.m_pixmap.resize((self.pixmapw,self.pixmaph)))
        self.cvCanvas.create_image(int(self.pixmapw/2),int(self.pixmaph/2),image=My_Global_CanVas_Pic)
        self.cvCanvas.config(scrollregion=(0,0,self.pixmapw,self.pixmaph))  # canvas滚动范围
        self.fm_canvas_scb_ver.pack(fill=tk.BOTH, expand=True)  # 放置canvas放置窗口
        self.cvCanvas.update()  # force screen redraw/update
        time.sleep(0.25)    # pause, but don't block gui

4、tkinter的问题

在开发中,界面布局代码虽然繁琐,这种编码只是重复劳动,一旦熟练后问题不是很大,最大的问题是性能问题,在本例中主要是canvas刷新比较慢。

在本例中有一个功能是使用ctrl+滚轮缩放页面,前段时间使用pyqt5写了个pymupdf的demo(见https://blog.csdn.net/zhoury/article/details/90743357),相同功能两者比较,pyqt5缩放很流畅,而tkinter有很明显的拖沓,特别是打开文件页数一多、查看的图片放大后,刷新更是有数量级的差距,感觉鼠标滚轮的事件都堵在队列中了。使用self.cvCanvas.update() 强制刷新,效果稍好点,但仍不是很理想,和pyqt5有明显差距。

目前没有找到好方法,如果哪位高手有解决方法,希望不吝赐教,多谢了!

使用pymupdf开发的pdf查看器-tkinter篇相关推荐

  1. Aurelia历险记:创建自定义PDF查看器

    本文由Vildan Softic进行同行评审. 感谢所有SitePoint的同行评审人员使SitePoint内容达到最佳状态! 在Web应用程序中处理PDF文件一直很麻烦. 如果幸运的话,您的用户只需 ...

  2. HTML PDF 查看器--RAD PDF 3.33 FOR ASP.NET

    RAD PDF 的主要特点 基于 HTML 的 PDF 阅读器 客户端 PDF 编辑器 功能丰富的 PDF 表单填写器 交互式 PDF 表单设计器 保护 PDF 内容 签署和认证 PDF 文件 广泛的 ...

  3. 在线PDF查看器和PDF编辑器:GrapeCity Documents PDF (GcPdf)

    跨平台 JavaScript PDF 查看器 使用我们的 JavaScript PDF 查看器在网络上阅读和编辑 PDF.跨浏览器和框架打开和打印.GrapeCity Documents PDF (G ...

  4. PDF控件PDFToolkit VCL V5.0.0.612发布 | 修复了PDF查看器和打印机

    2019独角兽企业重金招聘Python工程师标准>>> PDFtoolkit VCL 5.0.0.612 更新 修复以下问题: PDF查看器 查看器冻结加载特定的PDF文件时查看器冻 ...

  5. Texmaker中PDF查看器的设置经验

    这个问题很简单,不过有时候记不清,所以特意总结一下. Texmaker是一个不错的LaTeX编辑器,在我的推荐下现在实验室的小伙伴们都在用.但是我注意到很多人用的时候有个问题,Texmaker的PDF ...

  6. texstudio调用外部pdf查看器的配置方法

    选项-设置-命令-外部PDF查看器-打印符号-找到wps或者其他pdf查看软件的安装位置(可以在桌面的快捷方式右边查看),然后导入即可

  7. WordPress的最佳PDF查看器比较

    PDF文件是共享和显示文档的有效且经过时间考验的方式,但是当您的网站没有PDF查看器时,存在一些限制. 首先,您可能会失去访问者的风险:浏览器可以加载PDF文档时,文件会加载到新的标签页或窗口中,这意 ...

  8. Zathura: 轻巧好用的 PDF 查看器]

    [Zathura: 轻巧好用的 PDF 查看器](https://linuxtoy.org/archives/zathura.html) 这个文件很轻巧,且支持VIM方式的 快捷键 转载于:https ...

  9. 7款最佳jQuery和JavaScript的PDF查看器插件

    在这篇文章中,我们将提供最好的PDF浏览器插件. 1. JavaScript的PDF阅读器(JavaScript PDF Reader : pdf.js) pdf.js 基于HTML5实现 在线演示 ...

最新文章

  1. popWindow 出现点击上下空白区域消失点击左右空白区域不消失弹框的处理方法
  2. ASP.NET 3.5 企业级开发
  3. 关于Spring中的context:annotation-config/配置(开启注解)
  4. other than ,more than,less than,rather than到底有什么区别
  5. Spring boot日志关系
  6. java多线程------实现Runnable接口创建多进程,实现资源共享
  7. 《尼山萨满》项目美术亲述游戏创作过程
  8. 实现一个简单的基于码云(Gitee) 的 Storage
  9. php递归实现冒泡排序,PHP冒泡排序、快速排序算法
  10. Linux AIO的新归宿:io_uring(介绍,系统调用)
  11. Ponemon Institute告诉你,大数据正在勾搭网络安全
  12. linux 修改git端口号,SSH默认端口更改后使用Git
  13. 高一计算机函数公式,高中全部函数公式大全
  14. centos Unison+Inotify双向同步
  15. 新三级医院信息化建设解决方案
  16. 将一张表的主键作为外键关联到另一张表中
  17. 小明兄短视频引流变现必火课,最强DOU+玩法 超级变现法则,两天直播间涨粉20W+
  18. monkeyrunner +python 多台真机 多线程
  19. 2019微信公开课上张小龙都讲了些什么
  20. 日语笔记——新编日语教程2——春休みのあいだ上海に帰りました

热门文章

  1. 1040 输出绝对值
  2. 手机中怎么切换CAD图纸的布局空间
  3. python完成数字图像处理小练习
  4. JS使用正则+replace实现replace All 全部替换的方法
  5. Rokoko for Maya
  6. OpenCV-Python小应用(六):车道线检测
  7. (附源码)Springboot流浪动物救助平台-计算机毕设 071512
  8. 顺通服装鞋帽erp管理软件在实际中带来的便利
  9. Object类的Cloneable接口没有实现所以需要自己进行相关的实现
  10. 写一篇anytxt searcher软件的评测文章