engineering:

Who doesn’t love animated GIFs?
Believe it or not, support for GIFs at Tumblr was a happy accident! When Tumblr put together the code for handling JPEGs, support and GIFs (and PNGs) happened to also work using the same code. Perhaps even more surprising is that the tools used to handle GIFs at Tumblr hadn’t changed much from those early days. 
The image above is an original from sukme that could not be posted to Tumblr last June. It also would have failed if he’d tried last Sunday. If you click-through to the original post, you will see a muddy, reduced-saturation mess. All this because our resizer couldn’t handle the original. 
I’ve got ninety-nine problems and the GIF is one
There is a lot of misinformation about GIF limits on Tumblr, so let me set the record straight: We don’t count colors or frames or pixels. We only count bytes and seconds. Every image that comes in is scaled to a number of smaller sizes and the smaller your image is, the fewer resizes need to happen, which means less time. 
We had two core failure modes in our prior resizer: Some images would take as much as several minutes to convert. This was not directly attributable to color, dimensions, or frame count, but a mysterious mix of all of them. Some images would balloon in size (600KB at 400x400, 27MB at 250x250).
The unpredictability of these failures made our GIF limits feel arbitrary and terrible to the end users. Some have gone so far as to threaten monkey kicks. I don’t want to get kicked by a monkey, so we started working hard late last year to fix it. 
A proposed solution
Some of you may have seen this post where the performance of our current converter was compared with a new “mystery” converter. The mystery converter was roughly 1000x faster on the “slapping” GIF and happened to look great, but had quality problems on other images. Those were more fully explored in here a couple of days later.
If you haven’t figured it out yet, the mystery converter is gifsicle.
Getting a better handle on it
To get an unbiased test set, I took a random sample of roughly 90K GIFs that Tumblr users tried to upload, not limiting the corpus only to those that succeeded. These were tested against the current converter, resizing down to the next size we produce. Each resize is given up to 20 seconds to complete in our application, but all resizes must complete in 30 seconds. All resizes must be under 1MB or we will convert the first frame to JPEG and call it a day. 
2.6% of my 90K GIFs took longer than 20 seconds to resize. This is an underestimation of how many GIFs would be rejected for time because this is only one of several resizes required. A whopping 17.1% of all GIFs were over 1MB. Even if we bump up to 2MB, the rejection rate is 2.75%. The converter was making over 25% of all resizes larger than the higher-resolution originals! The total rejection rate for my sample set was 4.46% of all original GIFs uploaded. 
Using gifsicle is so much faster that our CPU rejection rate drops to 0.00 on my test set. Also, just under 99% of all images were smaller when resized than they were at their original resolution. The size rejection rate was a much lower 0.59%.
Gifsicle problems
As compelling as the performance of gifsicle is, the quality problems are too much to ignore. We played around with the code a bit, but eventually we just got in touch with the author, Dr. Eddie Kohler. The specifics are in this post, but the short version is that Eddie was able to improve quality by adding some more advanced resampling methods as well as palette expansion for small-palette images. This increased our size rejection rate to 0.68% while still keeping us well under our CPU budget. 
Proving it
Image processing is all about choices. How do you resample? Do you sharpen? Where in the workflow is gamma correction applied, if at all? The list goes on and on. 
As you can imagine from the performance differences, our previous converter and gifsicle take very different approaches to GIF resizing. The output images look different. Sometimes it is slight, sometimes it is significant, but there is no way we could put out a converter that messes up your images, even if it messes them up quickly. 
We set up a qualitative study. The goal was simply to prove that we weren’t doing worse than our old converter, not necessarily that we were doing better. This study was opened up to all Tumblr employees, as well as some “randomly selected” outsiders (my friends and family). Participants were presented with one of two questions:
1.) Given an original and 1 resize, decide whether it is ok, unacceptable, or completely broken.
2.) Given an original and 2 resizes (randomly choses which was left and which was right, sometimes they were identical), choose the better image or say there is no difference.
The results were everything I could have hoped for. The “acceptable” test showed that users found gifsicle better at producing acceptable results (87% vs. 84%), but not by a statistically relevant amount (p=0.086) and that gifsicle produced fewer broken GIFs (0.71% vs. 1.38%), but again not enough to say it is definitively better (p=0.106). The “better” test found users preferring gifsicle 37% of the time, the prior converter only 16% of the time, but users also preferred one identical image over the other 27% of the time. Again, it is hard to say that gifsicle is better, but it is clear that it is no worse.
Putting it all together
The development and testing described above took from late October until the beginning of March. Packaging, deployment, and integration took only a couple of weeks!
We aren’t done. There is work underway exploring how we handle JPEGs and PNGs. There are a slew of features that we can go after. This was a big step, a necessary step, but not the end for sure. 
We are a community, it takes a village, there’s no “i” in GIF
This project couldn’t have happened without the excellent work of Eddie Kohler in creating, maintaining, and enhancing gifsicle. Tumblr’s Site Reliability Engineering group packaged and helped deploy gifsicle onto hundreds and hundreds of machines in our datacenter. Tumblr’s Security Team vetted the code, both by inspection and by attacking it to make sure we stay safe. This was all for the awesome Tumblr creators, but I have to mention qilme/sukme (same dude, two blogs), reallivingartist, and especially gnumblr for their help in understanding and ultimately attacking this monstrous problem.

Interesting update re: gifs on Tumblr. Could this be the end of “Image couldn’t be uploaded”?

engineering:

Who doesn’t love animated GIFs?

Believe it or not, support for GIFs at Tumblr was a happy accident! When Tumblr put together the code for handling JPEGs, support and GIFs (and PNGs) happened to also work using the same code. Perhaps even more surprising is that the tools used to handle GIFs at Tumblr hadn’t changed much from those early days. 

The image above is an original from sukme that could not be posted to Tumblr last June. It also would have failed if he’d tried last Sunday. If you click-through to the original post, you will see a muddy, reduced-saturation mess. All this because our resizer couldn’t handle the original. 

I’ve got ninety-nine problems and the GIF is one

There is a lot of misinformation about GIF limits on Tumblr, so let me set the record straight: We don’t count colors or frames or pixels. We only count bytes and seconds. Every image that comes in is scaled to a number of smaller sizes and the smaller your image is, the fewer resizes need to happen, which means less time. 

We had two core failure modes in our prior resizer: Some images would take as much as several minutes to convert. This was not directly attributable to color, dimensions, or frame count, but a mysterious mix of all of them. Some images would balloon in size (600KB at 400x400, 27MB at 250x250).

The unpredictability of these failures made our GIF limits feel arbitrary and terrible to the end users. Some have gone so far as to threaten monkey kicks. I don’t want to get kicked by a monkey, so we started working hard late last year to fix it. 

A proposed solution

Some of you may have seen this post where the performance of our current converter was compared with a new “mystery” converter. The mystery converter was roughly 1000x faster on the “slapping” GIF and happened to look great, but had quality problems on other images. Those were more fully explored in here a couple of days later.

If you haven’t figured it out yet, the mystery converter is gifsicle.

Getting a better handle on it

To get an unbiased test set, I took a random sample of roughly 90K GIFs that Tumblr users tried to upload, not limiting the corpus only to those that succeeded. These were tested against the current converter, resizing down to the next size we produce. Each resize is given up to 20 seconds to complete in our application, but all resizes must complete in 30 seconds. All resizes must be under 1MB or we will convert the first frame to JPEG and call it a day. 

2.6% of my 90K GIFs took longer than 20 seconds to resize. This is an underestimation of how many GIFs would be rejected for time because this is only one of several resizes required. A whopping 17.1% of all GIFs were over 1MB. Even if we bump up to 2MB, the rejection rate is 2.75%. The converter was making over 25% of all resizes larger than the higher-resolution originals! The total rejection rate for my sample set was 4.46% of all original GIFs uploaded. 

Using gifsicle is so much faster that our CPU rejection rate drops to 0.00 on my test set. Also, just under 99% of all images were smaller when resized than they were at their original resolution. The size rejection rate was a much lower 0.59%.

Gifsicle problems

As compelling as the performance of gifsicle is, the quality problems are too much to ignore. We played around with the code a bit, but eventually we just got in touch with the author, Dr. Eddie Kohler. The specifics are in this post, but the short version is that Eddie was able to improve quality by adding some more advanced resampling methods as well as palette expansion for small-palette images. This increased our size rejection rate to 0.68% while still keeping us well under our CPU budget. 

Proving it

Image processing is all about choices. How do you resample? Do you sharpen? Where in the workflow is gamma correction applied, if at all? The list goes on and on. 

As you can imagine from the performance differences, our previous converter and gifsicle take very different approaches to GIF resizing. The output images look different. Sometimes it is slight, sometimes it is significant, but there is no way we could put out a converter that messes up your images, even if it messes them up quickly. 

We set up a qualitative study. The goal was simply to prove that we weren’t doing worse than our old converter, not necessarily that we were doing better. This study was opened up to all Tumblr employees, as well as some “randomly selected” outsiders (my friends and family). Participants were presented with one of two questions:

1.) Given an original and 1 resize, decide whether it is ok, unacceptable, or completely broken.

2.) Given an original and 2 resizes (randomly choses which was left and which was right, sometimes they were identical), choose the better image or say there is no difference.

The results were everything I could have hoped for. The “acceptable” test showed that users found gifsicle better at producing acceptable results (87% vs. 84%), but not by a statistically relevant amount (p=0.086) and that gifsicle produced fewer broken GIFs (0.71% vs. 1.38%), but again not enough to say it is definitively better (p=0.106). The “better” test found users preferring gifsicle 37% of the time, the prior converter only 16% of the time, but users also preferred one identical image over the other 27% of the time. Again, it is hard to say that gifsicle is better, but it is clear that it is no worse.

Putting it all together

The development and testing described above took from late October until the beginning of March. Packaging, deployment, and integration took only a couple of weeks!

We aren’t done. There is work underway exploring how we handle JPEGs and PNGs. There are a slew of features that we can go after. This was a big step, a necessary step, but not the end for sure. 

We are a community, it takes a village, there’s no “i” in GIF

This project couldn’t have happened without the excellent work of Eddie Kohler in creating, maintaining, and enhancing gifsicle. Tumblr’s Site Reliability Engineering group packaged and helped deploy gifsicle onto hundreds and hundreds of machines in our datacenter. Tumblr’s Security Team vetted the code, both by inspection and by attacking it to make sure we stay safe. This was all for the awesome Tumblr creators, but I have to mention qilme/sukme (same dude, two blogs), reallivingartist, and especially gnumblr for their help in understanding and ultimately attacking this monstrous problem.

Interesting update re: gifs on Tumblr. Could this be the end of “Image couldn’t be uploaded”?

asker

leaabracadabra asked: Got the problem! Had some brackets "[HD]" in the names of my pictures. But thank you anyway! You might pass on the hint :)

Yeah, this is actually pretty common. For what it’s worth, It’s mentioned in the FAQ.

asker

Anonymous asked: Is there way to add layer mask to each particular member group layer?

Well, the simple way is to assign a keyboard shortcut (Edit - Keyboard Shortcuts) to “Add Layer Mask”, then you’ll be able to add them in a few key presses (your shortcut, then Enter, then PgDn to go to the next layer). I use this method when I, for example, want to do Curves/Levels to every layer, it’s cheap but it works.

asker

Anonymous asked: when I only want to process 1 layer is it fine to just name it [fg] ?

If you only have one layer, what do you want it to be a foreground of? There needs to be at least one layer without tags.

asker

Anonymous asked: when i process animstack it just deletes the layer?

Please provide more information, such as what layers do you have and their exact names, or even better the file itself. It appears that the tag(s) you placed on your layer do nothing, and then the layer gets deleted, which is to be expected. For example if you place a layer with [fg] at the bottom, it will do nothing, or the one with [bg] at the top. I have no way to know what you’re trying to do.

asker

ladyintheattic asked: im having a problem with my animstack: every time i put [fg] and [bg] on the layers i want and click "process animstack tags", the [fg] is deleted and nothing else happens. how can i send you the .xcf file for help?

Just upload it to Mediafire and send me the link in the ask (replace dots with spaces if Tumblr complains about urls in the ask).

Or, alternatively, send me a link to a screenshot of your layer panel.

asker

Anonymous asked: Hi! First of all i want to thank you for creating such great tool as AnimStack. As soon as I get better at it I'm totally going to do some tutorials. I wanted to do something similar with [scatter] like you did with these snowflakes, but in my case there is sky with blinking stars. I did layer group with roll tag containing star animation and now im stuck. I want to copy and paste this stars randomly on the sky. Is there any way to randomly copy&paste whole layer group?

Well, it’s pretty much like in the video, you use [!scatter] to move star to a random position at the beginning and also add a multiply tag [*number] to copy the star layer group number times (this happens before scatter).

But the important thing is, you must crop the star layer to it’s actual size, it won’t work if it’s image sized because it won’t be able to move it anywhere. Use Layer-Autocrop Layer to do it quickly (it works even on layer groups).

Also, it will place stars really randomly which means they might overlap, or all get bunched to one side and so on. You might need to undo and redo it several times until they are distributed nicely. Or just do it manually :)

asker

excusis asked: hello! okay so every time i try to save a gif after using animstack it says that i have to convert the mode to either indexed or grayscale. So when i go back it won't let me convert it to indexed and i don't want it in black in white. I try to convert it to indexed before but then it won't let me hit process animstack tags. i've uninstalled and reinstalled it twice, i have gimp 2,8 and everything else works fine like GAP, what should i do?

You can convert to Indexed or export to GIF only if all layer groups are flattened (this is a deficiency of the current version of GIMP). This is unfortunate, as Animstack is built around the concept of layer groups. Fortunately it’s easy to flatten all layer groups at once, just go to Image menu and select “Flatten Layer Groups”.

To summarize:

  • Indexed mode in GIMP doesn’t support layer groups
  • Animstack uses layer groups and doesn’t work in Indexed mode
  • images must be converted to Indexed mode before exporting to GIF, because GIF is an image format limited to 256 colors
  • to convert an RGB mode image that has layer groups in it to Indexed mode, you need to flatten all layer groups either manually or via the abovementioned menu command

Hopefully that helps.

asker

if-it-fits-it-ships asked: hi, recently my Animstack has been having strange problems. Whenever I go click 'Process Animstack Tags', nothing happens. sometimes, it will simply get rid of all the layers that contain [fg] or any other types of tags. I've had this program for close to a year now, and nothing bad's happened to it before. I've tried re-installing it, but it still didn't fix it. any suggestions?

Are you sure your layers don’t have brackets (“[” and “]”) in their names? Otherwise I don’t know what could be wrong. If you can somehow send me an xcf that doesn’t work (via some sort of filesharing service), I might be able to help.

asker

Anonymous asked: Hi, using the tutorials i've created a simple animation ontop of a [bg]. I can't seem to figure out how I can start a second and third animation on that same bg sequentially or after x amount of time

I assume you added background to some frames, but want to add it to a few more? Put new frames on top of the layer stack and a copy of your background below them, but above the completed frames. [bg] tag only affects the frames above it, so your completed frames will be unaffected. But I may have misunderstood your question.