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").
Related
I created this little algorithm that is supposed to draw an image (imagine that my brush is an image) so that when I keep clicking I will draw the image, but as you can see if you test the code, it does not paint.
What it does is just moves the image across the Canvas.
Is there a way for the image to remain on the Canvas?
Here is my code:
from tkinter import *
from PIL import Image, ImageTk
master = Tk()
w = Canvas(master, width=800, height=400)
w.pack(expand = YES, fill = BOTH)
imagen = Image.open('C:/Users/Andres/Desktop/hola.png')
P_img = ImageTk.PhotoImage(imagen)
def paint( event ):
global w, P_img_crop
#I get the mouse coordinates
x, y = ( event.x - 1 ), ( event.y - 1 )
#I open and draw the image
img_crop = Image.open('C:/Users/Andres/Desktop/papa.png')
P_img_crop = ImageTk.PhotoImage(img_crop)
w.create_image((x,y), anchor=NW, image=P_img_crop)
w.bind( "<B1-Motion>", paint )
mainloop()
I GOT IT
I did not know that the image that was drawn on the canvas, should be saved, so what I did is store the images in a matrix, which belongs to the canvas.
Here is the code, just in case ...
from tkinter import *
from PIL import Image, ImageTk
master = Tk()
w = Canvas(master, width=800, height=400)
w.dib = [{} for k in range(10000)]
w.pack(expand = YES, fill = BOTH)
puntero = 0
def paint( event ):
global w, P_img_crop, puntero
#I get the mouse coordinates
x, y = ( event.x - 1 ), ( event.y - 1 )
#I open and draw the image
img_crop = Image.open('C:/Users/Andres/Documents/PROYECTOS INCONCLUSOS/PAINT MATEW PYTHON/hola.png')
w.dib[puntero]['image'] = ImageTk.PhotoImage(img_crop)
w.create_image((x,y), anchor=NW, image=w.dib[puntero]['image'])
puntero += 1
if(puntero >=10000):
puntero = 0
w.bind( "<B1-Motion>", paint )
mainloop()
All you need to do remove the image creation inside the paint() function. Then you will achieve what you want because otherwise it creates the image again and doesn't save a copy behind. In other words, when you move the brush, the previous image is garbage collected.
Code:
from tkinter import *
from PIL import Image, ImageTk
master = Tk()
w = Canvas(master, width=800, height=400)
w.pack(expand = YES, fill = BOTH)
img_crop = Image.open('yes.png')
P_img_crop = ImageTk.PhotoImage(img_crop)
def paint(event):
global P_img_crop
#I get the mouse coordinates
x, y = event.x - 1, event.y - 1
#I open and draw the image
w.create_image(x, y, image = P_img_crop)
w.bind("<B1-Motion>", paint)
master.mainloop()
Hope this helps!
I was trying to create and display an empty image to edit and update later on. This code worked when not using tkinter, just the image display. When i run the following code:
from random import randint
from time import *
from PIL import Image as Img
from PIL import ImageTk as ImgTk
from tkinter import *
main = Tk()
main.geometry('1001x1001')
width, height = map(int, input('width and height\n').split())
canvas = Canvas(main, width = width, height = height)
canvas.pack()
next_cells = []
img = Img.new('RGB', (width, height))
pix = img.load()
tkpix = ImgTk.PhotoImage(pix)
imgsprite = canvas.create_image(width,height,image=pix)
main.mainloop()
I get the following error:
File "/Applications/eeie", line 14, in <module>
tkpix = ImgTk.PhotoImage(pix)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/PIL/ImageTk.py", line 108, in __init__
mode = Image.getmodebase(mode)
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/PIL/Image.py", line 275, in getmodebase
return ImageMode.getmode(mode).basemode
File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/site-packages/PIL/ImageMode.py", line 64, in getmode
return _modes[mode]
builtins.KeyError: <PixelAccess object at 0x108aa4790>
What is causing this error?
Here you go, description in code.
from tkinter import *
import Image, ImageTk
# create canvas
canvas = Canvas(width=300, height=200, bg='black')
canvas.pack()
# create image object
img = Image.new('RGB', (60, 30), color='red')
new_image = ImageTk.PhotoImage(img)
# load into canvas
canvas.create_image(50, 10, image=new_image, anchor=NW)
mainloop()
Output:
To update canvas create function, and update root after changes to the object are made.
from tkinter import *
import Image, ImageTk
import time
def update_position():
while True:
canvas.move(rectangle, 30, 10)
time.sleep(1)
root.update()
root = Tk()
# create canvas
canvas = Canvas(root, width=300, height=200, bg='black')
canvas.pack()
# create image object
img = Image.new('RGB', (60, 30), color='red')
new_image = ImageTk.PhotoImage(img)
# load into canvas
rectangle = canvas.create_image(50, 10, image=new_image, anchor=NW)
update_position()
root.mainloop()
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()
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()
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()