Defining a filename and calling the filename in various loops and functions - python

In short, I have written a code that opens up a file and does a number of modifications on it. However, I don't want to keep going through my script and renaming all the files when I want to open up a new file.
I'm thinking of setting a variable early on that defines the filename, i.e.
A=filename('png1.png')
B=filename('png2.png')
However, I don't quite know how to implement this. This is my current code:
import os
from os import path
import numpy as np
from PIL import Image
from wordcloud import WordCloud, STOPWORDS
#d=path.dirname(_file_) if "_file_" in locals() else os.getcwd()
os.chdir('C:/Users/Sams PC/Desktop/Word_Cloud_Scripts/Dmitrys Papers/Word_Cloud_Dmitry')
Document=open('Dmitry_all_lower.txt', 'r', encoding='utf-8')
text=Document.read()
heart_mask=np.array(Image.open("**png1.png**"))
print (heart_mask)
split= str('**png1.png**').rsplit('.')
extension=split[len(split)-1]
if extension == "png":
image = Image.open("**png1.png**")
image.convert("RGBA") # Convert this to RGBA if possible
canvas = Image.new('RGBA', image.size, (255,255,255,255)) # Empty canvas colour (r,g,b,a)
canvas.paste(image, mask=image) # Paste the image onto the canvas, using it's alpha channel as mask
#canvas.thumbnail([width, height], Image.ANTIALIAS)
canvas.save('**png2.png**')
from wand.image import Image
with Image(filename='**png2.png**') as img:
img.format='jpeg'
img.save(filename='**png1.jpg**')
from PIL import Image
heart_mask=np.array(Image.open("**png1.jpg**"))
else:
print ('')
print (heart_mask)
stopwords=set(STOPWORDS)
stopwords.update(["will", "us","protein","residue", "interaction","residues","using","proteins","thus","fig"])
wc= WordCloud(stopwords=stopwords, background_color="white",max_words=1000, mask=heart_mask, contour_width=3, contour_color='black')
print ('Generating Word Cloud')
wc.generate(text)
wc.to_file("Dmitry3.png")
import matplotlib.pyplot as plt
plt.figure()
plt.imshow(wc,interpolation="bilinear")
plt.axis("off")
print ('Generation Done')
plt.show()
I've put the entire thing just to see what's going on, but I've bolded (put stars next to), the files I'm trying to modify in my idea. As you can see, I have multiple calls to my file 'png1.png', and I also have calls to save a modified version of that file to 'png2.png' and later a jpeg version of it 'png1.jpg'. I don't want to have to go through my script each time and change each one individually. I was hoping to define them earlier such as A=png1, B=png2, C=jpg1 so that I can replace the calls in my loops with simply A B and C, and if I do choose a new image to upload, I simply change 1 or 2 lines rather than 5 or 6. I.E.
heart_mask=np.array(Image.open("A"))
split= str('A').rsplit('.')
image = Image.open("A")
canvas.save('B')
... so on and so forth

To make your task easier, perhaps you should establish a naming standard defining which files are to be modified, and which ones are already processed. Also, the images you are to process should have a dedicated directory for the purpose.
From what I understand in your code, PNG files are the ones getting processed, while the JPEG files are already done. You can use os.listdir() to traverse a list of files which have a .png extension, something similar to the one below:
for file in os.listdir( "/dedicated_image_dir" ):
if file.endswith(".png"):
# Process your PNG images here
That way, you wouldn't even need to change your code just to accommodate new PNG images with different filenames.

Related

Errno 20: Not a directory when saving into zip file

When I try to save a pyplot figure as a jpg, I keep getting a directory error saying that the given file name is not a directory. I am working in Colab. I have a numpy array called z_img and have opened a zip file.
import matplotlib.pyplot as plt
from zipfile import ZipFile
zipObj = ZipFile('slices.zip', 'w') # opening zip file
plt.imshow(z_img, cmap='binary')
The plotting works fine. I did a test of saving the image into Colab's regular memory like so:
plt.savefig(str(ii)+'um_slice.jpg')
And this works perfectly, except I am intending to use this code in a for loop. ii is an index to differentiate between each image, and several hundred images would be created so I want them going in the zipfile. Now when I try adding the path to the zipfile:
plt.savefig('/content/slices.zip/'+str(ii)+'um_slice.jpg')
I get: NotADirectoryError: [Errno 20] Not a directory: '/content/slices.zip/150500um_slice.jpg'
I assume it's because the {}.jpg string is a filename, and not a directory per se. But I am quite new to Python, and don't know how to get the plot into the zip file. That's all I want. Would love any advice!
First off, for anything that's not photographic content (ie. nice and soft), JPEG is the wrong format. You'll have a better time using a different file format. PNG is nice for pixels, SVG for vector graphics (in case you embed this in a website later!), PDF for vector, too.
The error message is quite on point: you cannot just save to a zip file as if it was a directory.
Multiple ways around:
use the tempfile module's mkdtemp to make a temporary directory, save into that, and zip the result
save not into a filename, but into a buffer (BytesIO I guess) and append that to the compressed stream (I'm not too familiar with ZipFile)
use PDF as output and simply generate a multipage PDF; it's not hard, and probably much nicer in the long term. You can still convert that vector graphic result to PNG (or any other pixel format9 as desired, but for the time being, it's space efficient, arbitrarily scaleable and keeps all your pages in one place. It's easy to import selected pages into LaTeX (matter of fact, \includegraphics does it directly) or into websites (pdf.js).
From the docs, matplotlib.pyplot.savefig accepts a binary file-like object. ZipFile.open creates binary file like objects. These two have to get todgether!
with zipobj.open(str(ii)+'um_slice.jpg', 'w') as fp:
plt.savefig(fp)

Python: SVG to PNG converting issue

UPDATE: I tried increasing size in the chess.svg.board and it somehow cleared all the rendering issues at size = 900 1800
I tried using the svglib and reportlab to make .png files from .svg, and here is how the code looks:
import sys
import chess.svg
import chess
from svglib.svglib import svg2rlg
from reportlab.graphics import renderPM
board = chess.Board("rnbqkbnr/pppppppp/8/8/8/8/PPPPPPPP/RNBQKBNR")
drawing = chess.svg.board(board, size=350)
f = open('file.svg', 'w')
f.write(drawing)
drawing = svg2rlg("file.svg")
renderPM.drawToFile(drawing, "file.png", fmt="png")
If you try to open file.png there is a lot of missing parts of the image, which i guess are rendering issues. How can you fix this?
Sidenote: also getting a lot of 'x_order_2: colinear!' messages when running this on a discord bot, but I am not sure if this affects anything yet.
THIS!! I am having the same error with the same libraries... I didn't find a solution but just a workaround which probably won't help too much in your case, where the shapes generating the bands are not very sparse vertically.
I'll try playing with the file dimensions too, but so far this is what I got. Note that my svg consists of black shapes on a white background (hence the 255 - x in the following code)
Since the appearance of the bands is extremely random, and processing the same file several times in a row produces different results, I decided to take advantage of randomness: what I do is I export the same svg a few times into different pngs, import them all into a list and then only take those pixels that are white in all the exported images, something like:
images_files = [my_convert_function(svgfile=file, index=i) for i in range(3)]
images = [255 - imageio.imread(x) for x in images_files]
result = reduce(lambda a,b: a & b, images)
imageio.imwrite(<your filename here>, result)
[os.remove(x) for x in images_files]
where my_convert_function contains your same svg2rlg and renderPM.drawToFile, and returns the name of the png file being written. The index 'i' is to save several copies of the same png with different names.
It's some very crude code but I hope it can help other people with the same issue
The format parameter has to be in uppercase
renderPM.drawToFile(drawing, "file.png", fmt="PNG")

In python's unittest, how do I mock a fake folder with fake images inside?

I am trying to create a unit test for a function that reads every image from a folder and saves them in a list.
Here is a simplified version of the function:
def read_images(directory):
image_paths = os.listdir(directory)
images = []
for im in image_paths:
images.append(cv2.imread(os.path.join(directory, im)))
return images
This other question brought me close to the solution, but in my case I want the fake files created to be images (basically, arrays) so I can read them with cv2.imread.
My idea is not having to create any temporary folder and, of course, not having to connect with any external folder or database. Is this possible?
Edit: to be clear, I'd like to not have to create temporary folders, nor temporary image files. I'd like to know if there is a way of telling the program: "There is a folder here, and inside it there are some images/arrays with this shape", but with actually not having to create anything in memory.
If you actually need temporary files, you should check tempfile.
It allows you to create temporary files and directories which provide automatic cleanup, so there are no trash files if you use this while having the opportunity to test what you want.
EDIT
If you don't really want to use tempfiles nor tempfolders, here is another solution concerning your problem:
Generate in-memory image for your test.
from io import BytesIO
from PIL import Image
def create_in_memory_image():
in_memory_file = BytesIO()
image = Image.new('RGBA',
size=(0, 0),
color=(155, 0, 0))
image.save(in_memory_file,
'png')
in_memory_file.name = 'tmp_testing_name.png'
in_memory_file.seek(0)
return in_memory_file
how do I mock a fake folder with fake images inside?
def local_cv2_imread():
# use as a side effect
return 'fakeImg1'
def test_read_images(self):
with mock.patch('os.listdir') as mock_listdir:
with mock.patch('package.module.cv2.imread') as mock_imread:
mock_listdir.return_value = ['fake_path']
mock_imread.side_effect = local_cv2_imread
images = read_images('a_real_path')
self.assertEqual(images, ['fakeImg1']

Wand Python multi-size icon

i'm trying to use Wand to create a multi-size ico, but i don't find anything talking about that, only normal conversion, to ico... i've found "Sequences":
https://wand.readthedocs.org/en/latest/roadmap.html
and sequences look like what i need, but i only see samples trying to read the multiple images, but not how to create, am i missing something? or is not possible?
or is it possible to do using PIL/PILLOW?
You can append() a single image to Image.sequence list. For example:
from wand.color import Color
from wand.image import Image
with Image(width=32, height=32, background=Color('red')) as ico:
with Image(width=16, height=16, background=Color('green')) as s16:
ico.sequence.append(s16)
ico.save(filename='multisized.ico')
Result (multisized.ico):
I had a similar problem, but with creating a multi-page PDF from multiple JPEG files. In Imagemagick i used command -adjoin. In Wand i did the following:
from glob import glob
from wand.image import Image
files = glob('*.jpg')
with Image() as orig: # create empty Image object
for f in files:
page = Image(filename=f)
orig.sequence.append(page)
orig.save(filename='result.pdf')

Programmatically generate video or animated GIF in Python?

I have a series of images that I want to create a video from. Ideally I could specify a frame duration for each frame but a fixed frame rate would be fine too. I'm doing this in wxPython, so I can render to a wxDC or I can save the images to files, like PNG. Is there a Python library that will allow me to create either a video (AVI, MPG, etc) or an animated GIF from these frames?
Edit: I've already tried PIL and it doesn't seem to work. Can someone correct me with this conclusion or suggest another toolkit? This link seems to backup my conclusion regarding PIL: http://www.somethinkodd.com/oddthinking/2005/12/06/python-imaging-library-pil-and-animated-gifs/
I'd recommend not using images2gif from visvis because it has problems with PIL/Pillow and is not actively maintained (I should know, because I am the author).
Instead, please use imageio, which was developed to solve this problem and more, and is intended to stay.
Quick and dirty solution:
import imageio
images = []
for filename in filenames:
images.append(imageio.imread(filename))
imageio.mimsave('/path/to/movie.gif', images)
For longer movies, use the streaming approach:
import imageio
with imageio.get_writer('/path/to/movie.gif', mode='I') as writer:
for filename in filenames:
image = imageio.imread(filename)
writer.append_data(image)
Here's how you do it using only PIL (install with: pip install Pillow):
import glob
import contextlib
from PIL import Image
# filepaths
fp_in = "/path/to/image_*.png"
fp_out = "/path/to/image.gif"
# use exit stack to automatically close opened images
with contextlib.ExitStack() as stack:
# lazily load images
imgs = (stack.enter_context(Image.open(f))
for f in sorted(glob.glob(fp_in)))
# extract first image from iterator
img = next(imgs)
# https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
img.save(fp=fp_out, format='GIF', append_images=imgs,
save_all=True, duration=200, loop=0)
See docs: https://pillow.readthedocs.io/en/stable/handbook/image-file-formats.html#gif
Well, now I'm using ImageMagick. I save my frames as PNG files and then invoke ImageMagick's convert.exe from Python to create an animated GIF. The nice thing about this approach is I can specify a frame duration for each frame individually. Unfortunately this depends on ImageMagick being installed on the machine. They have a Python wrapper but it looks pretty crappy and unsupported. Still open to other suggestions.
As of June 2009 the originally cited blog post has a method to create animated GIFs in the comments. Download the script images2gif.py (formerly images2gif.py, update courtesy of #geographika).
Then, to reverse the frames in a gif, for instance:
#!/usr/bin/env python
from PIL import Image, ImageSequence
import sys, os
filename = sys.argv[1]
im = Image.open(filename)
original_duration = im.info['duration']
frames = [frame.copy() for frame in ImageSequence.Iterator(im)]
frames.reverse()
from images2gif import writeGif
writeGif("reverse_" + os.path.basename(filename), frames, duration=original_duration/1000.0, dither=0)
I used images2gif.py which was easy to use. It did seem to double the file size though..
26 110kb PNG files, I expected 26*110kb = 2860kb, but my_gif.GIF was 5.7mb
Also because the GIF was 8bit, the nice png's became a little fuzzy in the GIF
Here is the code I used:
__author__ = 'Robert'
from images2gif import writeGif
from PIL import Image
import os
file_names = sorted((fn for fn in os.listdir('.') if fn.endswith('.png')))
#['animationframa.png', 'animationframb.png', 'animationframc.png', ...] "
images = [Image.open(fn) for fn in file_names]
print writeGif.__doc__
# writeGif(filename, images, duration=0.1, loops=0, dither=1)
# Write an animated gif from the specified images.
# images should be a list of numpy arrays of PIL images.
# Numpy images of type float should have pixels between 0 and 1.
# Numpy images of other types are expected to have values between 0 and 255.
#images.extend(reversed(images)) #infinit loop will go backwards and forwards.
filename = "my_gif.GIF"
writeGif(filename, images, duration=0.2)
#54 frames written
#
#Process finished with exit code 0
Here are 3 of the 26 frames:
shrinking the images reduced the size:
size = (150,150)
for im in images:
im.thumbnail(size, Image.ANTIALIAS)
To create a video, you could use opencv,
#load your frames
frames = ...
#create a video writer
writer = cvCreateVideoWriter(filename, -1, fps, frame_size, is_color=1)
#and write your frames in a loop if you want
cvWriteFrame(writer, frames[i])
I came across this post and none of the solutions worked, so here is my solution that does work
Problems with other solutions thus far:
1) No explicit solution as to how the duration is modified
2) No solution for the out of order directory iteration, which is essential for GIFs
3) No explanation of how to install imageio for python 3
install imageio like this: python3 -m pip install imageio
Note: you'll want to make sure your frames have some sort of index in the filename so they can be sorted, otherwise you'll have no way of knowing where the GIF starts or ends
import imageio
import os
path = '/Users/myusername/Desktop/Pics/' # on Mac: right click on a folder, hold down option, and click "copy as pathname"
image_folder = os.fsencode(path)
filenames = []
for file in os.listdir(image_folder):
filename = os.fsdecode(file)
if filename.endswith( ('.jpeg', '.png', '.gif') ):
filenames.append(filename)
filenames.sort() # this iteration technique has no built in order, so sort the frames
images = list(map(lambda filename: imageio.imread(filename), filenames))
imageio.mimsave(os.path.join('movie.gif'), images, duration = 0.04) # modify duration as needed
Like Warren said last year, this is an old question. Since people still seem to be viewing the page, I'd like to redirect them to a more modern solution. Like blakev said here, there is a Pillow example on github.
import ImageSequence
import Image
import gifmaker
sequence = []
im = Image.open(....)
# im is your original image
frames = [frame.copy() for frame in ImageSequence.Iterator(im)]
# write GIF animation
fp = open("out.gif", "wb")
gifmaker.makedelta(fp, frames)
fp.close()
Note: This example is outdated (gifmaker is not an importable module, only a script). Pillow has a GifImagePlugin (whose source is on GitHub), but the doc on ImageSequence seems to indicate limited support (reading only)
Old question, lots of good answers, but there might still be interest in another alternative...
The numpngw module that I recently put up on github (https://github.com/WarrenWeckesser/numpngw) can write animated PNG files from numpy arrays. (Update: numpngw is now on pypi: https://pypi.python.org/pypi/numpngw.)
For example, this script:
import numpy as np
import numpngw
img0 = np.zeros((64, 64, 3), dtype=np.uint8)
img0[:32, :32, :] = 255
img1 = np.zeros((64, 64, 3), dtype=np.uint8)
img1[32:, :32, 0] = 255
img2 = np.zeros((64, 64, 3), dtype=np.uint8)
img2[32:, 32:, 1] = 255
img3 = np.zeros((64, 64, 3), dtype=np.uint8)
img3[:32, 32:, 2] = 255
seq = [img0, img1, img2, img3]
for img in seq:
img[16:-16, 16:-16] = 127
img[0, :] = 127
img[-1, :] = 127
img[:, 0] = 127
img[:, -1] = 127
numpngw.write_apng('foo.png', seq, delay=250, use_palette=True)
creates:
You'll need a browser that supports animated PNG (either directly or with a plugin) to see the animation.
As one member mentioned above, imageio is a great way to do this. imageio also allows you to set the frame rate, and I actually wrote a function in Python that allows you to set a hold on the final frame. I use this function for scientific animations where looping is useful but immediate restart isn't. Here is the link and the function:
How to make a GIF using Python
import matplotlib.pyplot as plt
import os
import imageio
def gif_maker(gif_name,png_dir,gif_indx,num_gifs,dpi=90):
# make png path if it doesn't exist already
if not os.path.exists(png_dir):
os.makedirs(png_dir)
# save each .png for GIF
# lower dpi gives a smaller, grainier GIF; higher dpi gives larger, clearer GIF
plt.savefig(png_dir+'frame_'+str(gif_indx)+'_.png',dpi=dpi)
plt.close('all') # comment this out if you're just updating the x,y data
if gif_indx==num_gifs-1:
# sort the .png files based on index used above
images,image_file_names = [],[]
for file_name in os.listdir(png_dir):
if file_name.endswith('.png'):
image_file_names.append(file_name)
sorted_files = sorted(image_file_names, key=lambda y: int(y.split('_')[1]))
# define some GIF parameters
frame_length = 0.5 # seconds between frames
end_pause = 4 # seconds to stay on last frame
# loop through files, join them to image array, and write to GIF called 'wind_turbine_dist.gif'
for ii in range(0,len(sorted_files)):
file_path = os.path.join(png_dir, sorted_files[ii])
if ii==len(sorted_files)-1:
for jj in range(0,int(end_pause/frame_length)):
images.append(imageio.imread(file_path))
else:
images.append(imageio.imread(file_path))
# the duration is the time spent on each image (1/duration is frame rate)
imageio.mimsave(gif_name, images,'GIF',duration=frame_length)
It's not a python library, but mencoder can do that: Encoding from multiple input image files. You can execute mencoder from python like this:
import os
os.system("mencoder ...")
Installation
pip install imageio-ffmpeg
pip install imageio
Code
import imageio
images = []
for filename in filenames:
images.append(imageio.imread(filename))
imageio.mimsave('movie.mp4', images)
Quality is raised and size is reduced from 8Mb to 80Kb when saving as mp4 than gif
from PIL import Image
import glob #use it if you want to read all of the certain file type in the directory
imgs=[]
for i in range(596,691):
imgs.append("snap"+str(i)+'.png')
print("scanned the image identified with",i)
starting and ending value+1 of the index that identifies different file names
imgs = glob.glob("*.png") #do this if you want to read all files ending with .png
my files were: snap596.png, snap597.png ...... snap690.png
frames = []
for i in imgs:
new_frame = Image.open(i)
frames.append(new_frame)
Save into a GIF file that loops forever
frames[0].save('fire3_PIL.gif', format='GIF',
append_images=frames[1:],
save_all=True,
duration=300, loop=0)
I found flickering issue with imageio and this method fixed it.
Have you tried PyMedia? I am not 100% sure but it looks like this tutorial example targets your problem.
With windows7, python2.7, opencv 3.0, the following works for me:
import cv2
import os
vvw = cv2.VideoWriter('mymovie.avi',cv2.VideoWriter_fourcc('X','V','I','D'),24,(640,480))
frameslist = os.listdir('.\\frames')
howmanyframes = len(frameslist)
print('Frames count: '+str(howmanyframes)) #just for debugging
for i in range(0,howmanyframes):
print(i)
theframe = cv2.imread('.\\frames\\'+frameslist[i])
vvw.write(theframe)
The easiest thing that makes it work for me is calling a shell command in Python.
If your images are stored such as dummy_image_1.png, dummy_image_2.png ... dummy_image_N.png, then you can use the function:
import subprocess
def grid2gif(image_str, output_gif):
str1 = 'convert -delay 100 -loop 1 ' + image_str + ' ' + output_gif
subprocess.call(str1, shell=True)
Just execute:
grid2gif("dummy_image*.png", "my_output.gif")
This will construct your gif file my_output.gif.
The task can be completed by running the two line python script from the same folder as the sequence of picture files. For png formatted files the script is -
from scitools.std import movie
movie('*.png',fps=1,output_file='thisismygif.gif')
I was looking for a single line code and found the following to work for my application. Here is what I did:
First Step: Install ImageMagick from the link below
https://www.imagemagick.org/script/download.php
Second Step: Point the cmd line to the folder where the images (in my case .png format) are placed
Third Step: Type the following command
magick -quality 100 *.png outvideo.mpeg
Thanks FogleBird for the idea!
Addition to Smart Manoj answers: Make a .mp4 movie from all images in a folder
Installation:
pip install imageio-ffmpeg
pip install imageio
Code:
import os
import imageio
root = r'path_to_folder_with_images'
images = []
for subdir, dirs, files in os.walk(root):
for file in files:
images.append(imageio.imread(os.path.join(root,file)))
savepath = r'path_to_save_folder'
imageio.mimsave(os.path.join(savepath,'movie.mp4'), images)
PS: Make sure your "files" list is sorted the way you want, you will save some time if you already save your images accordingly
A simple function that makes GIFs:
import imageio
import pathlib
from datetime import datetime
def make_gif(image_directory: pathlib.Path, frames_per_second: float, **kwargs):
"""
Makes a .gif which shows many images at a given frame rate.
All images should be in order (don't know how this works) in the image directory
Only tested with .png images but may work with others.
:param image_directory:
:type image_directory: pathlib.Path
:param frames_per_second:
:type frames_per_second: float
:param kwargs: image_type='png' or other
:return: nothing
"""
assert isinstance(image_directory, pathlib.Path), "input must be a pathlib object"
image_type = kwargs.get('type', 'png')
timestampStr = datetime.now().strftime("%y%m%d_%H%M%S")
gif_dir = image_directory.joinpath(timestampStr + "_GIF.gif")
print('Started making GIF')
print('Please wait... ')
images = []
for file_name in image_directory.glob('*.' + image_type):
images.append(imageio.imread(image_directory.joinpath(file_name)))
imageio.mimsave(gif_dir.as_posix(), images, fps=frames_per_second)
print('Finished making GIF!')
print('GIF can be found at: ' + gif_dir.as_posix())
def main():
fps = 2
png_dir = pathlib.Path('C:/temp/my_images')
make_gif(png_dir, fps)
if __name__ == "__main__":
main()
I just tried the following and was very useful:
First Download the libraries Figtodat and images2gif to your local directory.
Secondly Collect the figures in an array and convert them to an animated gif:
import sys
sys.path.insert(0,"/path/to/your/local/directory")
import Figtodat
from images2gif import writeGif
import matplotlib.pyplot as plt
import numpy
figure = plt.figure()
plot = figure.add_subplot (111)
plot.hold(False)
# draw a cardinal sine plot
images=[]
y = numpy.random.randn(100,5)
for i in range(y.shape[1]):
plot.plot (numpy.sin(y[:,i]))
plot.set_ylim(-3.0,3)
plot.text(90,-2.5,str(i))
im = Figtodat.fig2img(figure)
images.append(im)
writeGif("images.gif",images,duration=0.3,dither=0)
I came upon PIL's ImageSequence module, which offers for a better (and more standard) GIF aninmation. I also use Tk's after() method this time, which is better than time.sleep().
from Tkinter import *
from PIL import Image, ImageTk, ImageSequence
def stop(event):
global play
play = False
exit()
root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = im.info['duration'] # Delay used in the GIF file
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True;
while play:
for frame in ImageSequence.Iterator(im):
if not play: break
root.after(delay);
img = ImageTk.PhotoImage(frame)
lbl.config(image=img); root.update() # Show the new frame/image
root.mainloop()
It's really incredible ... All are proposing some special package for playing an animated GIF, at the moment that it can be done with Tkinter and the classic PIL module!
Here is my own GIF animation method (I created a while ago). Very simple:
from Tkinter import *
from PIL import Image, ImageTk
from time import sleep
def stop(event):
global play
play = False
exit()
root = Tk()
root.bind("<Key>", stop) # Press any key to stop
GIFfile = {path_to_your_GIF_file}
im = Image.open(GIFfile); img = ImageTk.PhotoImage(im)
delay = float(im.info['duration'])/1000; # Delay used in the GIF file
lbl = Label(image=img); lbl.pack() # Create a label where to display images
play = True; frame = 0
while play:
sleep(delay);
frame += 1
try:
im.seek(frame); img = ImageTk.PhotoImage(im)
lbl.config(image=img); root.update() # Show the new frame/image
except EOFError:
frame = 0 # Restart
root.mainloop()
You can set your own means to stop the animation. Let me know if you like to get the full version with play/pause/quit buttons.
Note: I am not sure if the consecutive frames are read from memory or from the file (disk). In the second case it would be more efficient if they all read at once and saved into an array (list). (I'm not so interested to find out! :)
I understand you asked about converting images to a gif; however, if the original format is MP4, you could use FFmpeg:
ffmpeg -i input.mp4 output.gif

Categories