How to show Swipe transition with tkinter? - python

I'm creating a project where the Swipe transition between two images. I'm using the tkinter library and I'm stuck.
Šobrīd fragments:
import tkinter as tk
from PIL import ImageTk, Image
root = tk.Tk()
image1 = Image.open('name.jpg')
image2 = Image.open('name2.jpg')
width = min(image1.width, image2.width)
height = min(image1.height, image2.height)
image1 = image1.resize((width, height),Image.ANTIALIAS)
image2 = image2.resize((width, height),Image.ANTIALIAS)
def Swipe(image1, image2, end):
new_image = Image.new('RGB', (image1.width, image1.height), color='white')
for y in range(image1.height):
for x in range(image1.width):
if y <= end: new_image[x][y] = image1[x][y]
else: new_image[x][y] = image2[x][y]
return new_image
for i in range(image1.height):
got = Swipe(image1, image2, i)
But I get a error /'Image' object is not subscriptable/ And how do I realize this transition in the root window? Maybe someone could help?

Related

PIL.ImageTk.PhotoImage stored in RAM appears as black square on Tkinter

Ok so I'm trying to reproduce a raycaster with Python. All things done, now I've got a 512x512 matrix coded as 8-bit colors, that I try rendering through Tkinter.
Problem is, after doing a bit of conversion with Pillow, the image appears roughly half-sized, but most importantly as a black square. I'm sure it's some kind of misuse of a function, but i can't find which. Here's the code :
from PIL import Image, ImageTk
import tkinter as Tk
import matplotlib.pyplot as plt, numpy as np
fen = Tk.Tk()
img = plt.imread('BG0.png')
canvas = Tk.Canvas(fen, width = 512, height = 512)
canvas.pack()
def Up(event):
global img
i = np.finfo(img.dtype)
img = img.astype(np.float64)/i.max
img = 255 * img
img = img.astype(np.uint8)
img = ImageTk.PhotoImage(Image.fromarray(img))
canvas.create_image(0, 0, image = img, anchor = Tk.NW)
fen.bind_all('<Up>', Up)
fen.mainloop()
And here's that famous image we're looking to show (but actually, any 512x512 image could do the trick i'd say), just put it in the same folder as this program:
BG0.png
You just have to press the up arrow key on your keybord to have it render in the tkinter window.
It's a PIL and Tkinter bug.
The image that ImageTk returns must to be stored in a variable, or a list.
You can try to pop one image from the list and it will disappear.
Here is what you can do.
from PIL import Image, ImageTk
import tkinter as Tk
import matplotlib.pyplot as plt, numpy as np
fen = Tk.Tk()
img = plt.imread('BG0.png')
canvas = Tk.Canvas(fen, width = 512, height = 512)
canvas.pack()
# THIS IS NEEDED
images_tk_list = []
def Up(event):
global img
i = np.finfo(img.dtype)
img = img.astype(np.float64)/i.max
img = 255 * img
img = img.astype(np.uint8)
img = ImageTk.PhotoImage(Image.fromarray(img))
# THIS IS NEEDED
images_tk_list.append( img )
canvas.create_image(0, 0, image = img, anchor = Tk.NW)
fen.bind_all('<Up>', Up)
fen.mainloop()

Change RGB of an Image using python

I'm trying to change the color of an image using RGB values in python, for example, if I want to change my image to grayscale I want to be able to manipulate the RGB values of the image. I've read that if I want my image in grayscale I would have to do something like Gray = (RedValue + GreenValue + BlueValue) / 3.
Here's my attempt code:
import tkinter as tk
from tkinter import *
from PIL import ImageTk, Image
from tkinter import filedialog
import os
import numpy as np
root = Tk()
root.geometry("550x300+300+150")
root.resizable(width=True, height=True)
#Find image
def openfn():
filename = filedialog.askopenfilename(title='Open')
return filename
#Here's where we load the image
def open_img():
x = openfn()
img = Image.open(x)
img = img.resize((350, 350), Image.ANTIALIAS)
img = ImageTk.PhotoImage(img)
panel = Label(root, image=img)
panel.image = img
panel.grid()
def gray():
imagen = openfn()
img = Image.open(imagen)
img = img.convert("RGB")
datas = img.getdata()
new_image_data = []
for item in datas:
if item[0] in list(range(0, 255)):
new_image_data.append((20, 40, 60))
else:
new_image_data.append(item)
img.putdata(new_image_data)
img.save("gray_image.png")
img = img.resize((250, 250), Image.ANTIALIAS)
img = ImageTk.PhotoImage(img)
panel = Label(root, image=img)
panel.image = img
panel.grid()
#buttons
btn = tk.Button(root, text='Select an image', command=open_img).grid(column=0,row=0)
gray = tk.Button(root, text='Gray filter', command=gray).grid(column=1,row=0)
root.mainloop()
I made a function called gray where I reloaded the image and change it's colors, but I don't want that, I want to apply changes to the image I loaded.
Hope you can help me out.
Try this:
import tkinter as tk
from tkinter import *
from PIL import ImageTk, Image
from tkinter import filedialog
import os
import numpy as np
root = Tk()
root.geometry("550x300+300+150")
root.resizable(width=True, height=True)
#Find image
def openfn():
filename = filedialog.askopenfilename(title="Open")
return filename
#Here's where we load the image
def open_img():
global filename, img, tk_img, panel
filename = openfn()
img = Image.open(filename)
img = img.resize((350, 350), Image.ANTIALIAS)
tk_img = ImageTk.PhotoImage(img)
panel = Label(root, image=tk_img)
panel.grid()
def apply_gray_filter():
global tk_img
draw = img.load()
width, height = img.size
# For each pixel
for x in range(width):
for y in range(height):
# Get the value as (r, g, b) using draw[x, y] and then average it
gray = sum(draw[x, y])/3
# turn it into an int
gray = int(gray)
# Change the pixel's value
draw[x, y] = (gray, gray, gray)
# Display the new image
tk_img = ImageTk.PhotoImage(img)
panel.config(image=tk_img)
#buttons
select_img_button = tk.Button(root, text="Select an image", command=open_img)
select_img_button.grid(column=0, row=0)
gray_filter_button = tk.Button(root, text="Gray filter",
command=apply_gray_filter)
gray_filter_button.grid(column=1, row=0)
root.mainloop()
It loops through all of the pixels and converts each one to grey scale. For some reason, if you press it multiple times it will turn the image into white. I have no idea why.

How to display image/screenshot in python window without saving it

I want to display my screenshot in new tkinter window (TopLevel) but I don't want to save it on pc. When I save it it's working fine but when I try to load screenshot from memory I have error: image doesn't exist.
My main window is root = Tk()
I call this function from button:
def screenshot():
x = 500
y = 500
im1 = pyautogui.screenshot(region=(x, y, 100, 100))
im1.save('test.png')
New = Toplevel(root)
im1 = ImageTk.PhotoImage(Image.open("test.png"))
image1 = Label(New, image = im1)
image1.image = im1
image1.place(x=0, y=0)
And this works good, but when I try this:
def screenshot():
x = 500
y = 500
im1 = pyautogui.screenshot(region=(x, y, 100, 100))
New = Toplevel(root)
image1 = Label(New, image = im1)
image1.image = im1
image1.place(x=0, y=0)
I got error:
_tkinter.TclError: image "<PIL.Image.Image image mode=RGB size=100x100 at 0xB4367F0>" doesn't exist
How can I display my screenshot without saving it?
EDIT:
I bypass my own problem using os.remove code looks like this:
def screenshot():
x = 500
y = 500
im1 = pyautogui.screenshot(region=(x, y, 100, 100))
im1.save('test.png')
New = Toplevel(root)
im1 = ImageTk.PhotoImage(Image.open('test.png'))
image1 = Label(New, image = im1)
image1.image = im1
image1.place(x=0, y=0)
os.remove('test.png')
And this is working pretty well but I'm still interested if I can do it without im1.save somehow.
I'm pretty new into programming, so please give me hints if my solution is ok.
Solution to your problem is very simple. From the error message "_tkinter.TclError: image "<PIL.Image.Image image mode=RGB size=100x100 at 0xB4367F0>" doesn't exist" I see that the image is in PIL format. Basically you just need to import ImageTk from PIL library and do im1 = ImageTk.PhotoImage(im1) in your function after you capture the screen.
Here is your function.
def screenshot():
x = 500
y = 500
# Can use ImageGrab to capture the screen as well
im1 = pyautogui.screenshot(region=(x, y, 100, 100))
New = Toplevel(root)
im1 = ImageTk.PhotoImage(im1) # converting PIL to support Tkinter format
image1 = Label(New, image = im1)
image1.image = im1
image1.place(x=0, y=0)
If you are using pyautogui just to capture the screen then I would recommend from PIL import ImageGrab, ImageTk with this way you don't even need pyautogui and replace it with ImageGrab.grab(bbox)).
Sample:
from tkinter import *
import pyautogui
from PIL import ImageTk, ImageGrab
root = Tk()
def screenshot():
x = 500
y = 500
# ----They both show the same results-----
# im1 = pyautogui.screenshot(region=(x, y, 100, 100))
im1 = ImageGrab.grab((x, y, x+100, y+100)) # bbox = (x1, y1, x2, y2)
New = Toplevel(root)
im1 = ImageTk.PhotoImage(im1)
image1 = Label(New, image = im1)
image1.image = im1
image1.place(x=0, y=0)
Button(root, text='ScreenShot', padx=10, command=screenshot).pack(padx=10, pady=10)
mainloop()

Tkinter Image transparency

So I have 2 images that I would like to display on top of each other.
The image on top should have transparency so that the one on the bottom is visible.
Here is my code so far:
from Tkinter import *
import ttk
from PIL import Image, ImageTk
root = Tk()
face = Image.open("faces/face.gif")
eyes = Image.open("faces/eyes1.png")
face = face.convert("RGBA")
eyes = eyes.convert("RGBA")
facedatas = face.getdata()
eyesdatas = eyes.getdata()
newData = []
for item in eyesdatas:
if item[0] == 255 and item[1] == 255 and item[2] == 255:
newData.append((255, 255, 255, 0))
else:
newData.append(item)
eyes.putdata(newData)
eyes.save("eyes0.png", "PNG")
facepic = ImageTk.PhotoImage(face)
eyespic = ImageTk.PhotoImage(eyes)
label1 = Label(image=facepic)
label1.image = facepic
label1.grid(row = 0, column = 0)
label2 = Label(image=eyespic)
label2.image = eyespic
label2.grid(row = 0, column = 0)
root.mainloop()
And here is what I get when I run it:
When I would like to obtain this:
With the face in the bottom and the eyes on top.
Try this
from PIL import Image, ImageTk
from Tkinter import Tk, Label
root = Tk()
def RBGAImage(path):
return Image.open(path).convert("RGBA")
face = RBGAImage("faces/face.gif")
eyes = RBGAImage("faces/eyes1.png")
face.paste(eyes, (0, 0), eyes)
facepic = ImageTk.PhotoImage(face)
label1 = Label(image=facepic)
label1.grid(row = 0, column = 0)
root.mainloop()
I do not have both your source images, so I can not be sure it will work with them. Please provide the originals of both if there is any issue.
You can use Image.alpha_composite to create a new composited image.
from PIL import Image, ImageTk
from Tkinter import Tk, Label
root = Tk()
def RBGAImage(path):
return Image.open(path).convert("RGBA")
face = RBGAImage("faces/face.gif")
eyes = RBGAImage("faces/eyes1.png")
c = Image.alpha_composite(face, eyes)
facepic = ImageTk.PhotoImage(c)
label1 = Label(image=facepic)
label1.grid(row = 0, column = 0)
root.mainloop()

Fade between images on screen using Python TKinter / imageTK

I am a python newbie and have been making a somewhat odd slideshow script that cycles through images and also sources a variable from another file to 'settle' on an image.
I'm sure my code is tragic. But it does work (see below)!
My question is - how would I make it fade between images instead of the jerky go to white momentarily then to next image which it does currently? Is there a transitions module I should look at?
from Tkinter import *
import Image, ImageTk, random, string
class MyApp(Tk):
def __init__(self):
Tk.__init__(self)
fr = Frame(self)
fr.pack()
self.canvas = Canvas(fr, height = 400, width = 600)
self.canvas.pack()
self.old_label_image = None
self.position = 0
self.command = 0
self.oldcommand = 0
self.slideshow()
self.debug()
def debug(self):
self.QUIT = Button(self)
self.QUIT["text"] = "QUIT!" + str(self.command)
self.QUIT["fg"] = "red"
self.QUIT["command"] = self.quit
self.QUIT.pack({"side": "right"})
def slideshow (self):
if self.command != self.oldcommand:
self.after_cancel(self.huh)
# run through random between 2-5 changes
# then settle on command for 30 seconds
self.title("Title: PAUSE")
self.oldcommand = self.command
self.slideshow()
else:
file = str(self.position) + '.jpg'
image1 = Image.open(file)
self.tkpi = ImageTk.PhotoImage(image1)
label_image = Label(self, image=self.tkpi)
label_image.place(x=0,y=0,width=image1.size[0],height=image1.size[1])
self.title("Title: " + file)
if self.old_label_image is not None:
self.old_label_image.destroy()
self.old_label_image = label_image
# make this random instead of pregressional
if self.position is not 1:
self.position = self.position + 1
else:
self.position = 0
commandfile = open('command.txt', 'r')
self.command = string.atoi(commandfile.readline())
commandfile.close()
int = random.randint(2000, 5000)
self.huh = self.after(int, self.slideshow)
#self.after_cancel(huh) - works ! so maybe can do from below Fn?
if __name__ == "__main__":
root = MyApp()
root.mainloop()
This can be achieved using the blend function.
Image.blend(image1, image2, alpha) ⇒ image
Creates a new image by interpolating between the given images, using a constant alpha. Both images must have the same size and mode.
out = image1 * (1.0 - alpha) + image2 * alpha
If the alpha is 0.0, a copy of the first image is returned. If the alpha is 1.0, a copy of the second image is returned. There are no restrictions on the alpha value. If necessary, the result is clipped to fit into the allowed output range.
So you could have something like this:
alpha = 0
while 1.0 > alpha:
image.blend(img1,img2,alpha)
alpha = alpha + 0.01
label_image.update()
An example is here, havn't had time to test this but you get the idea-
from PIL import image
import time
white = image.open("white_248x.jpg")
black = image.open("black_248x.jpg")
new_img = image.open("white_248x.jpg")
root = Tk()
image_label = label(root, image=new_img)
image_label.pack()
alpha = 0
while 1.0 > alpha:
new_img = image.blend(white,black,alpha)
alpha = alpha + 0.01
time.sleep(0.1)
image_label.update()
root.mainloop()

Categories

Resources