Load image in tkinter from pygame surface in python 3 - python

I would like to load an image in tkinter from a pygame surface and I am having a problem.
This is what I am currently trying:
image= pygame.image.tostring(surf, 'RGB')
tkimage= tkinter.PhotoImage(data= image)
canvas.create_image(0, 0, tkimage)
but I unfortunately get this error:
_tkinter.TclError: couldn't recognize image data

The PhotoImage class can only read GIF and PGM/PPM files, either directly from a file or as base64 encoded string.
You should use the Python Imaging Library for loading and creating the image for Tk.
Here's an example:
import pygame
from PIL import Image
import ImageTk
import Tkinter
# load image in pygame
pygame.init()
surf = pygame.image.load('bridge.png')
# export as string / import to PIL
image_str = pygame.image.tostring(surf, 'RGB') # use 'RGB' to export
w, h = surf.get_rect()[2:]
image = Image.fromstring('RGB', (w, h), image_str) # use 'RGB' to import
# create Tk window/widgets
root = Tkinter.Tk()
tkimage = ImageTk.PhotoImage(image) # use ImageTk.PhotoImage class instead
canvas = Tkinter.Canvas(root)
canvas.create_image(0, 0, image=tkimage)
canvas.pack()
root.mainloop()

------- UPDATE ------
import pygame
from pygame.locals import *
from PIL import Image
import ImageTk
import Tkinter
# load image in pygame
pygame.init()
surf = pygame.image.load('pic_temp.png') # you can use any Surface a Camers is also an Surface
mode = "RGB"
# export as string / import to PIL
image_str = pygame.image.tostring(surf, mode) # use 'RGB' to export
size = (640, 480)
#image = Image.fromstring(mode, size, image_str)
# use frombuffer() - fromstring() is no longer supported
image = Image.frombuffer(mode, size, image_str, 'raw', mode, 0, 1) # use 'RGB' to import
# create Tk window/widgets
root = Tkinter.Tk()
tkimage = ImageTk.PhotoImage(image) # use ImageTk.PhotoImage class instead
label = Tkinter.Label(root, image=tkimage)
label.pack()
root.mainloop()

Related

PIL ImageTk AttributeError, can't display ImageTk on window

I've been working on a small program to convert PNG, JPG and JPEG files to .ICO files. This was relatively simple to do, but while I was trying to display the selected PNG image in Tkinter using PIL's ImageTk, I get a strange error.
from tkinter import *
from tkinter import filedialog
import re
from PIL import Image, ImageTk
root = Tk()
pathToImage = ''
selectedImage = ''
def make_square(im, min_size=256, fill_color = (0, 0, 0)): # Puts the selected image into a black square
x, y = im.size
size = max(min_size, x, y)
new_im = Image.new('RGB', (size,size), fill_color)
new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
return new_im
def select_image(): # Function that is run when Select PNG button is clicked
global pathToImage
pathToImage = filedialog.askopenfilename(filetypes=[('PNG Files','*.png'),('JPG Files','*.jpg'),('JPEG Files','*.jpeg')]) # Gets path to PNG, JPG or JPEG image
image = Image.open(pathToImage) # Opens image in PIL
image = make_square(im=image) # Turns image into square for ICO conversion
#!!!!!!!!!!!!!!!!!!!!! ERROR Among these 3 lines
global selectedImage # Here I try to tell Python I'm referring to the global variable selectedImage
selectedImage = (ImageTk.PhotoImage(image=pathToImage)) # selectedImage is given the value of ImageTk.PhotoImage with the source image being the path of the selected image
Label(root, image=selectedImage).pack() # Throws an error for some reason
# Rest of the code works fine
image.save('output.ico')
Label(root,text='Converted file stored in the same folder as \'PNG to ICO.py\'').pack()
Button(root,text='Select PNG', command=select_image).pack()
root.mainloop()
I've tried saving the image to display to a variable, but that doesn't seem to work either. Could anyone help point out what I did wrong? I'd really appreciate it.
There are couple of issues with your code.
In your line (ImageTk.PhotoImage(image=pathToImage)) you are passing a path (str) which is not what it should take, ImageTk.PhotoImage takes instance of Image(path). So change it to the image getting returned by make_square function.
Every time when the button is clicked, it'll create a new label if that's what you want then ignore this, if not then create your labels outside of the function select_image after you create the Button and later in the function update them.
I don't really get why you are using global when you can achieve your purpose without making variables pathToImage or selectedImage unless you want to access that image later in the program.
Here is the improved version of your code.
from tkinter import *
from tkinter import filedialog
import re
from PIL import Image, ImageTk
def make_square(im, min_size=256, fill_color = (0, 0, 0)): # Puts the selected image into a black square
x, y = im.size
size = max(min_size, x, y)
new_im = Image.new('RGB', (size,size), fill_color)
new_im.paste(im, (int((size - x) / 2), int((size - y) / 2)))
return new_im
def select_image(): # Function that is run when Select PNG button is clicked
pathToImage = filedialog.askopenfilename(filetypes=[('PNG Files','*.png'),('JPG Files','*.jpg'),('JPEG Files','*.jpeg')])
image = Image.open(str(pathToImage)) # Opens image in PIL
image = make_square(im=image) # Turns image into square for ICO conversion
selectedImage = ImageTk.PhotoImage(image=image)
imglabel.img = selectedImage # create a reference of the image
imglabel['image'] = selectedImage
# selectedImage is given the value of ImageTk.PhotoImage with the source image being the path of the selected image
# Rest of the code works fine
image.save('output.ico', 'ICO')
infolabel['text'] = 'Converted file stored in the same folder as \'PNG to ICO.py\''
root = Tk()
but1 = Button(root,text='Select PNG', command=select_image)
but1.pack()
imglabel = Label(root)
imglabel.pack()
infolabel = Label(root)
infolabel.pack()
root.mainloop()

Pillow Fails Rendering Urdu Text for Different Fonts

I am trying to generate image for some Urdu text using Pillow. Using the same code to generate normal English works like a charm but when I do the same with Urdu text things just does not go as smooth.
Following is the code and result when done with English:
from PIL import Image, ImageFont, ImageDraw
from matplotlib import pyplot as plt
import numpy as np
from bidi.algorithm import get_display
text_string = u'Hello how are you doing?'
img = Image.new('RGB', (720, 480))
draw = ImageDraw.Draw(img)
draw.text((25,40), text_string, fill='white')
img.save('pil_text_font.png')
And the resultant image:
Following is the code and result when done with Urdu:
from PIL import Image, ImageFont, ImageDraw
from matplotlib import pyplot as plt
import numpy as np
from bidi.algorithm import get_display
text_string = u'نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں'
img = Image.new('RGB', (720, 480))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('../UrduFontsDirectory' + data.iloc[14]['Path'], 25)
draw.text((25,40), text_string, fill='white', font=font)
img.save('pil_text_font.png')
And the resultant image:
Also I tried using Arabic Reshaper which resolved the alignment on rendering issue but yet some characters never get rendered:
from PIL import Image, ImageFont, ImageDraw
from matplotlib import pyplot as plt
import numpy as np
from bidi.algorithm import get_display
from arabic_reshaper import reshape
text_string = u'نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں'
text_string = get_display(reshape(text_string))
img = Image.new('RGB', (720, 480))
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('../UrduFontsDirectory' + data.iloc[14]['Path'], 25)
draw.text((25,40), text_string, fill='white', font=font)
img.save('pil_text_font.png')
And the resultant iamge:
On further R&D found out that this is still an issue specifically for Urdu and no solution has been worked out for it yet:
As per described here.
However, I was able to find a work around for this using the good old .NET. For someone who might face similar problem may use following to generate Urdu text images (all of the fonts supported):
//Create the font using your font file
var modernFont = new PrivateFontCollection();
modernFont.AddFontFile("NafeesNaskh.ttf");//Load font from the font file
var font= new Font(modernFont.Families[0], 12);//The second argument is the font size
//first, create a dummy bitmap just to get a graphics object
Image img = new Bitmap(1, 1);
Graphics drawing = Graphics.FromImage(img);
//free up the dummy image and old graphics object
img.Dispose();
drawing.Dispose();
//create a new image of the right size
img = new Bitmap(500, 40);
drawing = Graphics.FromImage(img);
//paint the background
drawing.Clear(Color.Black);
//create a brush for the text
Brush textBrush = new SolidBrush(Color.White);
drawing.DrawString("نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں", font, textBrush, new Rectangle(0, 0, img.Width, img.Height), new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
drawing.Save();
textBrush.Dispose();
drawing.Dispose();
string path = "./" + Id[i] + "_" + font.Name + ".jpg";
img.Save(path);
Also here is the resultant image:
Also it provides many more features like getting the image size for the text a given font and font size and also centering your content.
Image img = new Bitmap(1, 1);
Graphics drawing = Graphics.FromImage(img);
//Size of image for current text, font and font size
SizeF textSize = drawing.MeasureString("نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں", font);
img.Dispose();
drawing.Dispose();
Also in the above example the center aligning code is as follows:
drawing.DrawString("نیدرلینڈز کی ملکہ پاکستان آ رہی ہیں", font, textBrush, new Rectangle(0, 0, img.Width, img.Height), new StringFormat { Alignment = StringAlignment.Center, LineAlignment = StringAlignment.Center });
You can modify to have the text aligned to left, right, top or bottom as per your requirement.
Also for further details do refer to the documentation here.

Resize PIL image: ValueError: Unknown resampling filter

So I am trying to make a desktop-like interface in python with Tkinter, and I am trying to set the wallpaper but I have no idea how to resize it. Here is the code:
from tkinter import *
import tkinter.messagebox as box
import webbrowser
from PIL import Image, ImageTk
window=Tk()
window.title('Label Example')
window.configure(background = 'gray44')
#---=Main_Frame=---#
main_frame = Frame(window)
main_frame.pack(padx = 600, pady=350)
#---=Wallpaper=---#
img_wallpaper = ImageTk.PhotoImage(Image.open('minecraft main picture.gif').resize(10, 10)) # the one-liner I used in my app
label_w = Label(window, image=img_wallpaper)
label_w.image = img_wallpaper # this feels redundant but the image didn't show up without it in my app
label_w.pack()
##wallpaper_image = PhotoImage(file = 'minecraft main picture.gif')
##wallpaper = Label(window, image= wallpaper_image, width=400, height = 400)
##wallpaper_image_big = PhotoImage.subsample(wallpaper_image, x=1, y=1)
##can_wallpaper = \
##Canvas(window, width = 1200, height = 700)
##can_wallpaper.create_image((100, 100), image = wallpaper_image)
##can_wallpaper.place(x=0, y =0)
window.mainloop() #Main loop
I have tried used someone else's code to resize it with PIL pillow but it does not work.
Here is the error:
Traceback (most recent call last):
File "/Users/edwardandreilucaciu/Desktop/Desktop Interface Project/Desktop Interface.py", line 16, in <module>
img_wallpaper = ImageTk.PhotoImage(Image.open('minecraft main picture.gif').resize(10, 10)) # the one-liner I used in my app
File "/Library/Frameworks/Python.framework/Versions/3.7/lib/python3.7/site-packages/PIL/Image.py", line 1865, in resize
message + " Use " + ", ".join(filters[:-1]) + " or " + filters[-1]
ValueError: Unknown resampling filter (10). Use Image.NEAREST (0), Image.LANCZOS (1), Image.BILINEAR (2), Image.BICUBIC (3), Image.BOX (4) or Image.HAMMING (5)
Question: how to resize images in Tkinter
import kinter as tk
from PIL import Image, ImageTk
class ImageLabel(tk.Label):
def __init__(self, parent, **kwargs):
path = kwargs.pop('path', None)
if path is not None:
image = Image.open(path)
resize = kwargs.pop('resize', None)
if resize is not None:
image = image.resize(resize, Image.LANCZOS)
# Keep a reference to prevent garbage collection
self.photo = ImageTk.PhotoImage(image)
kwargs['image'] = self.photo
super().__init__(parent, **kwargs)
Usage:
class App(tk.Tk):
def __init__(self):
super().__init__()
lab=ImageLabel(self,
path="minecraft main picture.gif",
resize=(400, 400))
lab.grid()
if __name__ == '__main__':
App().mainloop()
It's actually quite easy
img_wallpaper = ImageTk.PhotoImage(Image.open('minecraft main picture.gif').resize(10, 10))
you see .resize is not availble for ImageTk image object also .resize takes a tuple of width and height
Try this
img_wallpaper = Image.open('minecraft main picture.gif').resize((10,10))
img_wallpaper = ImageTk.PhotoImage(img_wallpaper)

Why is a blank image in Tkinter 1/4 the size I specify?

I'm creating a canvas in a Python program using Tkinter and putting a solid single color image in it. (I need an image in there because later I'll be replacing that image with another, which is why I don't just specify the background.)
I specify the size of the canvas and have checked it when the window is open. It's 640x640. I specify the blank gray image to be the same size, but it comes up as 320x320, filling only a quarter of the canvas.
I know I can just change the image size to 1280x1280 so the whole canvas will be gray, but when I add other images to the canvas, I don't want to run into similar problems.
Here's the program:
#!/usr/bin/python
import datetime
import os
from PIL import Image, ImageTk
import sys
import Tkinter as tk
width = 640
height = 640
guiRoot = tk.Tk()
pWindow = tk.Frame(guiRoot)
BlankImage = None
CanvasMap = None
if __name__ == "__main__":
bmpfile = sys.argv[1]
print "Working with file: %s" % bmpfile
BlankImage = ImageTk.PhotoImage(Image.new('RGB', (width, height), 'gray'))
CanvasMap = tk.Canvas(guiRoot, width=width, height=height)
CanvasMap.create_image(0, 0, image=BlankImage)
CanvasMap.grid(row=0, column=0, columnspan=4) #later it's 4 columns
os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
guiRoot.mainloop()
When it runs, it looks like this.
Why is the image only 1/4 size of the canvas? What do I need to do differently so when I use the same dimensions for the canvas and the image, they'll be the same size?
The entire image is displayed, but centered at canvas origin (0, 0), this is why you can only see the bottom right 1/4 of it.
You need either to off set the display to the center of the canvas (WIDTH // 2, HEIGHT // 2), or set the image handle to the top left corner.
Here is one approach:
import datetime
import os
from PIL import Image, ImageTk
import sys
import Tkinter as tk
width = 640
height = 640
guiRoot = tk.Tk()
pWindow = tk.Frame(guiRoot)
BlankImage = None
CanvasMap = None
if __name__ == "__main__":
bmpfile = sys.argv[1]
# print "Working with file: %s" % bmpfile
BlankImage = ImageTk.PhotoImage(Image.new('RGB', (width, height), 'gray'))
CanvasMap = tk.Canvas(guiRoot, width=width, height=height)
CanvasMap.create_image(width//2, height//2, image=BlankImage)
CanvasMap.grid(row=0, column=0, columnspan=4) #later it's 4 columns
os.system('''/usr/bin/osascript -e 'tell app "Finder" to set frontmost of process "Python" to true' ''')
guiRoot.mainloop()

How Tkinter could load png images with transparent backgrounds?

Some weeks ago i load a png image into my Tkinter Canvas and drawed with create_image, but now i can't do this anymore, i tried convert with ImageTk but png did not display
I have the following code:
load = Image.open("mouse.png")
self.img = ImageTk.PhotoImage(load)
self.draw.create_image(100,100,image=self.img,anchor = NW)
self.draw.image = self.img
I just need to present a png image
Try this
vSmallIco = (15, 15)
self.original = Image.open('.//data//img//plus.png')
resized = self.original.resize(vSmallIco, Image.ANTIALIAS)
self.plusIco = ImageTk.PhotoImage(resized)
self.medIco = ttk.Label(self.mf, image=self.plusIco, style='Main.TLabel')
this is done with this import
from PIL import Image, ImageTk
Also, please use a *.png image if you wish to use png.

Categories