Quality loss while using PIL.convert("RGBA") - python

My Problem:
As soon as I convert the input GIF Image into a RGBA to process it, I'm enjoying quality loss on the image. (You can see the both pictures below the code)
The code shown below "works" just I don't got a clue, why i loose quality.
Any suggestions??
My Code:
from PIL import ImageTk, Image as Im
from Tkinter import *
class App:
def __init__(self):
self.root = Tk()
self.root.geometry('1171x900')
self.maskPng = Im.open("Images/mask.gif")
self.maskPng = self.maskPng.convert("RGBA")
self.mask = ImageTk.PhotoImage(self.maskPng)
self.show = Canvas(self.root, width = 1170, height = 780)
self.show.pack()
self.show.create_image(0, 0, image = self.mask, anchor = NW)
self.speedBTN = Button(self.root, text = "hello", command = self.speed).pack(side = "right")
self.changed = False
def speed(self):
self.speedImg = Im.open("Images/speed/3_1.gif")
self.speedImg = self.speedImg.convert("RGBA")
self.maskPng.paste(self.speedImg, (0,0), self.speedImg)
self.maskPng.save("Images/speed/test.gif", "GIF")
self.render()
def render(self):
self.mask = ImageTk.PhotoImage(Im.open('Images/speed/test.gif'))
self.show.create_image(0,0, image = self.mask, anchor = NW)
self.show.image = self.mask
def draw(self):
self.root.mainloop()
main = App()
main.root.mainloop()
Images:
This is my mask.gif:
This is my 3_1.gif:
(What it white on stackoverflow is transparent in the gif)
This is the grainy, harrowing result:
(I marked the most "grainy" areas with red rectangles)
Thanks for your help! :)

Facing the same issue but I might have solution for your use case.
It doesn't seem like you actually do anything with the image so why don't you use the base64 encoded image and read it directly like below:
import Tkinter as tk # Python 2
import tkinter as tk # Python 3
# base64 encoded image data
image = ''
root = tk.Tk()
# Pass the base64 encoded data directly to your PhotoImage()
root.image = tk.PhotoImage(data=image)
# Display image in any way you need.
label = tk.Label(root, image=root.image, bg='white')
root.overrideredirect(True)
root.geometry("+250+250")
root.lift()
root.wm_attributes("-topmost", True)
root.wm_attributes("-disabled", True)
root.wm_attributes("-transparentcolor", "white")
label.pack()
label.mainloop()
The question is old so it's unlikely that you are still working on this but I hope it will help someone else.
The issue seems to be only with RGBA, RGB works just fine but it obviously doesn't have Alpha channel. The code above will render image in its original form.
My problem is slightly different but relates to this issue. I'm trying to manipulate pixels so I have to load it as RGBA, process it and save again.
Final Edit:
After filling the issue report on github I got reply from the author.
https://github.com/python-pillow/Pillow/issues/3059
The relevant part is :
It's quantization issue.
This gives the same result:
(Image.open('./37943912.gif')
.convert('RGBA')
.quantize()
.save('_out.png'))
This is now verified and should be considered a final answer.

Related

Black sometimes replaces transparent when using PIL on tkinter

I have been trying to display several images (in png) on tkinter. All of them have a transparent background, but for some reason jailer.png (the handcuffs) has been displaying with a black background (see screenshot), while every other image works as it should. Why ?
Here's my code (if create_a_label_with_an_image is redudant, it's because i had a lot of problem wth garbage disposal, if anyone knows the trick, pls tell me !) :
import tkinter as tk
from tkinter import ttk
from os import walk
from PIL import Image, ImageTk
class Gui:
def __init__(self):
self.frames={"main":tk.Tk()} #every frame will be added in this dictionnary
self.l_widgets={} #all widgets
def create_notebook(self, name, config_args={}, grid_args={}, frame="main"):
self.l_widgets[name] = (ttk.Notebook(self.frames[frame], **config_args),0)
self.l_widgets[name][0].grid(**grid_args)
def create_a_label_with_an_image(self, name, filename, size=(None, None), config_args={}, grid_args={}, frame="main"):
image_temp=Image.open(filename)
if size!=(None,None):
image_temp.thumbnail(size)
image=ImageTk.PhotoImage(image_temp)
self.l_widgets[name] = (ttk.Label(self.frames[frame]),image) #Image is stored at several places to hope it will not get erased
self.l_widgets[name][0].config(**config_args, image=image)
self.l_widgets[name][0].image=image
self.l_widgets[name][0].grid(**grid_args)
def add_to_notebook(self, name, name_frame, config_args={}, grid_args={}):
self.frames[name_frame]=ttk.Frame(self.frames["main"])
self.l_widgets[name][0].add(self.frames[name_frame], **config_args)
self.l_widgets[name][0].grid(**grid_args)
#END ####
g=Gui()
#here, i get all path to icons from this directory
mypath = "./Wolvesville Notebook/icons/characters"
filenames = next(walk(mypath), (None, None, []))[2] # [] if no file
if filenames==[]:
raise Warning("no icons found")
g.create_notebook("roles")
g.add_to_notebook("roles","all", config_args={"text":"all"})
nbr_images=0
for icon in filenames:
g.create_a_label_with_an_image(icon[:-4], mypath+"/"+icon,
size=(50,50),
grid_args={"row":nbr_images//12,
"column":nbr_images%12},
frame=str(pool))
nbr_images+=1
tk.mainloop()
Here's what the final result look like : Notebook, with one onglet named all, and 5 icons, all transparent but handcuffs
Here is the file that doesn't work : jailer.png.
Thank you in advance for the help !
Check the format of PNG file first, convert to "RGBA" if not.
>>> from PIL import Image
>>> im = Image.open('d:/jailer.png')
>>> im.mode
'LA'
>>> im.getpixel((0, 0))
(0, 0)
>>> new_im = im.convert(mode="RGBA")
>>> new_im.save("D:/jailer_new.png", format="PNG")
Simple code to show the differece, left one is your original copy.
from tkinter import *
from PIL import Image, ImageTk
root = Tk()
im1 = Image.open("D:/jailer.png")
im2 = Image.open("D:/jailer_new.png")
pic1 = ImageTk.PhotoImage(im1)
pic2 = ImageTk.PhotoImage(im2)
label_1 = Label(root, image=pic1, bg='blue')
label_2 = Label(root, image=pic2, bg='blue')
label_1.pack(side='left')
label_2.pack(side='left')
root.mainloop()
AKX commented under my question to convert the grayscale + alpha into rgb + alpha, and it works ! I don't know why it was in grayscale, but it doesn't matter. I will close the subject, thanks !
PS : I can't seem to put a comment as the answer, so I wrote another one.

tkinter create_image don't print

for a personnal project I've been playing with pyvirtualcam,
and wanted a nice feedback with interactions, so I started implementing some tkinter in it. But as I tried to display the image on the canvas, I faced a wall...
My problem is that when printing that "image" which I forced to be a black square, it do not display at all (I am convinced about this because my canvas background is red). Any idea where this can come from?
Here is the code to reproduce the problem I have:
self.screen = tk.Tk()
self.canvas = tk.Canvas(self.screen, bg = "red")
self.canvas.pack(fill=tk.BOTH, expand=tk.YES, side=tk.TOP)
size = 20, 20, 3
output = np.zeros(size, dtype=np.uint8)
imageRGB = cv2.cvtColor(output, cv2.COLOR_BGRA2RGBA)
imageTk = ImageTk.PhotoImage(image = Image.fromarray(imageRGB))
self.canvas.create_image(100, 100, image = imageTk, anchor=tk.NW)
questions you might ask:
console is empty as if everything was fine (no error)
when printing the "output" or "imageRGB" variables it prints the matrix fine,
when printing the "imageTk" variable is prints a < TkImage > object,
For more info, be free to ask me,
Thanks for your help!

Canvas not getting captured while saving tkinter python

[SOLVED]
Please don't judge the code. I just need to fix one bug with capturing canvas into file.
As you can see I've tried multiple solutions and still while saving file is all-white...
Do you have any soulutions to that?
This app is to generate randomly dots on canvas with option to save it.
it works when number of dots is above 40000 and rectangle is black.
But otherwise is white.
HEIGTH = 207
WIDTH = 207
def snapsaveCanvas():
fname = filename.get()
my_window.update_idletasks()
my_window.update()
canvas.update()
canvas.update_idletasks()
ps = canvas.postscript(colormode='color')
img = Image.open(io.BytesIO(ps.encode('utf-8')))
img.save(fname + ".bmp", 'bmp')
print("done")
canvas = tk.Canvas(frame2, width=HEIGTH, height=WIDTH, background='white')
canvas.grid(row=0, column=0)
canvas.create_rectangle(4, 4, 206, 206)
Ok, thanks for links.
I've tested several methods and one of them works.
taken from How can I convert canvas content to an image?
import win32gui
def snapsaveCanvas():
fileName = filename.get()
canvas.update()
canvas.update_idletasks()
HWND = canvas.winfo_id() # get the handle of the canvas
rect = win32gui.GetWindowRect(HWND) # get the coordinate of the canvas
im = ImageGrab.grab(rect).save(fileName + ".bmp")
print("done")

Resizing Image and fit it to the Canvas size

Can anyone help me to resize the image using ImageTk?
I have a canvas and I will put pictures there.
I have different kinds of pictures = different sizes for all pictures
And when I attach the picture (just one) in the canvas, I want the picture's size to resize so that it will fit in the canvas and it will still maintain its proportion.
Please help me! I am new in PIL, Tkinter,and Python.
Update:
I tried using thumbnail under Image but in resizing:
self.image.thumbnail(self.picsize,Image.ANTIALIAS)
the image is not fitting the canvas size and if the image is longer/wider than the canvas, it is just cut. (Not resizing to fit into the canvas)
Code:
from PIL import ImageTk
from Tkinter import *
import os,tkFileDialog,Image
picsize = 250,250 # I want to set this so that it will fit in the self.imagecanvas | Every images attached will share same Size
imagepath = "Default_ProPic.jpg"
class GUI():
global picsize
def display(self):
self.canvas = Canvas(width=1200,height=700)
self.canvas.pack()
self.imagecanvas = Canvas(self.canvas,width=400,height=400)
self.imagecanvas.place(x=980,y=180)
self.image = Image.open(imagepath)
self.image.thumbnail(picsize,Image.ANTIALIAS)
self.newimage = ImageTk.PhotoImage(self.image)
self.profile_picture=self.imagecanvas.create_image(0,0,anchor = NW,image=self.newimage)
attachbutton = Button(self.canvas,text=" Profile Pic ",command=lambda:self.attachpic())
attachbutton.place(x=1030,y=320)
mainloop()
def attachpic(self):
global picsize
attachphoto = tkFileDialog.askopenfilename(title="Attach photo")
self.image = Image.open(attachphoto)
self.image.thumbnail(picsize,Image.ANTIALIAS)
self.newimage = ImageTk.PhotoImage(self.image)
self.imagecanvas.itemconfigure(self.profile_picture, image=self.newimage)
GUI = GUI()
GUI.display()
Picture used above:
Try saving the thumbnail as a separate variable:
self.thmb_img = self.image.thumbnail(picsize, Image.ANTIALIAS)
I suspect it may be taking the original self.image = Image.open(attachphoto)
I would suggest watching what sizing is going on with:
def attachpic(self):
picsize = 250, 250
attachphoto = tkFileDialog.askopenfilename(title="Attach photo")
self.image = Image.open(attachphoto)
print self.image.size()
self.thmb_img = self.image.thumbnail(picsize,Image.ANTIALIAS)
print self.thmb_img.size()
Check the output size and verify it is the same as the original and the desired (250, 250) thumbnail.

Pixel Manipulation via GUI in Python (poss PIL, Tkinter)

Here's the issue -
I'm writing a program that will iterate through a series of image manipulations - both effecting the whole image as well as just portions of the image. I need to demonstrate these changes to the user (myself) so I can see what's going wrong with my manipulations as they take place.
I originally tried to use PIL and Tkinter to do this - but I couldn't even load an image into the GUI - here's a bit of code formed from the corners of the web, via many google searches:
from Tkinter import *
import Image, ImageDraw, ImageTk
import time
class Test(Frame):
def __init__(self):
Frame.__init__(self)
self.c = Canvas(self, width=574, height=431, bg="red")
self.c.pack()
Button(self, text="Process", command=self.procImg).pack()
Button(self, text="Quit", command=self.quit).pack()
def procImg(self):
t = time.time()
self.flashImg = Image.open("./in_img/resize.bmp")
#self.flashImg = flashImg.resize((574, 431))
self.flashImg = self.flashImg.convert("L")
#self.photo = ImageTk.BitmapImage(flashImg)
self.c.photo = ImageTk.PhotoImage(self.flashImg)
self.c.create_image(574, 431, anchor=NW, image=self.c.photo)
self.c.create_rectangle(50, 50, 100, 100, fill="blue")
self.update()
print time.time()-t
t = Test()
t.pack()
t.mainloop()
So the above code is pretty bad, I know - but I wanted to post something to prove that I have at least been working at this.
Can anyone suggest to me a new way of approaching this problem using Python? I'd rather not learn a different language - I'm new to the Tkinter library so if something else is better suited for this, I have no issues learning a new library.
Also, FYI, the "resize.bmp" image is a resized .JPG from a digital camera. I tried that one too and it didn't work - I really need to find a way to flash bitmaps from memory to the screen in a GUI so I can adjust parameters as the processing is going on.
Thanks for your help!
The image is probably there. It's just not visible.
Instead of :
self.c.create_image(574, 431, anchor=NW, image=self.c.photo)
try :
self.c.create_image(0, 0, anchor=NW, image=self.c.photo)
Also, if you keep a reference to the canvas image item, you can swap different images in and out.
eg. (self.canvasItem) below :
from Tkinter import *
from PIL import Image, ImageTk, ImageDraw, ImageOps, ImageEnhance
class ImageButcher(Tk):
def __init__(self):
Tk.__init__(self)
#create ui
f = Frame(self, bd=2)
self.colour = StringVar(self)
self.colourMenu = OptionMenu(f, self.colour,
*('red','green','blue','white'))
self.colourMenu.config(width=5)
self.colour.set('red')
self.colourMenu.pack(side='left')
self.rectangleButton = Button(f, text='Rectangle',
command=self.draw_rectangle)
self.rectangleButton.pack(side='left')
self.brightenButton = Button(f, text='Brighten',
command=self.on_brighten)
self.brightenButton.pack(side='left')
self.mirrorButton = Button(f, text='Mirror',
command=self.on_mirror)
self.mirrorButton.pack(side='left')
f.pack(fill='x')
self.c = Canvas(self, bd=0, highlightthickness=0,
width=100, height=100)
self.c.pack(fill='both', expand=1)
#load image
im = Image.open('IMG_1584.JPG')
im.thumbnail((512,512))
self.tkphoto = ImageTk.PhotoImage(im)
self.canvasItem = self.c.create_image(0,0,anchor='nw',image=self.tkphoto)
self.c.config(width=im.size[0], height=im.size[1])
self.img = im
self.temp = im.copy() # 'working' image
def display_image(self, aImage):
self.tkphoto = pic = ImageTk.PhotoImage(aImage)
self.c.itemconfigure(self.canvasItem, image=pic)
def on_mirror(self):
im = ImageOps.mirror(self.temp)
self.display_image(im)
self.temp = im
def on_brighten(self):
brightener = ImageEnhance.Brightness(self.temp)
self.temp = brightener.enhance(1.1) # +10%
self.display_image(self.temp)
def draw_rectangle(self):
bbox = 9, 9, self.temp.size[0] - 11, self.temp.size[1] - 11
draw = ImageDraw.Draw(self.temp)
draw.rectangle(bbox, outline=self.colour.get())
self.display_image(self.temp)
app = ImageButcher()
app.mainloop()

Categories

Resources