DEV Community

AsyncMonk
AsyncMonk

Posted on

What one 10-frame sample can and cannot tell you before you change your GIF export settings

Before changing the export settings of demo GIFs for a small site, I wanted to know two things: does turning dithering on cost bytes, and how far does a lower colour count go. All I had to look at was one sample, a 10-frame GIF, so this is a list of what it answered and what it left open.

The sample is File:MORPH.gif from Wikimedia Commons, author Kowloonese, CC BY-SA 3.0. It is 675×599, 10 frames at 100 ms each, 3,003,893 bytes, a photo-style gradient with text morphing across it. I ran it through the animation tool in ImgIng (图映) https://imging.ai/ in a desktop browser, then rebuilt the same variants with Pillow and gifsicle 1.98 to see whether the pattern survives a second pipeline. One file, one Apple M4, one run each, and every size below is exact bytes.

What the sample settled

Fewer colours means fewer bytes, and by a lot. In the tool, with dithering off, 256 colours gave 1,525,126 bytes and 32 colours gave 811,310. The 256-colour number is the baseline for everything else here.

Dithering costs bytes at every palette size I tried. With Floyd–Steinberg on, 32 colours went from 811,310 to 1,110,431 (+36.9%), 64 from 1,083,830 to 1,339,435 (+23.6%), and 128 from 1,337,247 to 1,475,692 (+10.4%). In my own rebuild the gap was wider, +32% to +50% across eight variants. At 32 colours the blurred copy of the source went from 572,768 to 861,321 bytes (+50.4%).

The lossy pass did not close that gap either. With gifsicle -O3 --lossy=N on the 256-colour rebuilds, the dithered file stayed 32.7% to 35.4% larger at lossy 30, 60 and 100, and 34.9% larger at 200. Lossy 200 saved about 22% on the plain 256-colour file, at the highest level I tried.

What the sample cannot settle

The first thing it cannot tell you is the size of the dither penalty. In the tool it ran from +36.9% at 32 colours down to +0.7% at 256 (1,525,126 against 1,535,115). My guess is that the source GIF is already at 256-colour level, so there was no error left for dithering to spread, but I did not test that.

The second is what "32 colours, dither off" costs, because that phrase named four different files in my runs: 811,310 from the tool, 625,102 and 572,768 from my two rebuilds, and 426,315 from gifsicle's own colour reduction on the original. They come from different palettes and different starting frames, so none of them can be ranked against another. The commands behind the last one:

$ gifsicle --info demo.gif | head -4
* demo.gif 10 images
  logical screen 675x599
  global color table [256]
  background 0
$ gifsicle -O3 --colors 32 --no-dither demo.gif -o demo_s.gif; stat -f%z demo_s.gif
426315
$ gifsicle -O3 --colors 32 -f demo.gif -o demo_s.gif; stat -f%z demo_s.gif
1005103
Enter fullscreen mode Exit fullscreen mode

Dither on versus off gave +135.8% in this gifsicle run and +50.4% in the Pillow rebuild at the same 32 colours, which says more about the pipeline than about dithering.

The third is why. Counting LZW output codes on four of the rebuilt files, dithering raised the code count by 50.3% at 32 colours, almost the same as the +50.4% in bytes, and the share of pixels equal to their left neighbour fell from 85.8% to 55.8%. That much I measured. Reading it as "the noise breaks up repeated pixel runs" is my explanation, and I did not run anything to prove it.

Last, the clip itself is a poor stand-in for most GIFs. Nearly every pixel changes in every frame, so frame differencing had nothing to save, and -O3 only trimmed tens to a few thousand bytes. It is not a screen recording or a flat-colour UI loop. I would not carry any of these percentages over to those.

What I would run on my own files

Take three of your real GIFs, not one. Export each at 256, 64 and 32 colours with dithering off and on, write down the byte counts, and zoom one frame to 10× to see whether the dithered version shows single-pixel noise where the plain one shows flat patches. If the dither-on column is not clearly larger for your content, the switch is not your problem, and frame count or dimensions are the next things to try.

For the byte counts I used the tool in a desktop browser, because it lets me set colour count and dithering by hand. In my capture, no request carried the file during compression. Phones and tablets only offer image compression there, so this is a desktop job.

Top comments (0)