![]() |
tuple indices must be integers or slices, not str - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: General Coding Help (https://python-forum.io/forum-8.html) +--- Thread: tuple indices must be integers or slices, not str (/thread-39470.html) Pages:
1
2
|
tuple indices must be integers or slices, not str - cybertooth - Feb-22-2023 I am trying to make a Tkinter GUI with PyMuPDF. however I am geting the error .can some one help fix this. import fitz import tempfile import os import tkinter as tk from PIL import Image, ImageTk # create a temporary directory to store extracted images temp_dir = tempfile.TemporaryDirectory() # open PDF file doc = fitz.open('G:\\Patient OPG\\Arshita Nagpal\\CBCT 48,38\\Axials.pdf') # iterate over pages for page_index in range(doc.page_count): # get the page page = doc[page_index] # iterate over images for image_index, img in enumerate(page.get_images()): # get the image extension image_ext = img['str'] # get the pixmap pixmap = page.get_pixmap(image_index) # get the image data image_data = pixmap.tobytes() # save the image to the temporary directory image_path = os.path.join(temp_dir.name, f"image{page_index+1}_{image_index}.{image_ext}") pixmap.save(image_path) ## with open(image_path, 'wb') as f: ## f.write(image_data) # create a tkinter window root = tk.Tk() # iterate over extracted images and display them in the tkinter window for image_file in os.listdir(temp_dir.name): image_path = os.path.join(temp_dir.name, image_file) # open image with PIL image = Image.open(image_path) # convert image to tkinter-compatible format photo = ImageTk.PhotoImage(image) # create a label with the image and add it to the tkinter window label = tk.Label(root, image=photo) label.pack() # start the tkinter mainloop root.mainloop() # delete the temporary directory temp_dir.cleanup() RE: tuple indices must be integers or slices, not str - menator01 - Feb-22-2023 What do you get when you print this? image_ext = img['str'] RE: tuple indices must be integers or slices, not str - deanhystad - Feb-22-2023 Post entire error including traceback. What do you think this does? image_ext = img['str']This looks like indexing for a dictionary, but from all the examples I can find, img uses integer indexing, not key indexing. From the documentation: https://pymupdf.readthedocs.io/en/latest/recipes-images.html Quote:The question remains: “How do I know those ‘xref’ numbers of images?”. There are two answers to this: RE: tuple indices must be integers or slices, not str - cybertooth - Feb-23-2023 Yes 'img' is a dictionary object. So why am I getting a tuple error. I went through the documentation but am unable to completely understand it so as to implement it in my code. using the documentation I am able to extract images from the pdf file and save them in the parent directory on my hard drive. The problem arises when I am trying to create a temporary folder within the program to store the images and access them to be displayed in tkinter window. (Feb-22-2023, 10:15 PM)deanhystad Wrote: Post entire error including traceback. RE: tuple indices must be integers or slices, not str - deanhystad - Feb-24-2023 The documentation says get_images() returns a list of lists (or tuples), not a list of dictionaries. If you print(img) you will see it is a tuple, not a dictionary. import fitz for page in fitz.open('test.pdf'): for img in page.get_images(): print(type(img), img) This agrees with the documentation. Page.get_images() returns a list of tuples.Maybe you skipped a step. To get the image you need to extract the image using the xref. The xref is the first element in the tuples returned by get_images. import fitz doc = fitz.open('test.pdf'): for page in doc: for xref, *_in page.get_images(): image = doc.extract_image(xref) # Extract the image print(image.keys()) Now we have a dictionary, but there is still not a key named 'str'. However, there is a key named 'ext'.import fitz doc = fitz.open('test.pdf'): for page in doc: for xref, *_in page.get_images(): print(doc.extract_image(xref)['ext']) My images are jpegs.
RE: tuple indices must be integers or slices, not str - deanhystad - Feb-26-2023 For fun I combined this thread with your other thread about a tkinter app that displays images: https://python-forum.io/thread-39420.html This is a tkinter app that displays images extracted from a pdf file. And for some bizarre reason they start spinning when clicked. import math import statistics import fitz import numpy as np import tkinter as tk from tkinter import filedialog, messagebox from PIL import Image, ImageTk from io import BytesIO IMAGE_SIZE = (100, 100) # Resize all images to this size LABEL_SIZE = 140 # Max size of rotated image class SpinningImageButton(tk.Frame): """A Button that has an image you can rotate""" def __init__(self, parent, image, *args, frames=20, command=None, **kwargs): super().__init__(parent, *args, **kwargs) self.running = False self.index = 0 self.command = command # Guess a fill color using the the top row of pixels pixels = [tuple(p) for p in np.array(image)[0]] rgb = statistics.mode(pixels)[:3] # Create movie frames image.thumbnail(IMAGE_SIZE) angle = 360 / frames self.images = [ ImageTk.PhotoImage(image.rotate(i*angle, fillcolor=rgb, expand=True)) for i in range(frames) ] # Make a label to display the image. self.image = tk.Label( self, image=self.images[0], width=LABEL_SIZE, height=LABEL_SIZE, bg=f'#{rgb[0]:02x}{rgb[1]:02x}{rgb[2]:02x}') self.image.pack(anchor=tk.CENTER) self.image.bind('<Button-1>', func=self._click) def _click(self, *args): """Called when mouse clicks on me""" if self.command: self.command(self) def _next(self, wait): """Display successive images to make it appear the image is spinning""" if self.running: self.index = (self.index + 1) % len(self.images) self.image.config(image=self.images[self.index]) self.after(wait, self._next, wait) def start(self, period=2): """Start spinning the image""" self.running = True self._next(int(period * 1000 / len(self.images))) def stop(self): """Stop spinning the image""" self.running = False class MyWindow(tk.Tk): """Window to show off my fancy spinning buttons""" def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) # Make a menubar instead of a bunch of buttons menubar = tk.Menu(self) menu = tk.Menu(menubar, tearoff=0) menubar.add_cascade(label="File", menu=menu) menu.add_command(label="Open PDF", command=self.open_pdf) menu.add_separator() menu.add_command(label="Quit", command=self.destroy) self.config(menu=menubar) self.images = [] self.frame = tk.Frame(self, width=300, height=300) self.frame.pack(expand=True, fill=tk.BOTH) def open_pdf(self): """Populate window with images extracted from pdf file""" pdf = filedialog.askopenfilename() if pdf: # Replace old image buttons with new for image in self.images: image.grid_forget() self.images = [] try: doc = fitz.open(pdf) for page in doc: for xref, *_ in page.get_images(): image_bytes = doc.extract_image(xref)["image"] image = Image.open(BytesIO(image_bytes)) self.images.append( SpinningImageButton( self.frame, image, frames=60, command=self.toggle ) ) except Exception as msg: messagebox.showerror('Error', str(msg)) # Organize the images on a grid. cols = int(math.ceil(len(self.images)**0.5)) for i, image in enumerate(self.images): image.grid(row=i // cols, column=i % cols) def toggle(self, image): """Toggle image spinning on/off when button clicked""" if image.running: image.stop() else: image.start() MyWindow().mainloop() RE: tuple indices must be integers or slices, not str - cybertooth - Feb-28-2023 Thanks deanhystad, I got this sample code and modified it . It works fine extracts the images and saves them in a temp folder and then displays them in the tkinter window. import fitz # PyMuPDF import io import os import tempfile from PIL import Image import tkinter as tk from tkinter import ttk from PIL import ImageTk # file path you want to extract images from file = 'G:\\Patient OPG\\Arshita Nagpal\\CBCT 48,38\\Axials.pdf' # open the file pdf_file = fitz.open(file) # create temporary folder to save images with tempfile.TemporaryDirectory() as temp_folder: # iterate over PDF pages for page_index in range(len(pdf_file)): # get the page itself page = pdf_file[page_index] # get image list image_list = page.get_images() # printing number of images found in this page if image_list: print(f"[+] Found a total of {len(image_list)} images in page {page_index}") else: print("[!] No images found on page", page_index) for image_index, img in enumerate(image_list, start=1): # get the XREF of the image xref = img[0] # extract the image bytes base_image = pdf_file.extract_image(xref) image_bytes = base_image["image"] # get the image extension image_ext = base_image["ext"] # load it to PIL image = Image.open(io.BytesIO(image_bytes)) # save it to temporary folder image.save(os.path.join(temp_folder, f"image{page_index+1}_{image_index}.{image_ext}")) print(f"[+] All images saved to {temp_folder}") # create a window using Tkinter root = tk.Tk() root.title("Extracted Images") # create a label to display the images image_label = ttk.Label(root) image_label.pack() # iterate over the image files in the temporary folder and display them image_files = sorted(os.listdir(temp_folder)) global current_index current_index = 0 pil_image = Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) image_label.configure(image=tk_image) def on_key_press(event): global current_index if event.keysym == "Right": current_index = (current_index + 1) % len(image_files) pil_image = Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) image_label.configure(image=tk_image) image_label.image = tk_image elif event.keysym == "Left": current_index = (current_index - 1) % len(image_files) pil_image = Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) image_label.configure(image=tk_image) image_label.image = tk_image # bind the left and right arrow keys to change the displayed image root.bind("<Left>", on_key_press) root.bind("<Right>", on_key_press) # start the Tkinter event loop root.mainloop() (Feb-26-2023, 02:12 PM)deanhystad Wrote: For fun I combined this thread with your other thread about a tkinter app that displays images: How ever when I try to add a select button the select button is seen in the GUI , allows you to select a pdf file and displays only the first image and when arrow keys are pressed I get the error message.. here I am posting the second code and the error message . Can some one help solve this. import fitz # PyMuPDF import io import os import tempfile import PIL.Image from PIL import ImageTk import tkinter as tk from tkinter import filedialog from tkinter import* root=Tk() # function to extract images from the PDF file def extract_images(file_path): # open the file pdf_file = fitz.open(file_path) # create temporary folder to save images with tempfile.TemporaryDirectory() as temp_folder: # iterate over PDF pages for page_index in range(len(pdf_file)): # get the page itself page = pdf_file[page_index] # get image list image_list = page.get_images() # printing number of images found in this page if image_list: print(f"[+] Found a total of {len(image_list)} images in page {page_index}") else: print("[!] No images found on page", page_index) for image_index, img in enumerate(image_list, start=1): # get the XREF of the image xref = img[0] # extract the image bytes base_image = pdf_file.extract_image(xref) image_bytes = base_image["image"] # get the image extension image_ext = base_image["ext"] # load it to PIL image = Image.open(io.BytesIO(image_bytes)) # save it to temporary folder image.save(os.path.join(temp_folder, f"image{page_index+1}_{image_index}.{image_ext}")) print(f"[+] All images saved to {temp_folder}") # call the function to display images after a delay of 500ms root.after(500, display_images, temp_folder) # function to display the images def display_images(temp_folder): # iterate over the image files in the temporary folder and display them image_files = sorted(os.listdir(temp_folder)) global current_index current_index = 0 # create a canvas to display the images canvas = tk.Canvas(root, width=600, height=600) canvas.pack() # display the first image pil_image = Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) canvas.create_image(0, 0, anchor="nw", image=tk_image) def on_key_press(event): global current_index if event.keysym == "Right": current_index = (current_index + 1) % len(image_files) pil_image = Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) canvas.create_image(0, 0, anchor="nw", image=tk_image) elif event.keysym == "Left": current_index = (current_index - 1) % len(image_files) pil_image = Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) canvas.create_image(0, 0, anchor="nw", image=tk_image) # bind the canvas to the key press event canvas.bind("<KeyPress>", on_key_press) # set the focus on the canvas so that it can receive the key press events canvas.focus_set() # function to get the path of the PDF file def select_pdf_file(): # open file dialog to choose a PDF file file_path = filedialog.askopenfilename(filetypes=[("PDF Files", "*.pdf")]) if file_path: # open the file pdf_file = fitz.open(file_path) # create temporary folder to save images with tempfile.TemporaryDirectory() as temp_folder: # iterate over PDF pages for page_index in range(len(pdf_file)): # get the page itself page = pdf_file[page_index] # get image list image_list = page.get_images() # printing number of images found in this page if image_list: print(f"[+] Found a total of {len(image_list)} images in page {page_index}") else: print("[!] No images found on page", page_index) for image_index, img in enumerate(image_list, start=1): # get the XREF of the image xref = img[0] # extract the image bytes base_image = pdf_file.extract_image(xref) image_bytes = base_image["image"] # 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_folder, f"image{page_index+1}_{image_index}.{image_ext}")) print(f"[+] All images saved to {temp_folder}") # iterate over the image files in the temporary folder and display them image_files = sorted(os.listdir(temp_folder)) global current_index current_index = 0 show_image(temp_folder, image_files[current_index]) def on_key_press(event): global current_index if event.keysym == "Right": current_index = (current_index + 1) % len(image_files) pil_image = PIL.Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) image_label.config(image=tk_image) elif event.keysym == "Left": current_index = (current_index - 1) % len(image_files) pil_image = PIL.Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) image_label.config(image=tk_image) root.bind("<Key>", on_key_press) def show_image(folder, file_name): pil_image = PIL.Image.open(os.path.join(folder, file_name)) tk_image = ImageTk.PhotoImage(pil_image) print(tk_image) image_label = tk.Label(root) image_label.pack() image_label.config(image=tk_image) image_label.image = tk_image # create button to select a PDF file select_file_button = tk.Button(root, text="Select PDF File", command=select_pdf_file) select_file_button.pack() root.mainloop()
RE: tuple indices must be integers or slices, not str - deanhystad - Feb-28-2023 https://docs.python.org/3/library/tempfile.html Quote:class tempfile.TemporaryDirectory(suffix=None, prefix=None, dir=None, ignore_cleanup_errors=False) In other words, as soon as you leave the context created by this: with tempfile.TemporaryDirectory() as temp_folder:The temporary directory is deleted. There is no need to write the image data to files. Create the images and keep them in a list. If you want to write files to a temporary directory, you could wrap you program in the temp_folder context. with tempfile.TemporaryDirectory() as temp_folder: window = function_that_creates_your_main_window() window.mainloop()Or you could make temp_folder a global variable def select_pdf_file(): global temp_folder, current_index file_path = filedialog.askopenfilename(filetypes=[("PDF Files", "*.pdf")]) if file_path: pdf_file = fitz.open(file_path) current_index = 0 temp_folder = tempfile.TemporaryDirectory() image_index = 0 for page in pdf_file: for xref, *_ in page.get_images(): # extract the image info = pdf_file.extract_image(xref) image = PIL.Image.open(io.BytesIO(info ["image"])) #<- Why not put this in a list?? image_file = os.path.join(temp_folder.name, f"image{image_index}.{info ["ext"]}") image.save(os.path.join(temp_folder.name, image_file)) show_image(temp_folder.name, image_file) image_index += 1Making temp_folder a global variable means the temporary folder stays alive until you reassign the temp_folder variable (no reference->delete folder), exit the program, or call the cleanup() function (temp_folder.cleanup()). One last thing, this does not belong inside select_pdf_file() def on_key_press(event): global current_index if event.keysym == "Right": current_index = (current_index + 1) % len(image_files) pil_image = PIL.Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) image_label.config(image=tk_image) elif event.keysym == "Left": current_index = (current_index - 1) % len(image_files) pil_image = PIL.Image.open(os.path.join(temp_folder, image_files[current_index])) tk_image = ImageTk.PhotoImage(pil_image) image_label.config(image=tk_image) root.bind("<Key>", on_key_press)You can embed a function inside another function, but you should only do this with "helper" functions, or if you are making a closure. I don't think either applies in this case. RE: tuple indices must be integers or slices, not str - cybertooth - Mar-03-2023 Thanks deanhystad . I rewrote the whole script and its working. However I have a few issues. 1) There seems to be lag in loading of the first image. 2) I would like to have the exit button to stop the program and allow for a new file/ folder to be selected . import fitz # PyMuPDF import io import os import tempfile import PIL.Image from PIL import ImageTk import tkinter as tk from tkinter import filedialog from tkinter import * root = tk.Tk() root.title("Viewer") photo=PhotoImage(file="C:\\Users\\INDIAN\Desktop\\python exercises\\Viewer\\Logo Viewer.png") label = Label(root,image = photo,bg="light blue") label.image = photo # keep a reference! label.grid(column=12,row=1,rowspan=2 ,ipadx=5, ipady=5,sticky=tk.W) root.geometry("1200x800") root.configure(background='light blue') tk.Label(root, text="Viewer",font="Algerian 20 bold",bg="light blue").grid(column=12,row=1, ipadx=150, ipady=10,sticky=tk.NE) canvas = tk.Canvas(root, width=800, height=600,bg='black') canvas.grid(column=1,row=1,columnspan=10,ipadx=10,ipady=10,sticky=tk.NW) ############################################################################################ # Create a temporary directory temp_dir = tempfile.TemporaryDirectory() print(f"[+] All images saved to {temp_dir}") ############################################################################################### def select_pdf_file(): global images # open file dialog to choose a PDF file file_path = filedialog.askopenfilename(filetypes=[("PDF Files", "*.pdf")]) if file_path: # open the file pdf_file = fitz.open(file_path) for page_index in range(len(pdf_file)): # get the page itself page = pdf_file[page_index] # get image list image_list = page.get_images() # printing number of images found in this page if image_list: print(f"[+] Found a total of {len(image_list)} images in page {page_index}") else: print("[!] No images found on page", page_index) for image_index, img in enumerate(image_list, start=1): # get the XREF of the image xref = img[0] # extract the image bytes base_image = pdf_file.extract_image(xref) image_bytes = base_image["image"] # 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}")) print(f"[+] All images saved to {temp_dir}") # iterate over the image files in the temporary folder and display them image_files = sorted(os.listdir(temp_dir.name)) global current_index current_index = 0 images = [] for filename in os.listdir(temp_dir.name): if filename.endswith('.png') or filename.endswith('.bmp') or filename.endswith('.jpg') or filename.endswith('.bmp') or filename.endswith('.dcm'): images.append(os.path.join(temp_dir.name, filename)) if images: show_image(0, images) #################################################################################################### def select_folder(): global images global folder_path # Open a file dialog to select the folder folder_path = filedialog.askdirectory() # Load the images from the selected folder images=[] for filename in os.listdir(folder_path): if filename.endswith('.png') or filename.endswith('.bmp') or filename.endswith('.jpg') or filename.endswith('.bmp') or filename.endswith('.dcm'): images.append(os.path.join(folder_path,filename)) show_image(0, images) global current_index current_index = 0 ###################################################################################################### def show_image(index, images): global current_index current_index = index image_path = images[index] image = PIL.Image.open(image_path) image = image.resize((800, 600)) photo = ImageTk.PhotoImage(image) canvas.create_image(0, 0, anchor=tk.NW, image=photo) canvas.image = photo current_index = index ###################################################################################################### def on_left_arrow(event): global current_index if current_index > 0: current_index -= 1 show_image(current_index, images) def on_right_arrow(event): global current_index if current_index < len(images) - 1: current_index += 1 show_image(current_index, images) def exit_program(): root.destroy() ########################################################################## # Set the initial image current_image = 0 ## Button & packing it and assigning it a command tk.Button(text=" Select PDF ", command=select_pdf_file).grid(row=13, column=11) button1 = tk.Button(root, text="Select Folder", command=select_folder).grid(row=13,column=12) button2 = tk.Button(root, text="Exit", command=select_folder).grid(row=13,column=12,padx=60,pady=0,sticky=tk.W) # bind the arrow keys to navigate the images root.bind('<Left>', on_left_arrow) root.bind('<Right>',on_right_arrow) ##Button(text=" Select File ",command=select_pdf_file).grid(row=13, column=3) root.mainloop() (Feb-28-2023, 05:04 PM)deanhystad Wrote: https://docs.python.org/3/library/tempfile.html RE: tuple indices must be integers or slices, not str - deanhystad - Mar-05-2023 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. 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() |