This is my code :
from PIL import Image, ImageSequence
import os
class MyImage:
def __init__(self,file_path):
self.image = Image.open(file_path)
def get_rewind(self):
iter = ImageSequence.Iterator(self.image)
index = 1
for frame in iter:
print("image [{}] : mode {}, size {}".format(index,frame.mode,frame.size))
frame.save("./rewind-result/frame{}.png".format(index))
index += 1
sequence = []
for f in ImageSequence.Iterator(self.image):
sequence.append(f.copy())
sequence.reverse()
sequence[0].save("./reverse_out.gif",save_all=True, append_images=sequence[1:])
if __name__ == '__main__':
image = MyImage("./test.gif")
image.get_rewind()
The gif is the reverse_out.gif, but it one loop once. So how to set the property of the loop?(Not by photoshop)
a non-healthy method:
from tkinter import *
class GIF(Tk):
def __init__(self):
super().__init__()
self.geometry("500x500")
self.x = 0
self.img = PhotoImage(file="filename.gif", format=f"gif -index {self.x}")
self.canvas = Canvas(self,width=1366, height=768,bd=0,highlightthickness=0)
self.canvas.pack(expand = 1, fill = BOTH)
self._img = self.canvas.create_image(0, 0, image=self.img,anchor = NW)
self.run_gif()
self.mainloop()
def run_gif(self):
try:
self.img = PhotoImage(file="filename.gif", format=f"gif -index {self.x}")
self.canvas.itemconfigure(self._img, image=self.img)
self.x += 1
except:
self.x = 0
self.canvas.after(10, self.run_gif)
GIF()
But there are those who are healthy!
Related
i'm working on creating a chat, like on a twitch, in my project using Tkinter. Is it possible to make a chat widget with animated (and not only) emojis in messages?
This is how it looks.
code:
def print_mess(self, mess):
self.console.configure(state='normal')
self.console.insert(END, mess.formated_time() + " ", 'timesign')
self.console.tag_config('timesign', foreground='#C0C0C0')
self.console.insert(END, mess.username, mess.username)
self.console.tag_config(mess.username, foreground=mess.usercolor)
self.console.insert(END, ": ", 'mess')
self.console.insert(END, mess.message + "\n", 'mess')
self.console.tag_config('mess', foreground='#FFFFFF')
self.console.yview(END) # autoscroll
self.console.configure(state='disabled')
There are multiple ways one way is to use a label and add it to the Text widget using window_create()
Example: (drag and drop a gif. click on the gif to play, Modify this to suit your need).
import tkinter as tk
from PIL import Image, ImageTk
import windnd
class Text(tk.Text):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.gif = {}
self.index = 0
self.delay = 20
self.currentlyPlaying = None
self.currentId = None
def insert_gif(self, path):
gif = GifMaker(path)
label = tk.Label(image=gif.frames[0], bd=3)
label.bind('<1>', lambda event: self.playGif(label))
self.window_create("end", window=label)
self.gif[label] = gif
self.playGif(label)
def playGif(self, label):
if self.currentlyPlaying is None:
self.currentlyPlaying = label
if self.currentlyPlaying != label: # makes sure only one gif is played at any time
self.index = 0
self.currentlyPlaying.configure(image=self.gif[self.currentlyPlaying].frames[0])
self.currentlyPlaying = label
self.after_cancel(self.currentId)
self.index += 1
if self.index == self.gif[self.currentlyPlaying].n_frames-1:
self.index = 0
self.currentlyPlaying.configure(image=self.gif[self.currentlyPlaying].frames[self.index])
if self.index != 0:
self.currentId = self.after(self.delay, self.playGif, self.currentlyPlaying)
class GifMaker:
def __init__(self, path):
self.path = path
self.image = Image.open(path)
self.n_frames = self.image.n_frames # number of frames
self.frames = []
self.duration = 0 # total duration of the gif
for x in range(self.n_frames):
img = ImageTk.PhotoImage(self.image.copy())
self.duration += self.image.info['duration']
self.frames.append(img)
self.image.seek(x)
self.delay = self.duration//self.n_frames
def dropped(file):
text.insert_gif(file[0])
root = tk.Tk()
text = Text()
text.pack(fill='both', expand=True)
windnd.hook_dropfiles(root, func=dropped)
root.mainloop()
other way is to use .image_create() to create the image and use .image_configure() to update the image. (Recommended)
import tkinter as tk
from PIL import Image, ImageTk
import windnd
class Text(tk.Text):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.gif = {}
self.frame_index = 0
self.delay = 10
def changeCursor(self, event):
if event.type == '7':
self.configure(cursor="hand2")
else:
self.configure(cursor="xterm")
def insert_gif(self, path):
gif = GifMaker(path)
index = self.image_create("end", image=gif.frames[0])
self.tag_add(f"{index}", 'end-2c')
self.gif[index] = gif
self.tag_bind(f"{index}", "<1>", lambda event: self.playGif(index))
self.tag_bind(f"{index}", "<Enter>", self.changeCursor)
self.tag_bind(f"{index}", "<Leave>", self.changeCursor)
self.playGif(index)
def playGif(self, label):
self.frame_index += 1
self.image_configure(label, image=self.gif[label].frames[self.frame_index])
if self.frame_index == self.gif[label].n_frames-1:
self.frame_index = 0
self.image_configure(label, image=self.gif[label].frames[0])
if self.frame_index != 0:
#self.after(self.gif[label].delay, self.playGif, label)
self.after(self.delay, self.playGif, label)
class GifMaker:
def __init__(self, path):
self.path = path
self.image = Image.open(path)
self.n_frames = self.image.n_frames # number of frames
self.frames = []
self.duration = 0 # total duration of the gif
for x in range(self.n_frames):
img = ImageTk.PhotoImage(self.image.copy())
self.duration += self.image.info['duration']
self.frames.append(img)
self.image.seek(x)
self.delay = self.duration//self.n_frames
def dropped(file):
text.insert_gif(file[0])
root = tk.Tk()
text = Text()
text.pack(fill='both', expand=True)
windnd.hook_dropfiles(root, func=dropped)
root.mainloop()
(make sure only one gif is played at any instance by adding conditions like the above method)
Output:
I wrote a Tkinter GUI that is supposed to show display 3D images by looping through the 2D slices of each 3D image. I read up on how to implement such an image loop, and it was recommended to use the after() function with recursion. This is, in principle, my implementation of that:
def load_image(self):
self.stack = read_3D_image(path)
slice = self.stack[self.slice_no]
im = Image.fromarray(slice)
self.photo = ImageTk.PhotoImage(image=im)
self.canvas.create_image(0, 0, image=self.photo, anchor=tk.NW)
if self.forward is True:
self.slice_no += 1
if self.slice_no == 21:
self.forward = False
if self.forward is False:
self.slice_no -= 1
if self.slice_no == 0:
self.forward = True
root.after(10, self.load_image)
This works well for some time, but after a couple of minutes, the loop notably slows down. I guess that is because of the high number of iterations. Is there a way to fix this?
Edit: I noticed this: when the program runs, the image loop will slow down to about half the original frequency after about 10 minutes. When I run a second instance, its loop runs equally slow. Then when I close the first instance, the second instance loop immediately runs faster. I launch from Eclipse.
Updated full code
import glob
import os.path
import tkinter as tk
from PIL import Image, ImageTk
import numpy as np
import helpers
class App():
def __init__(self, master):
super().__init__()
self.frame = tk.Frame(master)
master.bind("<KP_1>", lambda e: self.is_cell())
master.bind("<KP_2>", lambda e: self.is_not_cell())
self.frame.pack()
self.goto_button = tk.Button(
self.frame, text="Go to:", command=self.goto)
self.goto_button.pack(side=tk.TOP)
self.goto_entry = tk.Entry(self.frame, width=5)
self.goto_entry.pack(side=tk.TOP)
self.img_side_length = 100
self.canvas = tk.Canvas(
master=self.frame, width=self.img_side_length, height=self.img_side_length)
self.canvas.pack()
self.img_label = tk.Label(self.frame, text="Bla")
self.img_label.pack(side=tk.TOP)
self.no_cell_button = tk.Button(
self.frame, text="2: Not cell!", command=self.is_not_cell)
self.no_cell_button.pack(side=tk.RIGHT)
self.cell_button = tk.Button(
self.frame, text="1: Cell!", command=self.is_cell)
self.cell_button.pack(side=tk.RIGHT)
self.img_path = "/storage/images/"
self.img_list = glob.glob(os.path.join(self.img_path, "*"))
self.img_list.sort()
self.slice_no = 0
self.img_no = 0
self.forward = True
self.no_of_imgs = len(self.img_list)
self.stack = []
self.image_id = self.canvas.create_image(0, 0, anchor=tk.NW)
self.stack = helpers.read_image_sequence(self.img_list[self.img_no])
self.classifications = np.zeros(self.no_of_imgs)
self.out_path = "/dev/null"
self.loop_image()
def loop_image(self):
data = self.stack[self.slice_no]
im = Image.fromarray(data)
im = im.resize((self.img_side_length, self.img_side_length))
self.photo = ImageTk.PhotoImage(image=im)
self.canvas.itemconfigure(self.image_id, image=self.photo)
if self.forward is True:
self.slice_no += 1
if self.slice_no == 21:
self.forward = False
if self.forward is False:
self.slice_no -= 1
if self.slice_no == 0:
self.forward = True
root.after(10, self.loop_image)
def next_image(self):
self.img_no += 1
self.stack = helpers.read_image_sequence(self.img_list[self.img_no])
self.img_label['text'] = self.img_list[self.img_no].split("/")[-1]
def previous_image(self):
self.img_no -= 1
self.stack = helpers.read_image_sequence(self.img_list[self.img_no])
self.img_label['text'] = self.img_list[self.img_no].split("/")[-1]
def is_cell(self):
self.classifications[self.img_no] = 1
with open(self.out_path, "a") as f:
f.write(str(self.img_no) + "," + str(1) + "\n")
print(self.classifications)
self.next_image()
def is_not_cell(self):
self.classifications[self.img_no] = 2
with open(self.out_path, "a") as f:
f.write(str(self.img_no) + "," + str(2) + "\n")
print(self.classifications)
self.next_image()
def goto(self):
self.img_no = int(self.goto_entry.get())
root = tk.Tk()
app = App(root)
root.mainloop()
You are creating 100 images per second and are stacking them on top of each other. After 10 minutes, that's 60,000 images stacked on top of each other. The canvas has performance issues when it has tens of thousands of items on it, even if all but one is invisible.
Instead of creating more and more images on the canvas, just modify the existing image:
def __init__(self):
...
self.canvas = tk.Canvas(...)
...
# create the image object which will display the image
self.image_id = self.canvas.create_image(0, 0, anchor=tk.NW)
def load_image(self):
...
self.photo = ImageTk.PhotoImage(image=im)
# reconfigure the canvas item to show the new image
canvas.itemconfigure(self.image_id, image=self.photo)
...
I've been trying to figure out how to use how to place a mainloop() in my GUI so I don't need to have a while(True) anymore.
At the bottom of my code is an example of how I've been using this code. I know this is a lot of code to go through, so any help is appreciated
# Imports
import os
import os.path
import sys
import tkinter
tk = tkinter
from tkinter import font
#----- Set flag for JPEG support ---
noJPEG = False
try:
from PIL import Image
Pimg = Image
from PIL import ImageTk
Pimgtk = ImageTk
from PIL import ImageDraw
except ImportError:
noJPEG = True
#-----------------------------------
#
# Create an invisible global parent window to hold all children.
# Allows for easy closing of all windows by mouse click. If not
# closed programmatically, program exits if all windows are
# manually closed.
_root = tk.Tk()
_root.withdraw()
###
class ImageView(tk.Canvas):
def __init__(self, image, title, lotDiogram):
is_Diogram = lotDiogram
master = tk.Toplevel(_root) #sets master as a subwindow of _root
master.protocol("WM_DELETE_WINDOW", self.close)
if(is_Diogram == True):
"""When 'is_Diogram' is True, it means image is a
parking lot diogram, and does need scrollbars
added to its Toplevel"""
tk.Canvas.__init__(self, master,
width = 650, height = 525,
scrollregion=(0,0,image.getWidth(),
image.getHeight()))
self.master.title(title)
# Scrollbar added to master
vsb = tk.Scrollbar(master, orient="vertical", command=self.yview)
hsb = tk.Scrollbar(master, orient="horizontal", command=self.xview)
self.configure(yscrollcommand=vsb.set, xscrollcommand=hsb.set)
self.grid(row=0, column=0, sticky="nswe")
vsb.grid(row=0, column=1, sticky="ns")
hsb.grid(row=1, column=0, sticky="ew")
master.grid_rowconfigure(0, weight=1)
master.grid_columnconfigure(0, weight=1)
master.minsize(width=600, height=500)
master.maxsize(width = image.getWidth(),
height = image.getHeight() )
self.foreground = "black"
self.image = image
self.height = image.getHeight()
self.width = image.getWidth()
self.mouseX = None
self.mouseY = None
self.bind("<Button-1>", self.onClick)
self.tags = None
_root.update() #redraw global window
else:
"""When 'is_Diogram' is False, it means image is a
lot sign, and does not need scrollbars
added to its Toplevel"""
tk.Canvas.__init__(self, master, width = image.getWidth(),
height = image.getHeight() )
self.master.title(title)
self.pack()
master.resizable(0,0)
self.foreground = "black"
self.image = image
self.height = image.getHeight()
self.width = image.getWidth()
self.mouseX = None
self.mouseY = None
self.bind("<Button-1>", self.onClick)
self.tags = None
_root.update() #redraw global window
def close(self):
"""Close a window."""
self.master.destroy()
self.quit()
_root.update()
def getMouseXY(self):
"""Return a tuple with x,y position in the image of the
mouse click."""
self.mouseX = None
self.mouseY = None
while (self.mouseX == None) or (self.mouseY == None) :
self.update()
return ((self.mouseX,self.mouseY))
def onClick(self, event):
"""Perform various functions when mouse is clicked."""
self.mouseX = int(self.canvasx(event.x))
self.mouseY = int(self.canvasy(event.y))
def drawShape(self, shape, tagz=None, txt=None, tfont="TkDefaultFont",
color1=None, color2=None, coords=None, w=None, OL=None):
"""Draws a shape, assigns it a tag, and binds the tag to a
mouse click."""
self.tags = tagz
if shape == 'rectangle':
"""Only will accept 2 pairs of XY coordinates, X0, Y0, X1, Y1)"""
self.create_rectangle(coords, fill = color1,
activefill = color2, tags = tagz)
elif shape == 'polygon':
"""Polygon will accept a minimum of 4 XY coordinate pairs"""
self.create_polygon(coords, fill = color1,
activefill = color2, outline = OL,
tags = tagz)
else: #should never get here since shape is required
print("No shape specified!")
_root.update() #redraw global window
def getTags(self):
self.getMouseXY()
obj = self.find_closest(self.mouseX, self.mouseY)
return self.gettags(obj)
def getHeight(self):
"""Return the height of the window."""
return self.height
def getWidth(self):
"""Return the width of the window."""
return self.width
class imagesMSUError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)
#------------------------------------------------------
class Image(object):
def __init__(self, file_or_type, *args):
global noJPEG
try:
if type(file_or_type) != str:
raise imagesMSUError(str(file_or_type))
except imagesMSUError as e:
print('imagesMSU_Error: "' + e.value + '" is not a '
+ 'valid image type or a valid GIF/JPG filename.')
sys.exit(1)
# If an image type was passed in, create a blank image
# of that type.
self.type = file_or_type.upper()
if self.type == 'GIF' or self.type == 'JPG':
# Create blank image; *args are width, height.
self.width, self.height = args
self.filename = 'blank' #default filename for saving
if self.type == 'GIF': #create blank gif
self.image = tk.PhotoImage(master =_root,
width = self.width,
height = self.height)
if self.type == 'JPG': #create blank jpg
try:
if noJPEG: #libjpeg not installed
raise imagesMSUError(noJPEG)
except imagesMSUError as e:
print('imagesMSU_Error: Support library for JPEGs '
+ 'not found. Use GIFs instead.')
sys.exit(1)
else:
self.image = Pimg.new(mode = "RGB",
size = (self.width, self.height))
else: #A filename was passed in. Validate then load into an image.
# Check for valid image type
self.type = file_or_type[-3:].upper() #file's 3 char extension
try:
if self.type != 'GIF' and self.type != 'JPG': #wrong extension
raise imagesMSUError(self.type)
except imagesMSUError as e:
print('imagesMSUError: "' + e.value
+ '" is not a valid image type.')
sys.exit(1)
# Check for a valid file
filename = file_or_type
try:
if not os.path.isfile(filename): #not a file or not found
raise imagesMSUError(filename)
except imagesMSUError as e:
print('imagesMSU_Error: File "' + e.value + '" not found.')
sys.exit(1)
if self.type == 'GIF':
self.image = tk.PhotoImage(file = filename, master = _root)
self.width = self.image.width()
self.height = self.image.height()
if self.type == 'JPG':
try:
if noJPEG: #libjpeg not installed
raise imagesMSUError(noJPEG)
except imagesMSUError as e:
print('imagesMSU_Error: Support library for JPEGs '
+ 'not found. Use GIFs instead.')
sys.exit(1)
else:
self.image = Pimg.open(filename)
box = self.image.getbbox()
self.width = box[2]
self.height = box[3]
def getType(self):
"""Returns the image type."""
return self.type
def getWidth(self):
"""Returns the width of the image in pixels."""
return self.width
def getHeight(self):
"""Returns the height of the image in pixels."""
return self.height
def draw(self, win):
"""Creates and opens a window on an image. The user must close
the window to return control to the caller."""
self.canvas = win
if self.type == 'GIF':
self.canvas.create_image(self.width // 2,
self.height // 2,
image = self.image)
if self.type == 'JPG':
self.photoImage = Pimgtk.PhotoImage(self.image)
self.canvas.create_image(self.width // 2,
self.height // 2,
image = self.photoImage)
# Update the hidden root window to draw the image.
_root.update()
#-------------Example program----------------------------#
def main():
# Load an image
img1 = Image('BURG.jpg')
# Draw the image in a window.
window1 = ImageView(img1, "Burg Lot", True)
img1.draw(window1)
window1.drawShape('rectangle', tagz="Handicap", coords=[391, 214, 429, 235],
color1=None, color2='red')
window1.drawShape('rectangle', tagz="Lot_Sign", coords=[486, 375, 509, 389],
color1=None, color2='red')
# Loop to click parking spots and display parking sign
while(True):
tags = window1.getTags()
for tag in tags:
if tag != 'current':
if tag == 'Handicap':
img2 = Image('BUR HC.jpg')
window2 = ImageView(img2, "Handicap", False)
img2.draw(window2)
if tag == 'Lot_Sign':
img2 = Image('Lot Sign.jpg')
window2 = ImageView(img2, "Lot Info", False)
img2.draw(window2)
if __name__ == '__main__':
main()
If I understand your question correctly, I would do the main-loop as:
https://docs.python.org/3/library/tkinter.html#a-simple-hello-world-program
and then refactor a bit.
Your current for tag in tags-loop can be done inside drawShape where you set the tags anyway. This will convert your program to be event driven.
I'm trying to make a multithreaded program with Python, OpenCV, and Tkinter.
My program has some general point.
Load Video from file
Create 2 thread
1st thread to fetch frames from capture object and put it to python Queue
2nd thread to get the frames from Queue
At last, if possible, start and stop the capture object
However, my script seems to behave weirdly. Sometimes it can finish playing video until the end, but sometimes it also crash at some point of the video. Here is what I've got so far.
from Tkinter import Tk, Text
from Tkinter import PhotoImage
from ttk import Frame, Scrollbar, Button, Label
from PIL import Image, ImageTk
import cv
import time
import Queue
import threading
def writeToLog(log, msg):
numlines = log.index('end - 1 line').split('.')[0]
if log.index('end-1c')!='1.0': log.insert('end', '\n')
log.insert('end', msg)
log.see('end')
def GetIplImageMode(img):
orientation = 1 if img.origin == 0 else -1
mode_list = {(1, cv.IPL_DEPTH_8U) : ("L", "L", 1),\
(3, cv.IPL_DEPTH_8U) : ("BGR", "RGB", 3),\
(1, cv.IPL_DEPTH_32F) : ("F", "F", 4)}
key = (img.nChannels, img.depth)
modes = mode_list[key]
return [modes[0], modes[1], orientation]
def IplImage2PIL(img, mode):
return Image.fromstring(mode[1], (img.width, img.height),\
img.tostring(), "raw", mode[0],\
img.width * img.channels,\
mode[2])
def ResizePILImage(pil, width = 260, height = 180):
return pil.resize((width, height), Image.ANTIALIAS)
def PIL2TkImage(pil):
return ImageTk.PhotoImage(pil)
def setImageLabelFromIplImage(label, img_ipl):
mode = GetIplImageMode(img_ipl)
img_pil = IplImage2PIL(img_ipl, mode)
img_resized = ResizePILImage(img_pil)
img_tk = PIL2TkImage(img_resized)
label.configure(image = img_tk)
label.image = img_tk
def setImageLabelFromFile(label, szFileName):
img_ipl = cv.LoadImage(szFileName)
setImageLabelFromIplImage(label, img_ipl)
def mat_from_ipl(ipl):
return cv.GetMat(ipl)
def ipl_from_mat(mat):
ipl = cv.CreateImageHeader((mat.width, mat.height),\
cv.IPL_DEPTH_8U, mat.channels)
cv.SetData(ipl, mat.tostring())
return ipl
class asdf(Frame):
def __init__(self, parent):
Frame.__init__(self, parent)
self.pack(fill='both', expand=True)
self.parent = parent
self.variables()
self.ui()
def variables(self):
self.ctr = 0
self.fps = 0
self.video = None
self.image = None
self.putProc = None
self.getProc = None
self.isRunning = False
self.queue = Queue.Queue()
def ui(self):
f1 = Frame(self)
frm1 = Frame(f1)
self.lbl1 = Label(frm1, image=None)
setImageLabelFromFile(self.lbl1, '../image.bmp')
self.txt1 = Text(frm1, width=30, height=8)
sb1 = Scrollbar(frm1, orient='vertical', command=self.txt1.yview)
self.txt1.configure(yscrollcommand = sb1.set)
self.lbl1.pack()
self.txt1.pack(side='left')
sb1.pack(side='left', fill='y')
frm1.pack(side='left')
frm2 = Frame(f1)
self.lbl2 = Label(frm2, image=None)
setImageLabelFromFile(self.lbl2, '../image.bmp')
self.txt2 = Text(frm2, width=30, height=8)
sb2 = Scrollbar(frm2, orient='vertical', command=self.txt2.yview)
self.txt2.configure(yscrollcommand = sb2.set)
self.lbl2.pack()
self.txt2.pack(side='left')
sb2.pack(side='left', fill='y')
frm2.pack(side='left')
f1.pack()
f2 = Frame(self)
Button(f2, text='Run', command=self.run).pack(side='left')
Button(f2, text='Stop', command=self.stop).pack(side='left')
f2.pack()
def put_to_queue(self):
while self.isRunning:
self.ctr = self.ctr + 1
self.image = cv.QueryFrame(self.video)
time.sleep(1 / self.fps)
try:
writeToLog(self.txt1, '\nPut to queue .. %d' % (self.ctr))
temp1 = cv.CloneImage(self.image)
setImageLabelFromIplImage(self.lbl1, temp1)
temp2 = mat_from_ipl(temp1)
self.queue.put([self.ctr, temp2])
except:
writeToLog(self.txt1, '\nReach end of video ..')
break
def get_from_queue(self):
while self.isRunning:
from_queue = self.queue.get()
self.ctr_fr = from_queue[0]
if self.ctr_fr == self.ctr: time.sleep(30 / self.fps)
temp1 = ipl_from_mat(from_queue[1])
setImageLabelFromIplImage(self.lbl2, temp1)
writeToLog(self.txt2, '\nGet from queue .. %d' % (self.ctr_fr))
time.sleep(1 / self.fps)
def run(self):
self.isRunning = True
self.video = cv.CreateFileCapture('../video.avi')
self.fps = cv.GetCaptureProperty(self.video, cv.CV_CAP_PROP_FPS)
writeToLog(self.txt1, '\nStart put_queue ..')
self.putProc = threading.Thread(target=self.put_to_queue)
self.putProc.start()
time.sleep(1)
writeToLog(self.txt2, '\nStart get_queue ..')
self.getProc = threading.Thread(target=self.get_from_queue)
self.getProc.start()
def stop(self):
self.isRunning = False
if self.putProc.isAlive():
self.putProc._Thread__stop()
writeToLog(self.txt1, '\nputProc still alive, stopping ..')
self.putProc = None
if self.getProc.isAlive():
self.getProc._Thread__stop()
writeToLog(self.txt2, '\ngetProc still alive, stopping ..')
self.getProc = None
self.ctr_fr = 0
self.ctr = 0
if __name__ == '__main__':
root = Tk()
c = asdf(root)
root.mainloop()
Am I doing it wrong?
Any ideas will be very appreciated.
Thanks
I want to display an animated gif with Tkinter. I tried using the solutions proposed here.
The problem is that in my gif, only the first frame is complete. All other frame consist of a mostly transparent area where only the few pixels that change w.r.t. the preceding frame are non-transparent.
Hoe can I tell Tkinter that the background of those frames is supposed to be transparent?
from Tkinter import *
from PIL import Image, ImageTk
class MyLabel(Label):
def __init__(self, master, filename):
im = Image.open(filename)
seq = []
try:
while 1:
seq.append(im.copy())
im.seek(len(seq)) # skip to next frame
except EOFError:
pass # we're done
try:
self.delay = im.info['duration']
except KeyError:
self.delay = 100
first = seq[0].convert('RGBA')
self.frames = [ImageTk.PhotoImage(first)]
Label.__init__(self, master, image=self.frames[0])
temp = seq[0]
for image in seq[1:]:
temp.paste(image)
frame = temp.convert('RGBA')
self.frames.append(ImageTk.PhotoImage(frame))
self.idx = 0
self.cancel = self.after(self.delay, self.play)
def play(self):
self.config(image=self.frames[self.idx])
self.idx += 1
if self.idx == len(self.frames):
self.idx = 0
self.cancel = self.after(self.delay, self.play)
root = Tk()
anim = MyLabel(root, 'animated.gif')
anim.pack()
def stop_it():
anim.after_cancel(anim.cancel)
Button(root, text='stop', command=stop_it).pack()
root.mainloop()
Looks like you need to supply a mask for the paste operation:
from Tkinter import *
from PIL import Image, ImageTk
class MyLabel(Label):
def __init__(self, master, filename):
im = Image.open(filename)
seq = []
try:
while 1:
seq.append(im.copy())
im.seek(len(seq)) # skip to next frame
except EOFError:
pass # we're done
try:
self.delay = im.info['duration']
except KeyError:
self.delay = 100
first = seq[0].convert('RGBA')
self.frames = [ImageTk.PhotoImage(first)]
Label.__init__(self, master, image=self.frames[0])
lut = [1] * 256
lut[im.info["transparency"]] = 0
temp = seq[0]
for image in seq[1:]:
mask = image.point(lut, "1")
# point() is used to map image pixels into mask pixels
# via the lookup table (lut), creating a mask
# with value 0 at transparent pixels and
# 1 elsewhere
temp.paste(image, None, mask) #paste with mask
frame = temp.convert('RGBA')
self.frames.append(ImageTk.PhotoImage(frame))
self.idx = 0
self.cancel = self.after(1000, self.play)
def play(self):
self.config(image=self.frames[self.idx])
self.idx += 1
if self.idx == len(self.frames):
self.idx = 0
self.cancel = self.after(self.delay, self.play)
root = Tk()
anim = MyLabel(root, 'tumblr_m3i10ma4fI1qe0eclo1_r9_500.gif')
anim.pack()
def stop_it():
anim.after_cancel(anim.cancel)
Button(root, text='stop', command=stop_it).pack()
root.mainloop()