This code works fine and does exactly what I want but in the larger application that it is used in, when loading a new PDF or using the zoom in/zoom out buttons, the frame flickers not nearly as quickly as I would like or at all if possible. Basically, this takes in a pdf and uses the fitz library in Python to change it to an image and place it in a tkinter text widget using image_create. I would also like a better way of zooming but this was the only way I could think to do it.
Here's the code:
import tkinter as tk
from tkinter import filedialog
import ttkbootstrap as tb
import fitz
#----------------------------------------------------------
class PDFExample(tb.Frame):
#------------------------------------------------------
def __init__(self, root, filename=None):
super().__init__(root)
self.root = root
self.filename = filename
self.pack(fill='both', expand=True)
self.dpi = 100
# Setup
self.setupViewer()
self.checkSelection()
#------------------------------------------------------
def setupViewer(self):
# Create 2 Frames
self.pdf_frame = tb.Frame(self)
self.pdf_frame.pack(side='left', fill='both',
expand=1)
self.button_frame = tb.Frame(self)
self.button_frame.pack(side='right', fill='y')
# Create PDF Viewer
self.pdfViewer()
# Create Buttons
self.open_button = tb.Button(self.button_frame,
text='Open PDF', command=self.open)
self.open_button.grid(row=0, column=0,
padx=5, pady=5, sticky='nsew')
self.save_button = tb.Button(self.button_frame,
text='Save PDF', command=self.save,
state='disabled')
self.save_button.grid(row=1, column=0,
padx=5, pady=5, sticky='nsew')
self.zoom_in = tb.Button(self.button_frame,
text='Zoom In', command=self.zoomIn,
state='disabled')
self.zoom_in.grid(row=2, column=0,
padx=5, pady=5, sticky='nsew')
self.zoom_out = tb.Button(self.button_frame,
text='Zoom Out', command=self.zoomOut,
state='disabled')
self.zoom_out.grid(row=3, column=0,
padx=5, pady=5, sticky='nsew')
#------------------------------------------------------
def checkSelection(self):
if self.filename is not None and os.file.exists(self.filename):
self.save_button.config(state='enable')
self.zoom_in.config(state='enable')
self.zoom_out.config(state='enable')
# Show PDF
self.createPDF()
self.addImage()
#------------------------------------------------------
def pdfViewer(self):
scroll_y = tk.Scrollbar(self.pdf_frame,
orient='vertical', width=16)
scroll_x = tk.Scrollbar(self.pdf_frame,
orient='horizontal', width=16)
scroll_x.pack(side='bottom', fill='x')
scroll_y.pack(side='right', fill='y')
self.text = tb.Text(self.pdf_frame,
yscrollcommand=scroll_y.set,
xscrollcommand=scroll_x.set)
self.text.pack(side='top', fill='both', expand=True)
scroll_x.config(command=self.text.xview)
scroll_y.config(command=self.text.yview)
#------------------------------------------------------
def open(self):
files = [('PDF', '*.pdf'), ('All Files', '*.*')]
ask_where = filedialog.askopenfile(filetypes=files,
defaultextension='.pdf')
self.filename = ask_where.name
self.addImage()
#------------------------------------------------------
def save(self):
files = [('PDF', '*.pdf'), ('All Files', '*.*')]
ask_where = filedialog.asksaveasfile(filetypes=files,
defaultextension='.pdf')
shutil.copy(self.filename, ask_where.name)
#------------------------------------------------------
def zoomIn(self):
self.dpi += 10
self.addImage()
#------------------------------------------------------
def zoomOut(self):
self.dpi -= 10
self.addImage()
#------------------------------------------------------
def addImage(self):
self.img_object_li = []
with fitz.open(self.filename) as open_pdf:
for page in open_pdf:
pix = page.get_pixmap(dpi=self.dpi)
pix1 = fitz.Pixmap(pix,0) if pix.alpha else pix
img = pix1.tobytes('ppm')
timg = tb.PhotoImage(data=img)
self.img_object_li.append(timg)
# Destroy PDF Viewer and Recreate in order to Zoom
# There has to be a better way but this is all I
# could figure out for now
for widget in self.pdf_frame.winfo_children():
widget.destroy()
self.pdfViewer()
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')
#----------------------------------------------------------
if __name__ == '__main__':
app = tb.Window(title='Test')
p = PDFExample(app)
app.position_center()
app.mainloop()
Please ask any clarifying questions (I'm not always the best at explaining my code issues unless it's in person).
Thank you for any help!