How to rotate an image on a canvas without using P

2019-08-01 04:24发布

Is there any simple way to rotate an imported image on a tkinter canvas? I'd rather not use the PIL module, but I can't find any viable alternatives. (If it helps, I want to rotate some car images when they take a turn on a crossroad.)

2条回答
放我归山
2楼-- · 2019-08-01 04:34

Big thanks to @acw1668's answer on this page, which helped me to develop this more efficient solution.

It turns out the PhotoImage.put() method accepts string data and will write whatever pattern you give it as a string, on loop, to fill a given area within an image. So, instead of having to read each pixel one by one, and then write each pixel one by one, we can read each pixel and then write just once!

The function below allows you to rotate and mirror any PhotoImage object and does so in a fraction of the time that the pixel-for-pixel, read-write method does. Mirroring is accomplished by simply reading each row or column from back to front. Rotation writes each row as a column, which effectively turns the image 90 degrees.

import tkinter as tk

def putToImage(brush, canvas, bbox, mirror_x=False, mirror_y=False, rotate=False):
    value1 = brush.height() if rotate else brush.width()
    value2 = brush.width() if rotate else brush.height()
    start1, end1, increment1 = (value1 - 1, -1, -1) if mirror_x else (0, value1, 1)
    start2, end2, increment2 = (value2 - 1, -1, -1) if mirror_y else (0, value2, 1)

    data = ""
    for col in range(start2, end2, increment2):
        data = data + "{"
        for row in range(start1, end1, increment1):
            data = data + "#%02x%02x%02x " % brush.get(col if rotate else row, row if rotate else col)
        data = data + "} "
    canvas.put(data, to=bbox)

And here's a simple example of usage:

window = tk.Tk()
lbl1 = tk.Label(window)
lbl2 = tk.Label(window)

my_img = tk.PhotoImage(file="my_image.png")
rotated_img = tk.PhotoImage(width=my_img.height(), height=my_img.width())
putToImage(my_img, rotated_img, (0, 0, rotated_img.width(), rotated_img.height()), rotate=True)

lbl1.configure(image=my_img)
lbl1.pack()
lbl2.configure(image=rotated_img)
lbl2.pack()

window.mainloop()  
查看更多
老娘就宠你
3楼-- · 2019-08-01 04:47

Below is a simple but not efficient method to rotate a PhotoImage 90 (right), 180 and 270 (left) degrees:

def rotate_image(img, dir):
    w, h = img.width(), img.height()
    if dir in ['left', 'right']:
        newimg = PhotoImage(width=h, height=w)
    else: # 180 degree
        newimg = PhotoImage(width=w, height=h)
    for x in range(w):
        for y in range(h):
            rgb = '#%02x%02x%02x' % img.get(x, y)
            if dir == 'right': # 90 degrees
                newimg.put(rgb, (h-y,x))
            elif dir == 'left': # -90 or 270 degrees
                newimg.put(rgb, (y,w-x))
            else: # 180 degrees
                newimg.put(rgb, (w-x,h-y))
    return newimg
查看更多
登录 后发表回答