Tkinker and online resizing of .jpg with Pillow (PIL) - python

Trying to include a slider to resize images online in a Tkinker-GUI-Application of python.
Problem: Canvas Resizing works, Inital Show of original sized image, too. But when using the slider the picture is not resized - it just shows very short in the adjusted size and is then somehow "overwritten" by the original one.
from tkinter import *
from turtle import width
from PIL import Image, ImageTk
import FileDownloader
window = Tk()
window.title ('Price Catcher')
#PIL to open a jpg and store a Tk compatible objekct
headerpic = Image.open("./10374_0.jpg")
def resizePictures(scalerValue):
print(scalerValue)
print(window.canvas.find_all())
headerpicTk = ImageTk.PhotoImage(headerpic.resize((int(scalerValue), int(scalerValue)), Image.ANTIALIAS))
window.canvas.config(width=int(scalerValue), height=int(scalerValue))
#window.canvas.delete("all")
canvas_id = window.canvas.create_image(0,0, anchor=NW, image=headerpicTk)
window.canvas.update()
#Picture Resizer
PicResizeScale = IntVar() #Control Variable to use for Picture Resizing Value of Scaler
window.scale = Scale(window, label='Bildgröße in %', orient=HORIZONTAL, resolution=10, length=300, from_=0, to=200, command=resizePictures)
window.scale.set(100)
window.scale.pack(side=TOP)
#PIL to open a jpg and store a Tk compatible objekct
headerpic = Image.open("./10374_0.jpg")
headerpicTk = ImageTk.PhotoImage(headerpic)
#Place the opject to the canvas
window.canvas = Canvas(window, width=100, height=100)
window.canvas.pack()
canvas_id = window.canvas.create_image(0,0, anchor=NW, image=headerpicTk)
window.downloadbutton = Button(window, text='Download Bild', command=FileDownloader.FileDownloader("https://www.silbertresor.de/images/product_images/info_images/10374_0.jpg", ".\\10374_0.jpg"), justify= LEFT)
window.downloadbutton.pack(side = BOTTOM)
window.exitbutton = Button(window, text='Schließen', command=exit, justify= RIGHT)
window.exitbutton.pack(side= BOTTOM)
window.mainloop()
Any hints - i'm lost :(..

PhotoImage has bug which removes image when it is assigned to local variable in function.
And inside resizePictures you assign new PhotoImage to local variable headerpicTk.
You have to add global headerpicTk to assign PhotoImage to global variable headerpicTk.
def resizePictures(scalerValue):
global headerpicTk
print(scalerValue)
# ...rest ...
That's all.

Related

How do I keep this image in the center of the window?

I'm making a hangman-like game; for that, I need all the different stages of the man to be visualized, hence images. I want the entire tkinter window to be an image, when I change the size it pushes the image right.
from tkinter import *
root=Tk()
root.geometry("600x350")
canvas = Canvas(root, width=1600, height=900)
canvas.pack()
img = PhotoImage(file="4.png")
canvas.create_image(470,190, image=img, )
root.mainloop()
If canvas is bigger than window then when you resize then it show more canvas but and it can looks like it moves image.
But if you use smaller canvas then pack() will try to keep centered horizontally. And if you add pack(expand=True) then it will try to keep it centered vertically.
In example code I added red background to window to show where is canvas
import tkinter as tk # PEP8: import *
root = tk.Tk()
root.geometry("600x350")
root['bg'] = 'red'
img = tk.PhotoImage(file="lenna.png")
canvas = tk.Canvas(root, width=600, height=350)
canvas.pack(expand=True)
canvas.create_image(300, 175, image=img)
root.mainloop()
Image Lenna from Wikipedia
PEP 8 -- Style Guide for Python Code
Before resizing:
After resizing:
If you want to draw only image then you could use Label(image=img)
import tkinter as tk # PEP8: import *
root = tk.Tk()
root.geometry("600x350")
root['bg'] = 'red'
img = tk.PhotoImage(file="lenna.png")
label = tk.Label(root, image=img)
label.pack(expand=True)
root.mainloop()
Before resizing:
After resizing:
BTW:
tkinter can bind() some function to event <Configure> and it will execute this function everytime when you resize window (and/or move window) - and this function may also move or resize image in window.
import tkinter as tk # PEP8: import *
from PIL import Image, ImageTk
def resize(event):
global img
lower = min(event.width, event.height)
#print(event.width, event.height, 'lower:', lower)
new_image = original_image.resize((lower, lower))
img = ImageTk.PhotoImage(new_image) # need to assign to global variable because there is bug in PhotoImage
label['image'] = img
# --- main ---
root = tk.Tk()
root.geometry("350x350")
root['bg'] = 'red'
original_image = Image.open("lenna.png")
img = ImageTk.PhotoImage(original_image)
label = tk.Label(root, image=img)
label.pack(expand=True)
root.bind('<Configure>', resize)
root.mainloop()
Before (it resized image at start to fit window):
After (it resized image to fit window):

Tkinter - rotate image with slider simultaneously

UPDATED -
New to tkinter
Is it possible to rotate a picture by using a slider simultaneously.
I have an image of a rotatory dial, beneath this image is a slider listed from 0 to 360. I would like the image to rotate clockwise as the slider is moved from 0 to 360, and anticlockwise as the slider is returned from 360 to 0.
ROTATION OF IMAGE WITH SLIDER WORKS CORRECTLY
I have ran into a bug, the image is black. Perhaps the image is too zoomed in? Apologies, I am new to python and tkinter.
Here is how the GUI should look Correct GUI
THIS IS HOW THE GUI LOOKS NOW Incorrect GUI with Slider
THIS IS HOW THE GUI LOOKS REMOVING THUMBNAIL LINE THUMBNAIL
Here is the updated code
# import necessary modules
from tkinter import *
from tkinter import ttk
from PIL import Image, ImageTk
root = Tk()
root.title("Gesture Detection Application")
root.geometry("400x320") # set starting size of window
root.maxsize(400, 320) # width x height
root.config(bg="#6FAFE7") # set background color of root window
Heading = Label(root, text="Demonstrator Application2", bg="#2176C1", fg='white', relief=RAISED)
Heading.pack(ipady=5, fill='x')
Heading.config(font=("Font", 20)) # change font and size of label
image = Image.open("rotate_dial.png")
width, height = image.size
image.thumbnail((width/5, height/5))
photoimage = ImageTk.PhotoImage(image)
image_label = Label(root, image=photoimage, bg="white", relief=SUNKEN)
image_label.image = photoimage
image_label.pack(pady=5)
def rotate_image(degrees):
new_image = image.rotate(-int(degrees))
photoimage = ImageTk.PhotoImage(new_image)
image_label.image = photoimage #Prevent garbage collection
image_label.config(image = photoimage)
w2 = Scale(root, from_=0, to=360, tickinterval= 30, orient=HORIZONTAL, length=300, command = rotate_image)
w2.pack()
w2.set(0)
root.mainloop()
You can rotate the image using PIL (which you've already imported). You can link it to the Scale by adding a command.
image = Image.open("rotate_dial.png")
width, height = image.size
image.thumbnail((width/5, height/5))
photoimage = ImageTk.PhotoImage(image)
image_label = Label(root, image=photoimage, bg="white", relief=SUNKEN)
image_label.pack(pady=5)
def rotate_image(degrees):
new_image = image.rotate(-int(degrees))
photoimage = ImageTk.PhotoImage(new_image)
image_label.image = photoimage #Prevent garbage collection
image_label.config(image = photoimage)
w2 = Scale(root, from_=0, to=360, tickinterval= 30, orient=HORIZONTAL, length=300, command = rotate_image)
Instead of creating a PhotoImage initially, it now creates a PIL Image object. It then uses the height and width and the thumbnail function to replace the subsample. Then it uses ImageTk to turn it into a tkinter PhotoImage which is shown in the label. The Scale now has a command, rotate_image, which recieves the scale value, which is the number of degrees, and then uses PIL to create a new rotated image, which is then turned into a PhotoImage and displayed in the label by changing it's image with .config. Now when you move the slider, the image rotates with it.

How do I make a clickable image that gives me the coordinates of the click?

I am trying to make a slideshow-like program using the tkinter module. Here is what I have done:
from tkinter import *
root = Tk()
photo = PhotoImage(file = "image.jpeg")
w = Label(root, image=photo)
w.pack()
def callback(event):
print ("clicked at", event.x, event.y)
##canvas= Canvas(root, width=800, height=500)
canvas= Canvas(root)
canvas.bind("<Button-1>", callback)
canvas.pack()
root.mainloop()
what's going on:
I am putting a picture on the canvas.
I am also detecting left clicks and getting the coordinates (which are printed on the shell)
But what really happens:
The picture (which needs to be in the same folder as the script, btw) appears on top, and a little blank space appears underneath, and I can click that (and get coordinates for the click). If I click the picture, nothing happens. When I click the blank space, it only gives the coordinates of the click for the blank space, not counting the picture as part of the area. If I enlarge the window, it just adds inert blank space on the sides, that do not react to being clicked.
My question is, how do I get the picture to be the clickable part (meaning, gets coordinates as well), and remove the blank space
If you can get the picture to enlarge with the window, that's even better.
Python 3.7.3, on MacBook. I only have the standard library.
You don't need the canvas and should bind on the label instead. Note that tkinter.PhotoImage() does not support JPEG image, use PNG or use Pillow module instead.
from tkinter import *
from PIL import ImageTk
root = Tk()
photo = ImageTk.PhotoImage(file="image.jpeg")
w = Label(root, image=photo)
w.pack()
def callback(event):
print ("clicked at", event.x, event.y)
w.bind("<Button-1>", callback)
root.mainloop()
You are not actually placing the image on the canvas. To place the image on the canvas use
.create_image(). To resize the image to the canvas. you can use resize method provided by the PIL library.
from tkinter import *
from PIL import ImageTk, Image
def resize_event(event):
resized = ImageTk.PhotoImage(img.resize((event.width, event.height), resample = Image.NEAREST))
canvas.itemconfig(img_item, image=resized)
canvas.moveto(img_item, 0, 0)
canvas.image = resized
def callback(event):
print ("clicked at", event.x, event.y)
root = Tk()
img = Image.open(r"Imagepath")
photo = ImageTk.PhotoImage(img)
#w = Label(root, image=photo)
#w.pack()
##canvas= Canvas(root, width=800, height=500)
canvas= Canvas(root)
img_item = canvas.create_image(0, 0, image = photo)
canvas.bind("<Button-1>", callback)
canvas.bind('<Configure>', resize_event)
canvas.pack(expand=True, fill='both')
root.mainloop()

Is it possible to provide animation on image ? - Tkinter

I'm developing a GUI in Tkinter and want to apply animation in the below GIF on the image when it appears.
Here is my code,
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
frame = Frame(root)
frame.pack()
canvas = Canvas(frame, width=300, height=300, bd=0, highlightthickness=0, relief='ridge')
canvas.pack()
background = PhotoImage(file="background.png")
canvas.create_image(300,300,image=background)
my_pic = PhotoImage(file="start000-befored.png")
frame.after(1000, lambda: (canvas.create_image(50,50,image=my_pic, anchor=NW))) #and on this image, I want to give the effect.
root.mainloop()
Instead of clicking on the play button as shown in GIF, the image should automatically appears after 1 second like this animation and stays on screen. (No closing option).
I'm not 100% sure I understood the problem, but I'll describe how to animate an image.
Tkinter does not contain functions for animating images so you'll have to write them yourself. You will have to extract all subimages, subimage duration and then build a sequencer to swap subimages on your display.
Pillow can extract image sequences. WEBP images seems to only support one frame duration whereas GIF images may have different frame duration for each subimage. I will use only the first duration for GIF images even if there is many. Pillow does not support getting frame duration from WEBP images as far as I have seen but you gan read it from the file, see WebP Container Specification.
Example implementation:
import tkinter as tk
from PIL import Image, ImageTk, ImageSequence
import itertools
root = tk.Tk()
display = tk.Label(root)
display.pack(padx=10, pady=10)
filename = 'images/animated-nyan-cat.webp'
pil_image = Image.open(filename)
no_of_frames = pil_image.n_frames
# Get frame duration, assuming all frame durations are the same
duration = pil_image.info.get('duration', None) # None for WEBP
if duration is None:
with open(filename, 'rb') as binfile:
data = binfile.read()
pos = data.find(b'ANMF') # Extract duration for WEBP sequences
duration = int.from_bytes(data[pos+12:pos+15], byteorder='big')
# Create an infinite cycle of PIL ImageTk images for display on label
frame_list = []
for frame in ImageSequence.Iterator(pil_image):
cp = frame.copy()
frame_list.append(cp)
tkframe_list = [ImageTk.PhotoImage(image=fr) for fr in frame_list]
tkframe_sequence = itertools.cycle(tkframe_list)
tkframe_iterator = iter(tkframe_list)
def show_animation():
global after_id
after_id = root.after(duration, show_animation)
img = next(tkframe_sequence)
display.config(image=img)
def stop_animation(*event):
root.after_cancel(after_id)
def run_animation_once():
global after_id
after_id = root.after(duration, run_animation_once)
try:
img = next(tkframe_iterator)
except StopIteration:
stop_animation()
else:
display.config(image=img)
root.bind('<space>', stop_animation)
# Now you can run show_animation() or run_animation_once() at your pleasure
root.after(1000, run_animation_once)
root.mainloop()
There are libraries, like imgpy, which supports GIF animation but I have no experience in usig any such library.
Addition
The duration variable sets the animation rate. To slow the rate down just increase the duration.
The simplest way to put the animation on a canvas it simply to put the label on a canvas, see example below:
# Replace this code
root = tk.Tk()
display = tk.Label(root)
display.pack(padx=10, pady=10)
# with this code
root = tk.Tk()
canvas = tk.Canvas(root, width=500, height=500)
canvas.pack(padx=10, pady=10)
display = tk.Label(canvas)
window = canvas.create_window(250, 250, anchor='center', window=display)
Then you don't have to change anything else in the program.

How to make background Transparent in TKinter by converting Label widget into Canvas widget?

I have a code that is working perfectly but it's not giving me transparent background, (here is the image ) after a research on web, I found the solution by using canvas widget, we can us images with transparent background.
Here is my code,
import tkinter as tk
from PIL import Image, ImageTk
def work(progress=1):
if progress > 300: # define the width by yourself
return
tmp_images = ImageTk.PhotoImage(progress_images.resize((progress, 10))) # the image size
lb.image = tmp_images # keep reference
lb["image"] = tmp_images # change the image
root.add = root.after(100, work, progress+10) # define the amplitude by yourself
root = tk.Tk()
progress_images = Image.open("path.png")
lb = tk.Label(root, bg="black")
lb.pack(side="left")
work()
root.mainloop()
but I am confused how to change Label widget into Canvas ? can anyone help me please ? I am noob in Tkinter still!!!
You can use canvas.create_text(...) to replace the labels and then use canvas.itemconfig(...) to update the labels. I got this from an other stack over flow question
reference link :-
add label ..
Below is a modified code using Canvas:
import tkinter as tk
from PIL import Image, ImageTk
def work(progress=10):
if progress > 300: # define the width by yourself
return
canvas.image = ImageTk.PhotoImage(progress_images.resize((progress, 30))) # the image size
canvas.itemconfig(pbar, image=canvas.image) # update image item
root.add = root.after(100, work, progress+10) # define the amplitude by yourself
root = tk.Tk()
progress_images = Image.open("path.png")
canvas = tk.Canvas(root, width=300, height=30, bg='black', highlightthickness=0)
canvas.pack()
pbar = canvas.create_image(0, 0, anchor='nw') # create an image item
work()
root.mainloop()

Categories