Python Forum
tuple indices must be integers or slices, not str
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
tuple indices must be integers or slices, not str
#10
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 be
Use 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()
Reply


Messages In This Thread
RE: tuple indices must be integers or slices, not str - by deanhystad - Mar-05-2023, 04:09 AM

Possibly Related Threads…
Thread Author Replies Views Last Post
  No matter what I do I get back "List indices must be integers or slices, not list" Radical 4 1,312 Sep-24-2023, 05:03 AM
Last Post: deanhystad
  boto3 - Error - TypeError: string indices must be integers kpatil 7 1,374 Jun-09-2023, 06:56 PM
Last Post: kpatil
  Response.json list indices must be integers or slices, not str [SOLVED] AlphaInc 4 6,599 Mar-24-2023, 08:34 AM
Last Post: fullytotal
  "TypeError: string indices must be integers, not 'str'" while not using any indices bul1t 2 2,128 Feb-11-2023, 07:03 PM
Last Post: deanhystad
  Error "list indices must be integers or slices, not str" dee 2 1,532 Dec-30-2022, 05:38 PM
Last Post: dee
  TypeError: string indices must be integers JonWayn 12 3,604 Aug-31-2022, 03:29 PM
Last Post: deanhystad
  TypeError: list indices must be integers or slices, not range Anldra12 2 2,707 Apr-22-2022, 10:56 AM
Last Post: Anldra12
  string indices must be integers when parsing Json ilknurg 3 6,552 Mar-10-2022, 11:02 AM
Last Post: DeaD_EyE
  code with no tuple gets : IndexError: tuple index out of range Aggam 4 2,913 Nov-04-2020, 11:26 AM
Last Post: Aggam
  TypeError: string indices must be integers hendern 2 3,075 Oct-02-2020, 10:16 PM
Last Post: hendern

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020