Search code examples
pythonpdftkinterzoomingtkpdfviewer

How to make zoom in PDF viewer with Python tkinter and tkPDFViewer?


I have made a very simple PDF viewer for all PDF files contained in the folder where the executable is placed. Then, I am interested in adding some basic utilities to a buttons panel, such as with zoom + and zoom - button to increase the view of PDF file and allowing to improve the reading of the selected PDF file.

Here's my code [ https://github.com/marco-rosso-m/GUI_simplePDFviewer ]:

import tkinter as tk
from tkPDFViewer import tkPDFViewer as pdf 
from os import path
from glob import glob
import sys
import os

# set global variable v2
global v2
v2 = None

def list_file_ext_current_folder(dr, ext, ig_case=False):
    if ig_case: # case sensitive
        ext =  "".join(["[{}]".format(ch + ch.swapcase()) for ch in ext])
    return glob(path.join(dr, "*." + ext))

def on_select(evt):
    global v2
    # Note here that Tkinter passes an event object to onselect()
    w = evt.widget
    index = int(w.curselection()[0])
    value = w.get(index)
    # print('You selected item %d: "%s"' % (index, value))
    if v2: # if old instance exists, destroy it first
        v2.destroy()
    # creating object of ShowPdf from tkPDFViewer. 
    v1 = pdf.ShowPdf() 
    # clear the image list # this corrects the bug inside tkPDFViewer module
    v1.img_object_li.clear()
    # Adding pdf location and width and height. 
    v2=v1.pdf_view(frame2,pdf_location = f"{value}",  width = 80, height = 100)
    # Placing Pdf inside gui
    v2.pack()

def resource_path(relative_path):
    """ Get absolute path to resource, works for dev and for PyInstaller """
    base_path = getattr(
        sys,
        '_MEIPASS',
        os.path.dirname(os.path.abspath(__file__)))
    return os.path.join(base_path, relative_path)

# tkinter root widnow
root = tk.Tk() 
root.geometry('800x600')
root.minsize(800, 600)
root.title('Simple PDF Viewer inside the current Folder')
root.wm_iconbitmap(resource_path('logo.ico'))

# tkinter frame for listbox
frame1=tk.Frame(root,width=40)
# tkinter frame for pdf viewer
frame2=tk.Frame(root)

frame1.pack(side="left",fill="both",expand=True)
frame2.pack(side="right",fill="both",expand=True)

# get list of pdf files inside the current folder
paths=list_file_ext_current_folder(".","pdf",True)

# vertical scrollbar
yscrollbar = tk.Scrollbar(frame1)
yscrollbar.pack(side = tk.RIGHT, fill = tk.Y)

# generate listbox
lb = tk.Listbox(frame1, selectmode = "SINGLE", name='lb', yscrollcommand = yscrollbar.set)

lb.pack(padx = 10, pady = 10, expand = tk.YES, fill = "both")

if paths: # if paths list is not empty
    for each_item in range(len(paths)):
        lb.insert(tk.END, paths[each_item])
        lb.itemconfig(each_item)
    lb.bind('<<ListboxSelect>>', on_select)
    lb.select_set(0) # This only sets focus on the first item.
    lb.event_generate("<<ListboxSelect>>") # This creates the even clicked
else:
    lb.insert(tk.END, "No PDF are present in this forlder!")

# Attach listbox to vertical scrollbar
yscrollbar.config(command = lb.yview)


root.mainloop()

Moreover, at present, the above-implemented PDF viewer seems to not be responsive with respect to the window dimension, is any way to make it responsive?


Solution

  • In order to manage the zooming with tkPDFViewer module, I have downloaded the source code here, then I modified the pdf_view function adding a zooming parameter that I called zoomDPI, setting its default value of 72dpi:

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

    Thereafter, the new input parameter is used to modify the method getPixmap() inside the function add_img(). Inside this function I modified the following line inserting the new input parameter which govern the resolution of the image and thus the zooming level:

    pix = page.getPixmap(dpi=zoomDPI)
    

    Finally, inside the main code, when calling the pdf_view method I can adjust the image level by giving in input a dpi value higher of 72 in order to increase the zoom level (zooming in), or a lower value in order to decrease the zoom level (zooming out).

            if v2: # if old instance exists, destroy it first
                v2.destroy()
            # creating object of ShowPdf from tkPDFViewer. 
            v1 = pdf.ShowPdf() 
            # clear the image list # this corrects the bug inside tkPDFViewer module
            v1.img_object_li.clear()
            # Adding pdf location and width and height. 
            v2=v1.pdf_view(frame2,pdf_location = f"{value}",zoomDPI=zoomDPI) # default value for zoomDPI=72. Set higher dpi for zoom in, lower dpi for zoom out
            # Placing Pdf inside gui
            v2.pack()
    

    The new complete code can be found here.