After searching around, I saw some one had suggested this for a animated webp to webm. But that seemed cumbersome. So I made this to convert a animated webp to mp4 or webm, which I have live here. It takes some logic of converting a gif to video and applies it. The issue is, it takes a bit.
I was wondering if anyone had suggestions on how to improve the speed?
import os
import moviepy.video.io.ImageSequenceClip
def analyseImage(path):
'''
Pre-process pass over the image to determine the mode (full or additive).
Necessary as assessing single frames isn't reliable. Need to know the mode
before processing all frames.
'''
im = PIL.Image.open(path)
results = {
'size': im.size,
'mode': 'full',
}
try:
while True:
if im.tile:
tile = im.tile[0]
update_region = tile[1]
update_region_dimensions = update_region[2:]
if update_region_dimensions != im.size:
results['mode'] = 'partial'
break
im.seek(im.tell() + 1)
except EOFError:
pass
return results
def processImage(path):
'''
Iterate the animated image extracting each frame.
'''
images = []
mode = analyseImage(path)['mode']
im = PIL.Image.open(path)
i = 0
p = im.getpalette()
last_frame = im.convert('RGBA')
try:
while True:
print("saving %s (%s) frame %d, %s %s" % (path, mode, i, im.size, im.tile))
'''
If the GIF uses local colour tables, each frame will have its own palette.
If not, we need to apply the global palette to the new frame.
'''
if '.gif' in path:
if not im.getpalette():
im.putpalette(p)
new_frame = PIL.Image.new('RGBA', im.size)
'''
Is this file a "partial"-mode GIF where frames update a region of a different size to the entire image?
If so, we need to construct the new frame by pasting it on top of the preceding frames.
'''
if mode == 'partial':
new_frame.paste(last_frame)
new_frame.paste(im, (0, 0), im.convert('RGBA'))
nameoffile = path.split('/')[-1]
output_folder = path.replace(nameoffile, '')
name = '%s%s-%d.png' % (output_folder, ''.join(os.path.basename(path).split('.')[:-1]), i)
print(name)
new_frame.save(name, 'PNG')
images.append(name)
i += 1
last_frame = new_frame
im.seek(im.tell() + 1)
except EOFError:
pass
return images
def webp_mp4(filename, outfile):
images = processImage("%s" % filename)
fps = 30
clip = moviepy.video.io.ImageSequenceClip.ImageSequenceClip(images, fps=fps)
clip.write_videofile(outfile)
return [outfile]
webp_mp4(filename, outfile)
How it works currently, is it when you run webp_mp4(filename, outfile)
it calls processImage
which calls analyseImage
. In the end all this works fine. Just want it faster.