Mar-05-2023, 04:09 AM
(This post was last modified: Mar-05-2023, 04:09 AM by deanhystad.)
Stop using the reply button unless you want to reference something in the previous post. Use the New Reply instead.
How long is the lag? Is the lag when you open the pdf or when you push an arrow key? Not writing image files would speed things significantly. You don't need to make image files.
A few comments:
Your "Select PDF" button doesn't have a parent. This can mess with laying out controls in the window.
This sets button1 = None because grid() returns None.
on_left_arrow and on_right_arrow are nearly identical. If the only difference between two function is one function adds 1 and the other subtracts one, you don't need two functions. Use a function argument to add or subtract 1.
The way you use grid is odd. The row and column index number should mean something. Yours' appear to be arbitrary. You have more rows and columns than widgets.
Why are you using grid? This is not really a grid like layout. Where are there rows or columns? I think pack is better than grid for most window layouts.
Avoid setting the application window size. Let the layout manager determine how large the window needs to be. An image viewer program should be resizable.
That might sound a little harsh, but for the most part I think you wrote a really nice program. I had a lot of fun playing with it and wrote a version that I'll keep around to extract images from PDF files.
I added in a rotate button. It only took until now to realize why you were rotating images in your other post. I use buttons to select images instead of the mystifying key presses. I got rid of the exit button because the window manager provides one. I save the images in a list. This is faster and it lets me rotate an image and have it stay rotated. It is also a lot shorter and clearer code using an integer index to refer an image than using an integer index to reference a filename in a list to read the file and get the image. And I made the program resizable. Resize the window and it resizes the image (up to a point).
How long is the lag? Is the lag when you open the pdf or when you push an arrow key? Not writing image files would speed things significantly. You don't need to make image files.
A few comments:
Your "Select PDF" button doesn't have a parent. This can mess with laying out controls in the window.
This sets button1 = None because grid() returns None.
button1 = tk.Button(root, text="Select Folder", command=select_folder).grid(row=13,column=12)Do not do wildcard imports. It creates tons of variables in your program that you might not know about and makes it hard to track down where functions or variables are imported.
from tkinter import * # Bad! And you don't even use it.If all a function does is call another function, you only need one of the functions. Set command=root.destroy instead of writing this:
def exit_program(): root.destroy()You should use buttons to change the image, not key presses. Binding key press events doesn't give your users any hints about how to use the program. It also forces changing from the mouse to the keyboard. Think about the user experience.
on_left_arrow and on_right_arrow are nearly identical. If the only difference between two function is one function adds 1 and the other subtracts one, you don't need two functions. Use a function argument to add or subtract 1.
The way you use grid is odd. The row and column index number should mean something. Yours' appear to be arbitrary. You have more rows and columns than widgets.
Why are you using grid? This is not really a grid like layout. Where are there rows or columns? I think pack is better than grid for most window layouts.
Avoid setting the application window size. Let the layout manager determine how large the window needs to be. An image viewer program should be resizable.
root.geometry("1200x800") # let the user decide how big the window should beUse fewer comments. Good code it is easy to read. Lots of comments often make code harder to read, and they usually end up being misleading because the code changes but the comments remain the same. Instead of this:
# get the image extension image_ext = base_image["ext"] # load it to PIL image = PIL.Image.open(io.BytesIO(image_bytes)) # save it to temporary folder image.save(os.path.join(temp_dir.name, f"image{page_index+1}_{image_index}.{image_ext}"))Group your comments to describe the purpose of the following code. Think of them as a narrative or context or anything that cannot be inferred by reading the code. Do not use comments as pseudocode.
# Extract imags into a temporary folder. The temporary is used for image storage. image_ext = base_image["ext"] image = PIL.Image.open(io.BytesIO(image_bytes)) image.save(os.path.join(temp_dir.name, f"image{page_index+1}_{image_index}.{image_ext}"))Why do you have an exit button? Doesn't the window manager provide a way to close the window?
That might sound a little harsh, but for the most part I think you wrote a really nice program. I had a lot of fun playing with it and wrote a version that I'll keep around to extract images from PDF files.
I added in a rotate button. It only took until now to realize why you were rotating images in your other post. I use buttons to select images instead of the mystifying key presses. I got rid of the exit button because the window manager provides one. I save the images in a list. This is faster and it lets me rotate an image and have it stay rotated. It is also a lot shorter and clearer code using an integer index to refer an image than using an integer index to reference a filename in a list to read the file and get the image. And I made the program resizable. Resize the window and it resizes the image (up to a point).
import fitz import io import tkinter as tk from tkinter import filedialog from PIL import Image, ImageTk from pathlib import Path def select_pdf_file(): """Load images from a PDF file""" global images if file := filedialog.askopenfilename(filetypes=[("PDF", "*.pdf")]): images = [] with fitz.open(file) as doc: for page in doc: for xref, *_ in page.get_images(): image = doc.extract_image(xref) images.append(Image.open(io.BytesIO(image["image"]))) show_image(0) def select_folder(): """Load images from a folder""" global images if folder := filedialog.askdirectory(): images = [] for file in Path(folder).iterdir(): if file.suffix.lower() in (".png", ".bmp", ".jpg", ".bmp", ".dcm"): images.append(Image.open(file)) show_image(0) def show_image(index): """Display selected image""" global img_index canvas.delete("all") size = (canvas.winfo_width(), canvas.winfo_height()) if images: img_index = index % len(images) image = images[img_index].copy() # Keep original image image.thumbnail(size) image = ImageTk.PhotoImage(image) canvas.create_image( size[0] / 2, size[1] / 2, anchor=tk.CENTER, image=image ) canvas.image = image else: canvas.create_text( size[0] / 2, size[1] / 2, anchor=tk.CENTER, text="No Images", fill="white", font=('Helvetica 15 bold') ) def rotate_image(): """Rotate selected image 90 degrees""" if images: images[img_index] = images[img_index].rotate(-90, expand=True) show_image(img_index) images = [] img_index = 0 root = tk.Tk() canvas = tk.Canvas(root, bg="black") canvas.bind("<Configure>", lambda event: show_image(img_index)) canvas.pack(padx=10, pady=10, side=tk.TOP, expand=True, fill=tk.BOTH) bbar = tk.Frame(root) bbar.pack(side=tk.TOP, fill=tk.X, padx=10, pady=(0, 10)) button = tk.Button(bbar, text="<<", command=lambda: show_image(img_index-1)) button.pack(side=tk.LEFT) button = tk.Button(bbar, text="Select PDF", command=select_pdf_file) button.pack(side=tk.LEFT, expand=True, fill=tk.X) button = tk.Button(bbar, text="Select Folder", command=select_folder) button.pack(side=tk.LEFT, expand=True, fill=tk.X) button = tk.Button(bbar, text="Rotate Image", command=rotate_image) button.pack(side=tk.LEFT, expand=True, fill=tk.X) button = tk.Button(bbar, text=">>", command=lambda: show_image(img_index+1)) button.pack(side=tk.LEFT) root.mainloop()