You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用tkPDFViewer开发PDF阅读器遇Pixmap无getImageData属性问题求助

解决tkPDFViewer适配PyMuPDF新版本的API错误

问题背景

使用tkPDFViewer开发PDF阅读器时,先后遇到两个API错误:

  1. 初始运行官方示例报错:'Page' object has no attribute 'getPixmap'
  2. 将getPixmap替换为get_pixmap()后,又报错:'Pixmap' object has no attribute 'getImageData'

问题原因

这两个错误均由PyMuPDF(fitz库)版本更新导致API命名规则变更:

  • 旧版方法getPixmap() → 新版改为get_pixmap()
  • 旧版方法getImageData() → 新版改为tobytes()

修复步骤

1. 修正tkPDFViewer库代码

修改库中ShowPdf类的add_img函数,替换废弃的API:

try:
    from tkinter import*
    import fitz
    from tkinter.ttk import Progressbar
    from threading import Thread
    import math
except Exception as e:
    print(f"导入模块时出错: {e}")

class ShowPdf():

    img_object_li = []

    def pdf_view(self,master,width=1200,height=600,pdf_location="",bar=True,load="after"):

        self.frame = Frame(master,width= width,height= height,bg="white")

        scroll_y = Scrollbar(self.frame,orient="vertical")
        scroll_x = Scrollbar(self.frame,orient="horizontal")

        scroll_x.pack(fill="x",side="bottom")
        scroll_y.pack(fill="y",side="right")

        percentage_view = 0
        percentage_load = StringVar()

        if bar==True and load=="after":
            self.display_msg = Label(textvariable=percentage_load)
            self.display_msg.pack(pady=10)

            loading = Progressbar(self.frame,orient= HORIZONTAL,length=100,mode='determinate')
            loading.pack(side = TOP,fill=X)

        self.text = Text(self.frame,yscrollcommand=scroll_y.set,xscrollcommand= scroll_x.set,width= width,height= height)
        self.text.pack(side="left")

        scroll_x.config(command=self.text.xview)
        scroll_y.config(command=self.text.yview)


        def add_img():
            precentage_dicide = 0
            # 直接传文件路径,无需打开文件对象
            open_pdf = fitz.open(pdf_location)

            for page in open_pdf:
                pix = page.get_pixmap()
                pix1 = fitz.Pixmap(pix,0) if pix.alpha else pix
                # 替换getImageData为tobytes
                img = pix1.tobytes("ppm")
                timg = PhotoImage(data = img)
                self.img_object_li.append(timg)
                if bar==True and load=="after":
                    precentage_dicide = precentage_dicide + 1
                    percentage_view = (float(precentage_dicide)/float(len(open_pdf))*float(100))
                    loading['value'] = percentage_view
                    percentage_load.set(f"加载中... {int(math.floor(percentage_view))}%")
            if bar==True and load=="after":
                loading.pack_forget()
                self.display_msg.pack_forget()

            for i in self.img_object_li:
                self.text.image_create(END,image=i)
                self.text.insert(END,"\n\n")
            self.text.configure(state="disabled")

        def start_pack():
            t1 = Thread(target=add_img)
            t1.start()

        if load=="after":
            master.after(250,start_pack)
        else:
            start_pack()

        return self.frame



def main():
    root = Tk()
    root.geometry("700x780")
    d = ShowPdf().pdf_view(root,pdf_location=r"D:\DELL\Documents\Encyclopedia GUI.pdf",width=50,height=200)
    d.pack()
    root.mainloop()

if __name__ == '__main__':
    main()

2. 修正主代码的PDF路径传递错误

原代码中pdf_location=open(filename,'r')是错误的,应直接传递文件路径字符串,修改后的主代码:

from tkinter import *
from tkinter import filedialog
from tkPDFViewer import tkPDFViewer as pdf
import os

root = Tk()
root.geometry('630x700+400+100')
root.title('PDF viewer')
root.configure(bg='white')

def browseFiles():
    filename = filedialog.askopenfilename(initialdir=os.getcwd(),
                                          title='选择PDF文件',
                                          filetypes=(('PDF文件','.pdf'),
                                                     ('PDF文件','.PDF'),
                                                     ('所有文件','*.*')))
    if not filename:
        return  # 用户取消选择时直接返回
    # 清空旧图片对象,避免内存占用过高和重复显示
    pdf.ShowPdf.img_object_li.clear()
    v1 = pdf.ShowPdf()
    # 直接传递文件路径
    v2 = v1.pdf_view(root,pdf_location=filename,
                     width=77,height=100)
    v2.pack(pady=(0,0))

Button(root,text='打开PDF',width=40,
       command=browseFiles,
       font='arial 20',bd=4).pack()

root.mainloop()

额外优化说明

  • 添加用户取消文件选择的判断,避免空路径报错
  • 每次加载新PDF前清空图片对象列表,防止内存泄漏和重复显示旧内容

内容的提问来源于stack exchange,提问作者Sadek hossain nishat

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 19:35:38