{"id":141,"date":"2005-12-06T00:21:41","date_gmt":"2005-12-05T13:21:41","guid":{"rendered":"http:\/\/www.somethinkodd.com\/oddthinking\/?p=141"},"modified":"2007-09-10T18:35:57","modified_gmt":"2007-09-10T08:35:57","slug":"python-imaging-library-pil-and-animated-gifs","status":"publish","type":"post","link":"https:\/\/www.somethinkodd.com\/oddthinking\/2005\/12\/06\/python-imaging-library-pil-and-animated-gifs\/","title":{"rendered":"Python Imaging Library (PIL) and Animated GIFs"},"content":{"rendered":"<h2>Summary<\/h2>\n<p>Let me save the next person some trouble:  The  Python Imaging Library (<a href=\"http:\/\/www.pythonware.com\/products\/pil\/\">PIL 1.1.5<\/a>) does not support <em>writing<\/em> animated GIFs.<\/p>\n<p><strong>Update:<\/strong> A script that has been published may help. See comments.<\/p>\n<h2>Background<\/h2>\n<p>It was suggested to me that <a href=\"http:\/\/www.somethinkodd.com\/oddthinking\/2005\/12\/05\/traffic-lights-and-pedestrians-an-analysis\/\">my previous post<\/a> needed a few diagrams to explain the concepts. I thought about it the number of dimensions I was trying to explain, and decided that some simple machine-generated animations were probably the way to go here.<\/p>\n<p>When I hear machine-generated images, I think of the Python Imaging Library. It has proven to be a very powerful tool on a number of small-to-medium toy projects that I have attempted.<\/p>\n<p>I imagined that I would write a hundred or so lines of Python code that would spit out images of intersections in various states of traffic flow, and I would combine them together in a sequence to produce a a few animated GIFs, and then link the GIFs into appropriate places in the article.<\/p>\n<p>(Some of you are cringing at the idea of getting involved in the <a href=\"http:\/\/lpf.ai.mit.edu\/Patents\/Gif\/Gif.html\">GIF ex-controversy<\/a>, but I wanted animation, and couldn&#8217;t rely on <a href=\"http:\/\/gjuyn.xs4all.nl\/libmng\/download.html?cat=3\">browser support<\/a> for the uncontroversial GIF-alternative, <a href=\"http:\/\/en.wikipedia.org\/wiki\/MNG\" title=\"Wikipedia definition of MNG\" class=\"wikipedia\">MNG<\/a>.)<\/p>\n<h2>Findings<\/h2>\n<p>There are two GIF versions, <a href=\"http:\/\/www.commonsoftinc.com\/Babylon_Cpp\/Documentation\/Res\/gif87a.htm\"> GIF87a<\/a> and <a href=\" http:\/\/www.commonsoftinc.com\/Babylon_Cpp\/Documentation\/Res\/gif89a.htm\">GIF89a<\/a>. For reasons I don&#8217;t quite get, even though GIF87a supports having multiple images, but GIF89a is required for real animation.<\/p>\n<p>PIL 1.1.5 can <strong>read<\/strong> GIF87a and GIF89a [<a href=\"http:\/\/www.pythonware.com\/library\/pil\/handbook\/formats.htm\">Ref<\/a>]. It can read each of the images in the sequence (see <a href=\"http:\/\/www.pythonware.com\/library\/pil\/handbook\/image.htm\"><code>Image.seek()<\/code><\/a>).<\/p>\n<p>The GIF formats also include some metadata, which appears to be only partially supported by PIL 1.1.5. I found that the <a href=\"http:\/\/www.pythonware.com\/library\/pil\/handbook\/image.htm\"><code>Image.info()<\/code><\/a> method included &#8220;duration&#8221; and &#8220;loop&#8221; fields. The May 6, 2005 <a href=\"http:\/\/effbot.org\/imagingbook\/format-gif.htm\">draft of the next PIL  handbook<\/a> describes the &#8220;duration&#8221; field only.<\/p>\n<p>However, PIL 1.1.5 can only <strong>write<\/strong> to GIF87a. It cannot write to GIF89a. Therefore, it can&#8217;t be used to produce GIF89a animations.<\/p>\n<p>I do not believe it can even be used to create new GIF87a sequences. (I can&#8217;t find any suitable methods.)   I believe it can be used to edit existing (but useless?) GIF87a sequences, but I haven&#8217;t tested this.<\/p>\n<h2>Other References<\/h2>\n<p>In 1997, in an online thread titled: &#8220;<a href=\"http:\/\/mail.python.org\/pipermail\/image-sig\/1997-March\/000249.html\">Can PIL handle animated GIFs?<\/a>&#8221; appeared to suggest yes. I couldn&#8217;t find the referenced example code, but it seems to be a limited &#8220;yes&#8221;, and consistent with the restrictions above.<\/p>\n<p>In May 2005, <a href=\"http:\/\/www.livejournal.com\/users\/benlast\">Ben Last<\/a> <a href=\"http:\/\/www.livejournal.com\/users\/benlast\/23901.html?thread=61021\">complained<\/a>:<\/p>\n<blockquote><p>The only thing that let me down was&#8230; the damn PIL.  An imaging library that has some of the worst GIF support I&#8217;ve yet seen.   Yes, I know all about the GIF patent issues, but de-emphasising support for a de-facto standard because of ideological convictions doesn&#8217;t work in the real world.<\/p><\/blockquote>\n<p>He suggests some alternatives. (BTW, Ben, <a href=\"http:\/\/www.somethinkodd.com\/oddthinking\/2005\/09\/15\/anti-plonk\/\">knolp!<\/a>)<\/p>\n<p><strong>Update:<\/strong> A script, described in the comments below, may help people looking to work-around this missing feature.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Let me save the next person some trouble:  The  Python Imaging Library (<a href=\"http:\/\/www.pythonware.com\/products\/pil\/\">PIL 1.1.5<\/a>) does not support <em>writing<\/em> animated GIFs.<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_s2mail":"","footnotes":""},"categories":[25,47,34],"tags":[],"class_list":["post-141","post","type-post","status-publish","format-standard","hentry","category-insufficiently-advanced-technology","category-review","category-software-development"],"_links":{"self":[{"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/posts\/141","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/comments?post=141"}],"version-history":[{"count":0,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/posts\/141\/revisions"}],"wp:attachment":[{"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/media?parent=141"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/categories?post=141"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.somethinkodd.com\/oddthinking\/wp-json\/wp\/v2\/tags?post=141"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}