{"id":4943,"date":"2011-01-21T11:13:11","date_gmt":"2011-01-21T03:13:11","guid":{"rendered":"http:\/\/nick.onetwenty.org\/?p=4943"},"modified":"2011-01-21T11:13:11","modified_gmt":"2011-01-21T03:13:11","slug":"animated-gif-to-sprite-sheet-using-imagemagick","status":"publish","type":"post","link":"https:\/\/nick.onetwenty.org\/index.php\/2011\/01\/21\/animated-gif-to-sprite-sheet-using-imagemagick\/","title":{"rendered":"Animated GIF to sprite sheet using ImageMagick"},"content":{"rendered":"<p><a href=\"http:\/\/simonboxer.com\/\">Simon<\/a> made some animated GIFs to use as loading indicators for an HTML5 game we are working on. Here&#8217;s one of them:<\/p>\n<p><a href=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/DanceLoading1.gif\"><img data-attachment-id=\"4948\" data-permalink=\"https:\/\/nick.onetwenty.org\/index.php\/2011\/01\/21\/animated-gif-to-sprite-sheet-using-imagemagick\/danceloading1\/\" data-orig-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/DanceLoading1.gif?fit=82%2C74&amp;ssl=1\" data-orig-size=\"82,74\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"DanceLoading1\" data-image-description=\"\" data-medium-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/DanceLoading1.gif?fit=82%2C74&amp;ssl=1\" data-large-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/DanceLoading1.gif?fit=82%2C74&amp;ssl=1\" src=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/DanceLoading1.gif?resize=82%2C74\" alt=\"\" title=\"DanceLoading1\" width=\"82\" height=\"74\" class=\"aligncenter size-full wp-image-4948\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>Although animated GIFs are easy to place on a basic webpage, it turns out that they aren&#8217;t so great for scripting (since you don&#8217;t have much control over playback). Sprite sheets are better in this regard, since you can have pretty fine-grained control over the animation.<\/p>\n<p>So I searched for conversion methods and found this very useful <a href=\"http:\/\/forums.tigsource.com\/index.php?topic=9041\">TIGForums post<\/a> explaining how to generate sprite sheets from animated GIFs using <a href=\"http:\/\/www.imagemagick.org\/\">ImageMagick<\/a>.<\/p>\n<p>Following the instruction in that post, I ran:<\/p>\n<pre lang=\"bash\">\r\nmontage DanceLoading1.gif -tile x1 -geometry '1x1+0+0<' -alpha On -background \"rgba(0, 0, 0, 0.0)\" -quality 100 loading_1.png\r\n<\/pre>\n<p>And I ended up with this sprite sheet (click for full-size image):<\/p>\n<p><a href=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1.png\"><img data-attachment-id=\"4951\" data-permalink=\"https:\/\/nick.onetwenty.org\/index.php\/2011\/01\/21\/animated-gif-to-sprite-sheet-using-imagemagick\/loading_1\/\" data-orig-file=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1.png?fit=4428%2C74&amp;ssl=1\" data-orig-size=\"4428,74\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"loading_1\" data-image-description=\"\" data-medium-file=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1.png?fit=300%2C5&amp;ssl=1\" data-large-file=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1.png?fit=840%2C14&amp;ssl=1\" src=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1.png?resize=300%2C5\" alt=\"\" title=\"loading_1\" width=\"300\" height=\"5\" class=\"aligncenter size-medium wp-image-4951\" srcset=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1.png?w=300&amp;ssl=1 300w, https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1.png?w=1024&amp;ssl=1 1024w, https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1.png?w=1680 1680w, https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1.png?w=2520 2520w\" sizes=\"(max-width: 300px) 85vw, 300px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>Unfortunately, it looks like there are bits missing. The problem was that the animated GIF was optimised to use \"combine\" mode. This means that the image stored for each frame only includes pixels that need to be changed from the previous frame.<\/p>\n<p>Here's a close-up of where things went wrong:<\/p>\n<p><img data-attachment-id=\"4954\" data-permalink=\"https:\/\/nick.onetwenty.org\/index.php\/2011\/01\/21\/animated-gif-to-sprite-sheet-using-imagemagick\/loading_1_detail\/\" data-orig-file=\"https:\/\/i0.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1_detail.png?fit=480%2C74&amp;ssl=1\" data-orig-size=\"480,74\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"loading_1_detail\" data-image-description=\"\" data-medium-file=\"https:\/\/i0.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1_detail.png?fit=300%2C46&amp;ssl=1\" data-large-file=\"https:\/\/i0.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1_detail.png?fit=480%2C74&amp;ssl=1\" src=\"https:\/\/i0.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1_detail.png?resize=480%2C74\" alt=\"\" title=\"loading_1_detail\" width=\"480\" height=\"74\" class=\"aligncenter size-full wp-image-4954\" srcset=\"https:\/\/i0.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1_detail.png?w=480&amp;ssl=1 480w, https:\/\/i0.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_1_detail.png?w=300&amp;ssl=1 300w\" sizes=\"(max-width: 480px) 85vw, 480px\" data-recalc-dims=\"1\" \/><\/p>\n<p>In order to resolve this problem, I needed to change the GIF to use \"replace\" mode, which forces it to store a complete image for each frame. I opened the image in <a href=\"http:\/\/www.gimp.org\/\">GIMP<\/a> and saved a new copy with appropriate settings:<\/p>\n<p><a href=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/save_options.png\"><img data-attachment-id=\"4952\" data-permalink=\"https:\/\/nick.onetwenty.org\/index.php\/2011\/01\/21\/animated-gif-to-sprite-sheet-using-imagemagick\/save_options\/\" data-orig-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/save_options.png?fit=514%2C414&amp;ssl=1\" data-orig-size=\"514,414\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"save_options\" data-image-description=\"\" data-medium-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/save_options.png?fit=300%2C241&amp;ssl=1\" data-large-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/save_options.png?fit=514%2C414&amp;ssl=1\" src=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/save_options.png?resize=300%2C241\" alt=\"\" title=\"save_options\" width=\"300\" height=\"241\" class=\"aligncenter size-medium wp-image-4952\" srcset=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/save_options.png?w=300&amp;ssl=1 300w, https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/save_options.png?w=514&amp;ssl=1 514w\" sizes=\"(max-width: 300px) 85vw, 300px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>I then ran the same montage command on the newly exported file, and got pretty much what I wanted (click for full-size image):<\/p>\n<p><a href=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0.png\"><img data-attachment-id=\"4950\" data-permalink=\"https:\/\/nick.onetwenty.org\/index.php\/2011\/01\/21\/animated-gif-to-sprite-sheet-using-imagemagick\/loading_0\/\" data-orig-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0.png?fit=4428%2C74&amp;ssl=1\" data-orig-size=\"4428,74\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"loading_0\" data-image-description=\"\" data-medium-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0.png?fit=300%2C5&amp;ssl=1\" data-large-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0.png?fit=840%2C14&amp;ssl=1\" src=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0.png?resize=300%2C5\" alt=\"\" title=\"loading_0\" width=\"300\" height=\"5\" class=\"aligncenter size-medium wp-image-4950\" srcset=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0.png?w=300&amp;ssl=1 300w, https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0.png?w=1024&amp;ssl=1 1024w, https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0.png?w=1680 1680w, https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0.png?w=2520 2520w\" sizes=\"(max-width: 300px) 85vw, 300px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>Or so I thought... have a look at frame 35:<\/p>\n<p><a href=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0_detail.png\"><img data-attachment-id=\"4957\" data-permalink=\"https:\/\/nick.onetwenty.org\/index.php\/2011\/01\/21\/animated-gif-to-sprite-sheet-using-imagemagick\/loading_0_detail\/\" data-orig-file=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0_detail.png?fit=480%2C74&amp;ssl=1\" data-orig-size=\"480,74\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"loading_0_detail\" data-image-description=\"\" data-medium-file=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0_detail.png?fit=300%2C46&amp;ssl=1\" data-large-file=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0_detail.png?fit=480%2C74&amp;ssl=1\" src=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0_detail.png?resize=480%2C74\" alt=\"\" title=\"loading_0_detail\" width=\"480\" height=\"74\" class=\"aligncenter size-full wp-image-4957\" srcset=\"https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0_detail.png?w=480&amp;ssl=1 480w, https:\/\/i1.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_0_detail.png?w=300&amp;ssl=1 300w\" sizes=\"(max-width: 480px) 85vw, 480px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n<p>What is the deal with that? I checked the GIF image exported by GIMP and it's there as well. Gah. It must be a bug in GIMP.<\/p>\n<p>Nevermind, there must be a way to first convert the GIF via ImageMagick's command line operations. After reading <a href=\"http:\/\/www.imagemagick.org\/script\/command-line-options.php#layers\">some documentation<\/a>, I came up with the following:<\/p>\n<pre lang=\"bash\">\r\nconvert -layers dispose DanceLoading1.gif temp.gif\r\nmontage temp.gif -tile x1 -geometry '1x1+0+0<' -alpha On -background \"rgba(0, 0, 0, 0.0)\" -quality 100 loading_1.png\r\n<\/pre>\n<p>And it works. Yay!<\/p>\n<p><a href=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_test.png\"><img data-attachment-id=\"4964\" data-permalink=\"https:\/\/nick.onetwenty.org\/index.php\/2011\/01\/21\/animated-gif-to-sprite-sheet-using-imagemagick\/loading_test\/\" data-orig-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_test.png?fit=4428%2C74&amp;ssl=1\" data-orig-size=\"4428,74\" data-comments-opened=\"1\" data-image-meta=\"{&quot;aperture&quot;:&quot;0&quot;,&quot;credit&quot;:&quot;&quot;,&quot;camera&quot;:&quot;&quot;,&quot;caption&quot;:&quot;&quot;,&quot;created_timestamp&quot;:&quot;0&quot;,&quot;copyright&quot;:&quot;&quot;,&quot;focal_length&quot;:&quot;0&quot;,&quot;iso&quot;:&quot;0&quot;,&quot;shutter_speed&quot;:&quot;0&quot;,&quot;title&quot;:&quot;&quot;}\" data-image-title=\"loading_test\" data-image-description=\"\" data-medium-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_test.png?fit=300%2C5&amp;ssl=1\" data-large-file=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_test.png?fit=840%2C14&amp;ssl=1\" src=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_test.png?resize=300%2C5\" alt=\"\" title=\"loading_test\" width=\"300\" height=\"5\" class=\"aligncenter size-medium wp-image-4964\" srcset=\"https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_test.png?w=300&amp;ssl=1 300w, https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_test.png?w=1024&amp;ssl=1 1024w, https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_test.png?w=1680 1680w, https:\/\/i2.wp.com\/nick.onetwenty.org\/wp-content\/uploads\/2011\/01\/loading_test.png?w=2520 2520w\" sizes=\"(max-width: 300px) 85vw, 300px\" data-recalc-dims=\"1\" \/><\/a><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Simon made some animated GIFs to use as loading indicators for an HTML5 game we are working on. Here&#8217;s one of them: Although animated GIFs are easy to place on a basic webpage, it turns out that they aren&#8217;t so great for scripting (since you don&#8217;t have much control over playback). Sprite sheets are better &hellip; <a href=\"https:\/\/nick.onetwenty.org\/index.php\/2011\/01\/21\/animated-gif-to-sprite-sheet-using-imagemagick\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Animated GIF to sprite sheet using ImageMagick&#8221;<\/span><\/a><\/p>\n","protected":false},"author":67,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"spay_email":"","jetpack_publicize_message":"","jetpack_is_tweetstorm":false},"categories":[1],"tags":[],"jetpack_featured_media_url":"","jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_shortlink":"https:\/\/wp.me\/paLsRH-1hJ","_links":{"self":[{"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/posts\/4943"}],"collection":[{"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/users\/67"}],"replies":[{"embeddable":true,"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/comments?post=4943"}],"version-history":[{"count":26,"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/posts\/4943\/revisions"}],"predecessor-version":[{"id":4978,"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/posts\/4943\/revisions\/4978"}],"wp:attachment":[{"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/media?parent=4943"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/categories?post=4943"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/nick.onetwenty.org\/index.php\/wp-json\/wp\/v2\/tags?post=4943"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}