Guest User

Untitled

a guest
Dec 9th, 2016
64
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.23 KB | None | 0 0
  1. import os
  2. from PIL import Image
  3.  
  4.  
  5. '''
  6. I searched high and low for solutions to the "extract animated GIF frames in Python"
  7. problem, and after much trial and error came up with the following solution based
  8. on several partial examples around the web (mostly Stack Overflow).
  9.  
  10. There are two pitfalls that aren't often mentioned when dealing with animated GIFs -
  11. firstly that some files feature per-frame local palettes while some have one global
  12. palette for all frames, and secondly that some GIFs replace the entire image with
  13. each new frame ('full' mode in the code below), and some only update a specific
  14. region ('partial').
  15.  
  16. This code deals with both those cases by examining the palette and redraw
  17. instructions of each frame. In the latter case this requires a preliminary (usually
  18. partial) iteration of the frames before processing, since the redraw mode needs to
  19. be consistently applied across all frames. I found a couple of examples of
  20. partial-mode GIFs containing the occasional full-frame redraw, which would result
  21. in bad renders of those frames if the mode assessment was only done on a
  22. single-frame basis.
  23.  
  24. Nov 2012
  25. '''
  26.  
  27.  
  28. def analyseImage(path):
  29. '''
  30. Pre-process pass over the image to determine the mode (full or additive).
  31. Necessary as assessing single frames isn't reliable. Need to know the mode
  32. before processing all frames.
  33. '''
  34. im = Image.open(path)
  35. results = {
  36. 'size': im.size,
  37. 'mode': 'full',
  38. }
  39. try:
  40. while True:
  41. if im.tile:
  42. tile = im.tile[0]
  43. update_region = tile[1]
  44. update_region_dimensions = update_region[2:]
  45. if update_region_dimensions != im.size:
  46. results['mode'] = 'partial'
  47. break
  48. im.seek(im.tell() + 1)
  49. except EOFError:
  50. pass
  51. return results
  52.  
  53.  
  54. def processImage(path):
  55. '''
  56. Iterate the GIF, extracting each frame.
  57. '''
  58. mode = analyseImage(path)['mode']
  59.  
  60. im = Image.open(path)
  61.  
  62. i = 0
  63. p = im.getpalette()
  64. last_frame = im.convert('RGBA')
  65.  
  66. try:
  67. while True:
  68. print "saving %s (%s) frame %d, %s %s" % (path, mode, i, im.size, im.tile)
  69.  
  70. '''
  71. If the GIF uses local colour tables, each frame will have its own palette.
  72. If not, we need to apply the global palette to the new frame.
  73. '''
  74. if not im.getpalette():
  75. im.putpalette(p)
  76.  
  77. new_frame = Image.new('RGBA', im.size)
  78.  
  79. '''
  80. Is this file a "partial"-mode GIF where frames update a region of a different size to the entire image?
  81. If so, we need to construct the new frame by pasting it on top of the preceding frames.
  82. '''
  83. if mode == 'partial':
  84. new_frame.paste(last_frame)
  85.  
  86. new_frame.paste(im, (0,0), im.convert('RGBA'))
  87. new_frame.save('%s-%d.png' % (''.join(os.path.basename(path).split('.')[:-1]), i), 'PNG')
  88.  
  89. i += 1
  90. last_frame = new_frame
  91. im.seek(im.tell() + 1)
  92. except EOFError:
  93. pass
  94.  
  95.  
  96. def main():
  97. processImage('foo.gif')
  98. processImage('bar.gif')
  99.  
  100.  
  101. if __name__ == "__main__":
  102. main()
Add Comment
Please, Sign In to add comment