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

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()

Related

How to show Swipe transition with tkinter?

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?

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.

refresh the screen when changing the color of a pixel (Python Image and Tkinter)

I'm using Python Image and Tkinder. I am creating a blank image and I would like every click on it a pixel to turn red, but the image does not refresh.
What is the best way to do this?
import tkinter as tk
from PIL import Image, ImageTk
# PIL accesses images in Cartesian co-ordinates, so it is Image[columns, rows]
img = Image.new( 'RGB', (500,500), "white") # create a new white image
pixels = img.load() # create the pixel map
window = tk.Tk()
canvas = tk.Canvas(window, width=img.size[0], height=img.size[1])
canvas.pack()
image_tk = ImageTk.PhotoImage(img)
canvas.create_image(img.size[0]//2, img.size[1]//2, image=image_tk)
def mouseClick( event):
pixels[event.x, event.y]= (255,0,0) #print pixel red
canvas.bind("<Button-1>", mouseClick)
window.mainloop()
I don't know anything about tkinter but this seems to do what you want - it may be horrible but maybe it will suffice until someone comes along who knows better...
#!/usr/bin/env python3
import tkinter as tk
from PIL import Image, ImageTk
# PIL accesses images in Cartesian co-ordinates, so it is Image[columns, rows]
img = Image.new( 'RGB', (500,500), "white") # create a new white image
window = tk.Tk()
canvas = tk.Canvas(window, width=img.size[0], height=img.size[1])
canvas.pack()
image_tk = ImageTk.PhotoImage(img)
canvas.create_image(img.size[0]//2, img.size[1]//2, image=image_tk)
def mouseClick( event):
x, y = event.x, event.y
print("x: {}, y: {}".format(x,y))
# Update image
img.putpixel((x, y),(255,0,0))
# Update screen
canvas.create_oval(x, y, x, y, width = 0, fill = 'red')
canvas.bind("<Button-1>", mouseClick)
window.mainloop()

black screen when using python PIL paste

I am trying to paste several images end to end and then display on canvas. I cannot figure out why this image is showing as black. Any Ideas?
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
canvas = Canvas(root, width=1000, height=800)
canvas.pack()
grass = Image.open(r"C:\pathto\grass.gif")
water = Image.open(r"C:\pathto\ffwater.gif")
r1 = ['g','g','g','w','w','w','g','g']
row = Image.new('RGB', (1000, 800))
xx = 0
for i in r1:
if i == 'g':
img = grass
if i == 'w':
img = water
row.paste(img, (xx, 0))
xx = xx + img.size[0]
worldr1 = ImageTk.PhotoImage(row)
canvas.create_image(0,0, image=worldr1)
root.mainloop()
The image is black because it is only partially visible on the Canvas. I replaced
canvas.create_image(0,0, image=worldr1)
by
canvas.create_image(0,0, anchor="nw", image=worldr1)
and the full image was visible on the Canvas (the default value is anchor="center").

Categories

Resources