RGBA image not showing up with Pillow and tkinter - python-3.x

I am trying to get a PNGA image to show up in my UI using Pillow and Tkinter. I'm on python 3.7.7 on macOS.
import sys
import tkinter as tk
from PIL import ImageTk, Image
path = "path_to_image.png"
im = Image.open(path)
print(im.mode) # prints RGBA
root = tk.Tk()
root.title("Karel")
frame = tk.Frame(root)
frame.pack()
canvas = tk.Canvas(frame, bg="white", width=500, height=500)
canvas.pack()
img = Image.open(path) # PIL solution
img = img.resize((250, 250), Image.ANTIALIAS) #The (250, 250) is (height, width)
img = ImageTk.PhotoImage(img) # convert to PhotoImage
image = canvas.create_image(150,150, image = img)
root.mainloop()
When I try this with images without an alpha channel, it works. Adding img = ImageTk.PhotoImage(img.convert("RGB")) to remove the alpha channel makes a black box appear.
Any help would be greatly appreciated.
The image:

I don't understand what you are trying to do, but the issue is that all the information in your image is in the alpha (i.e. transparency) channel. I can demonstrate that by splitting out the R, G, B and A channels using ImageMagick in the Terminal like this and laying them out beside each other:
magick image.png -channel RGBA -separate -background none +smush 10 result.png
So, the Red, Green and Blue channels are all zero (i.e. black), and the alpha channel has white where it is transparent and you can see through to the RGB black, and it has black where it is transparent.
So, as regards your question, since all the info is in the alpha channel, you could take just the alpha channel as your image:
#!/usr/bin/env python3
import tkinter as tk
from PIL import ImageTk, Image
root = tk.Tk()
root.title("Karel")
frame = tk.Frame(root)
frame.pack()
canvas = tk.Canvas(frame, bg="red", width=500, height=500)
canvas.pack()
path = "image.png"
img = Image.open(path).getchannel('A') # Take just alpha channel
img = img.point(lambda a: 255-a) # Invert black/white
img = img.resize((250, 250), Image.ANTIALIAS)
img = ImageTk.PhotoImage(img)
image = canvas.create_image(150,150, image = img)
root.mainloop()
Note that you can easily install ImageMagick on macOS with homebrew:
brew install imagemagick
If you work with images, while you are there, get these packages too:
brew install pngcheck exiftool jhead

Related

How can I resize image without stretching it in Tkinter?

I am currently working on a project which requires displaying Images of different sizes. So I wanted to use tkinter for that purpose.
Here is my Code for displaying image
from tkinter import Tk, Label
from PIL import Image, ImageTk
root = Tk()
root.title("Display Images")
root.geometry('550x550')
root.maxsize(550, 550)
root.iconbitmap('icon.ico')
root.configure(background='#333')
image = Image.open('./image.jpg')
resized_image = image.resize((540, 540), Image.ANTIALIAS)
disp_image = ImageTk.PhotoImage(resized_image)
label = Label(image=disp_image) #.pack(padx=10, pady=10)
label.configure(border=0)
label.pack(padx=10, pady=10)
root.mainloop()
which works perfectly fine but
I wanted to display different sizes of images without stretching them.
Like, If image size exceeds the window size, it should take the size of the window, and If image size is less than the size of the window then there should be no change in image size.
Example:
I have two images of width and height [200x300, 400x500]
and my display size(windows width and height) is 350x350
When I display an image of size 200x300, it should display as it is without change in size and when I display another image it should change its size to 350x350
So, is there a way to pull that off?
Here is a solution:
from tkinter import Tk, Label
from PIL import Image, ImageTk
root = Tk()
root.title("Display Images")
root.geometry('550x550')
root.maxsize(550, 550)
root.configure(background='#333')
image = Image.open('./image.jpg')
# main part -----------------------------------------
if image.width > 540 and image.height > 540:
resized_image = image.resize((540, 540), Image.ANTIALIAS)
elif image.width > 540:
resized_image = image.resize((540, image.height), Image.ANTIALIAS)
elif image.height > 540:
resized_image = image.resize((image.width, 540), Image.ANTIALIAS)
else:
resized_image = image
# end main part ----------------------------------------
disp_image = ImageTk.PhotoImage(resized_image)
label = Label(image=disp_image, border=0)
label.pack(padx=10, pady=10)
root.mainloop()
Simple use of if statements.

Is it possible to make an uploaded photo realtive in tkinter?

As in question is it possible to upload a photo and make it relative?
I am trying to upload an image to my GUI, but it is not relative, so when you maximalize window, then unfortunatelly there is a problem with its size.
I want to change the image size dynamically when the window is resizing
Some example code:
import tkinter as tk
from PIL import ImageTk, Image
HEIGHT, WIDTH = 640, 700
root = tk.Tk()
canvas0 = tk.Canvas(height=HEIGHT, width=WIDTH)
canvas0.pack()
canvas = tk.Canvas(bg='black')
canvas.place(relx=0, rely=0, relheight=1, relwidth=1)
frame = tk.Frame(canvas, bg='#009900')
frame.place(relx=0.12, y=2, rely=0, relwidth=0.75, relheight=1)
column_1_img = Image.open('column.png')
column_1_img = ImageTk.PhotoImage(column_1_img)
column_label_1 = tk.Label(canvas, image=column_1_img)
column_label_1.image = column_1_img
column_label_1.place(relheight=1, relwidth=0.2)
root.mainloop()
This code produces this output:
Not fullscreen
Fullscreen
I want an image to automatically adjust to the label size, so do you have some ideas how?
Bind the <Configure> to an event handler and use the PIL's resize method to resize the image.
Here is an example:
import tkinter as tk
from PIL import ImageTk, Image
def resize_image(event):
column_label_1.resized = ImageTk.PhotoImage(column_1_img.resize((event.width, event.height), resample = Image.NEAREST))
column_label_1['image'] = column_label_1.resized
HEIGHT, WIDTH = 640, 700
root = tk.Tk()
canvas0 = tk.Canvas(height=HEIGHT, width=WIDTH)
canvas0.pack()
canvas = tk.Canvas(bg='black')
canvas.place(relx=0, rely=0, relheight=1, relwidth=1)
frame = tk.Frame(canvas, bg='#009900')
frame.place(relx=0.12, y=2, rely=0, relwidth=0.75, relheight=1)
column_1_img = Image.open(r'img_path')
column_img = ImageTk.PhotoImage(column_1_img)
column_label_1 = tk.Label(canvas, image=column_img)
column_label_1.image = column_1_img
column_label_1.place(relheight=1, relwidth=0.2)
column_label_1.bind('<Configure>', resize_image)
root.mainloop()

Tkinter resizing images in labels arranged in a grid

To start, I'm totally new to Tkinter and am trying to make a Raspberry Pi Media Player of sorts...
I grab the directories of all .mp4 files on a USB drive, and use PIL to put the thumbnails of the videos into a 3x3 grid of labels, with the grid inside of a frame (frame2 in the code).
Right now, with the thumbnails of varying sizes, the labels are also inconsistently sized. Also, only the top-right portion of larger thumbnails are displayed, rather than the entire image.
How can I to scale and fit the thumbnails into consistently sized labels, in grid form?
Here is part of my code (It's quite large so I try to include only the relevant parts):
import tkinter as tk
from subprocess import Popen
from time import sleep
import os
from random import randint
import imageio
from PIL import ImageTk, Image
from pathlib import Path
#putting 100th frame of video with 'path' into the label
def pack_thumbnail(path, label):
#this is probably not a good way to do this
video = imageio.get_reader(path)
for i in range(100):
try:
image = video.get_next_data()
except:
video.close()
break
frame_image = ImageTk.PhotoImage(Image.fromarray(image))
label.config(image=frame_image)
label.image = frame_image
window = tk.Tk()
window.attributes("-fullscreen", True)
frame1 = tk.Frame(master=window, width=200, height=100, bg="white")
frame1.pack(fill=tk.Y, side=tk.LEFT)
#frame2 contains the grid of labels
frame2 = tk.Frame()
for i in range(3):
frame2.columnconfigure(i, weight=1, minsize=75)
frame2.rowconfigure(i, weight=1, minsize=50)
for j in range(0, 3):
frame = tk.Frame(master=frame2, relief=tk.RAISED, borderwidth=1)
frame.grid(row=i, column=j, padx=5, pady=5)
#path to video to get thumbnail (i only have 3 videos so i randomize it)
vid_path=f"/media/pi/{os.listdir('/media/pi/')[0]}/{folder_name}/{videos[randint(0, 2)]}"
label = tk.Label(master=frame, text=f"Row {i}\nColumn {j}")
pack_thumbnail(vid_path, label)
label.pack(padx=5, pady=5)
frame2.pack()
window.bind("<Escape>", lambda x: window.destroy())
window.mainloop()
You can use Image.thumbnail() to resize the image:
# putting 100th frame of video with 'path' into the label
def pack_thumbnail(path, label):
with imageio.get_reader(path) as video:
image = video.get_data(100) # use get_date() instead of get_next_data()
w, h = 200, 200 # thumbnail size
image = Image.fromarray(image)
image.thumbnail((w, h)) # resize the image
frame_image = ImageTk.PhotoImage(image)
label.config(image=frame_image, width=w, height=h)
label.image = frame_image

Drawing a png image on a tkinter canvas python

I am trying to create a simple game using tkinter in python 3.5 using the canvas widget. For this game I am need to be able to use a transparent (png) image. Here is my code:
from PIL import ImageTk
from tkinter import Tk, Canvas
root = Tk()
im = ImageTk.PhotoImage(file="test.png")
canvas = Canvas(root, width=900, height=900)
canvas.pack()
canvasImage = canvas.create_image(0, 0, image=im, anchor="nw")
root.mainloop()
The problem is that, despite getting no errors i can't load an image with a transparent background but i can load png images with no transparent background.
You should try this:
from tkinter import *
root = Tk()
canvas = Canvas(root, width=500, height=500)
canvas.pack()
img = PhotoImage(file='path/your_image.png')
canvas.create_image(250, 250, image=img)
root.mainloop()
Output here

tkinter gif not moving, can tkinter display moving pictures?

My gif picture is not moving in tkinter. Help please. Thank you
canvas = Canvas(width = 450, height = 450, bg = 'white')
canvas.grid(row=2, column=0,sticky = 'W')
gif = PhotoImage(file = "picture.gif")
canvas.create_image(0, 0, image = gif, anchor = NW)
mainloop()
Tkinter does not support animated gifs.
The tk photo image class supports creating an image from each of the sub-images of an animated gif, and with that you can create your own animation. I don't know of any examples in python, but the tcl/tk version can be seen here: http://wiki.tcl.tk/4882

Resources