Search code examples
pythonpython-3.xtkinterpython-imaging-library

How do I flip (reflect/mirror) an image on a tkinter canvas?


I already have an image displayed on a tkinter Canvas using the Canvas.create_image() method.

I want to now flip the image after calling the create_image() method. I have the ID of the canvas object and also the filepath of the original image. So I want the existing canvas image to be replaced with a horizontally mirrored image.

I also want this to be something that can happen an unknown but unlimited number of times in my program, so just getting a PIL Image from the filepath and flipping that image and destroying and redrawing the image wouldn't work because the file itself always stays facing the same direction so after getting flipped once it would never go back to its original state. And also that just seems a bit cumbersome to read the disk every time I want to flip the image; surely it's possible to do it just in memory?

What's the best way of doing this?

Tagging with PIL because I thought PIL might be helpful for doing this, but obviously if it's not necessary to do this then it's not relevant.

Also, my program should be able to run in an environment with only Python standard libraries and possibly PIL if needed, so unfortunately I can't install anything with pip.


Solution

  • Frankly, I don't know what is the problem.

    If you have item_id then you can replace image with

    canvas.itemconfig(item_id, image=tk_flipped_image)
    

    Of course it always needs to use PIL to flip image.

    And if you want to flip the same image many times then you don't have to destroy it.
    Keep both versions in memory.


    Full Working code.

    I use after() to replace image every 1000ms (1s)

    import tkinter as tk
    from PIL import Image, ImageTk
    
    # --- functions ---
    
    def update_image():
        global index 
        
        index = (index + 1) % 2
    
        if index == 0:
            canvas.itemconfig(image_id, image=tk_image_0)
        else:
            canvas.itemconfig(image_id, image=tk_image_1)
        
        root.after(1000, update_image)  # run again after 1000ms
        
    # --- main ---
        
    root = tk.Tk()
    
    pil_image_0 = Image.open("test.png")
    pil_image_1 = pil_image_0.transpose(Image.FLIP_TOP_BOTTOM)   # Image.FLIP_LEFT_RIGHT
    
    tk_image_0 = ImageTk.PhotoImage(pil_image_0)
    tk_image_1 = ImageTk.PhotoImage(pil_image_1)
    
    canvas = tk.Canvas(root, width=pil_image_0.width, height=pil_image_0.height)
    canvas.pack(fill='both', expand='yes')
    
    index = 0
    image_id = canvas.create_image(0, 0, image=tk_image_0, anchor='nw')
    
    root.after(1000, update_image)
    
    root.mainloop()
    

    Result:

    enter image description here