使用tkPDFViewer开发PDF阅读器遇Pixmap无getImageData属性问题求助
解决tkPDFViewer适配PyMuPDF新版本的API错误
问题背景
使用tkPDFViewer开发PDF阅读器时,先后遇到两个API错误:
- 初始运行官方示例报错:
'Page' object has no attribute 'getPixmap' - 将
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
相关产品推荐
相关产品推荐

