Why Dithered Images Break Under JPEG and Video Compression
Dithering manufactures the exact high-frequency noise JPEG, video codecs, and PNG are built to discard. Here's the mechanism, real file-size numbers, and…
01/ ARTICLE
Why Does Dithering Break JPEG Compression?
Dithering turns a smooth gradient into a pattern that looks, pixel by pixel, like noise. JPEG's whole compression pipeline exists to find noise like that and throw it away. Except here it can't — the noise is the image. That's the entire conflict in one sentence, and it's why a dithered export that looks clean on your screen comes back from a JPEG re-save with torn, blocky edges and a file that's bigger than the one you started with.
JPEG works by splitting an image into 8x8 pixel blocks and running each one through a Discrete Cosine Transform, which re-expresses the block as a sum of cosine waves at increasing frequencies. That transform is lossless on its own — nothing gets thrown away yet. The loss happens a step later, in quantization: each frequency coefficient gets divided by a value from a quantization table and rounded, and low coefficients often round straight to zero. A coefficient of 5 divided by a quantization step of 6 becomes 0. On a photograph, that's a fine trade. Most of the visual information sits in the low frequencies, and the eye barely notices the high-frequency detail that gets rounded away.
Floyd-Steinberg dithering doesn't produce that kind of image. It works by pushing each pixel's rounding error onto its neighbors — 7/16 to the pixel on the right, 3/16 to the bottom-left, 5/16 to the bottom, 1/16 to the bottom-right — so every pixel's final value depends on the rounding history of every pixel processed before it. There's no low-frequency structure to speak of in the result. It's high-frequency by construction, and it doesn't repeat. Feed that into an 8x8 DCT block and there's nothing safe to round to zero. Quantization either leaves the block mostly untouched, which is expensive, or tears through it, which destroys the pattern — that's the ringing and blocking you can actually see at the block boundaries.
Dithering breaks JPEG compression because it manufactures the exact high-frequency signal the format is designed to discard, in a place where discarding it destroys the image instead of cleaning it up.
How Much Bigger Does a Dithered File Actually Get?
The honest answer: a lot. Worth seeing the real numbers before you treat dithering as a compression shortcut instead of a look.
| Test case | Format | Before dither | After dither + re-save | Change |
|---|---|---|---|---|
| Color photo | JPEG | 552 KB | 29.9 MB | +5,316% |
| B&W photo | JPEG | 3.50 MB | 16.4 MB | +369% |
| Color photo | Lossless WebP | 6.31 KB | 30.1 KB | +377% |
These figures come from a direct before/after test: a 552 KB color JPEG, dithered and re-saved as JPEG, ballooned to 29.9 MB. A 3.50 MB black-and-white JPEG grew to 16.4 MB under the same treatment. Lossless PNG survives better than JPEG — nothing's tearing the pattern's structure apart via quantization — but it isn't free either. Only one of four test images in that same benchmark actually came out smaller after dithering, because the entropy dithering adds resists LZ-style lossless compression too. Just less catastrophically. Even a lossless WebP export, generally the strongest option here, still came in 377% larger dithered than plain.
Dithering was never a file-size strategy. The moment you run it through any general-purpose compressor, you're paying for the aesthetic choice twice: once in visual damage, once in bytes.
Does the Dithering Algorithm Change How Badly It Compresses?
Not every dither pattern fails the same way. The difference comes down to whether the pattern has structure a compressor can actually find.
Error-diffusion dithering has effectively zero repeating structure. Floyd-Steinberg is the classic example, and Atkinson (kott's other core diffusion algorithm) follows the same logic with a lighter error fraction. Every pixel's value depends on a chain of prior rounding decisions, so there's no pattern for a compressor to exploit — the worst case for any general-purpose codec, lossy or lossless. See our Floyd-Steinberg vs ordered dithering comparison for the full visual and settings breakdown, and Atkinson dithering's exact settings for the threshold math.
Ordered dithering with a Bayer matrix works differently. The threshold at each pixel comes from a fixed matrix tied to pixel position, not pixel history, so the pattern has real, repeating structure — a small matrix repeats every 2 or 4 pixels — and a lossless compressor can actually use that. A 4x4 Bayer matrix (values 0-15, threshold computed as (bayerValue / 15.0) * 255.0) produces an obvious, low-detail grid that's cheap to describe. A 16x16 matrix gives smoother tonal steps, but it adds back the kind of fine high-frequency detail that's expensive to preserve — closer, in compression terms, to error diffusion than to a 4x4 grid.
The trade a designer is actually making isn't "dithering vs no dithering." It's matrix size and tonal-level count against file size and pattern visibility. A coarser, smaller matrix costs less no matter what compresses it downstream.
Why Do Dithered Videos Get Worse Than Dithered Stills?
Block-based video codecs — H.264, H.265, the MPEG family — inherit the same quantization logic as JPEG. Video adds a second failure mode on top of it: motion.
Dithering pre-encode is a known technique for hiding banding in smooth gradients under low-bitrate video compression. It turns a hard tonal step into spatial grain, which the eye reads as smooth instead of stepped. That's a real fix, right up until the bitrate budget gets tight enough to have caused the banding in the first place. At that point the codec's own quantization re-attacks the grain it's now looking at, and you're back to blocking and banding — on top of a noisier source, at a higher bit cost than the plain gradient would have needed.
Error-diffusion dithering makes this worse in a way that's specific to video: the pattern crawls. Every pixel's error depends on its neighbors, so a tiny brightness change from frame to frame — camera noise, a slight exposure shift, compression artifacts from a prior encode — can send the diffusion path through an entirely different sequence of pixels. The codec's motion estimation reads that shifting pattern as motion and spends bits encoding it, even though nothing in the actual scene moved. Ordered dithering's fixed, position-based pattern doesn't do this. It holds still because it was never derived from pixel history in the first place. Our dithering-in-motion breakdown covers the frame-stability settings in full if video is the actual target.
What's the Fix?
None of this means avoid dithering. It means treat compression order and format choice as part of the setting, not an afterthought.
Dither last, and dither directly into a lossless or dithering-tolerant format — PNG, GIF, or lossless WebP. Never let a dithered export take a JPEG pass afterward; the quantization step is what destroys the pattern and inflates the file at the same time. If file size still matters after that, the real lever is a smaller Bayer matrix or fewer tonal levels, not a lossy re-compression pass. A coarser regular pattern is genuinely cheaper. "Just compress it more" only makes things worse. And for anything that will be recorded, streamed, or re-encoded downstream, favor ordered dithering over error diffusion — the fixed pattern survives a second or third encode far more predictably.
Frequently Asked Questions
Does dithering always make a file bigger?
Almost always once a lossy or LZ-family compressor touches it. Dithering replaces smooth gradients with a pixel-level pattern that reads as high-frequency noise, and both JPEG's DCT quantization and PNG's LZ-style compression are built to exploit redundancy that dithering deliberately removes. Lossless formats survive better than JPEG but still usually grow.
Should I dither before or after compressing an image?
After, or not at all in the lossy path. Dither only the final export at the last possible step, directly into a lossless or dithering-aware format (PNG, GIF, WebP lossless). If a JPEG pass happens after dithering, the quantization step destroys the pattern's structure and inflates the file at the same time.
Does Floyd-Steinberg or ordered (Bayer) dithering compress better?
Neither compresses well, but ordered dithering with a small matrix (2x2 or 4x4) produces a more regular, lower-entropy pattern that lossless compressors handle slightly better than Floyd-Steinberg's error-diffusion noise, which has no repeating structure at all. Neither should go through a lossy JPEG pass.
Why do dithered videos look worse than dithered still images after upload?
Video platforms re-encode with block-based codecs (H.264, H.265) at a bitrate budget. Error-diffusion dithering also crawls frame to frame — a tiny brightness shift can send a completely different error path through the frame — which the codec reads as motion, spending bits it doesn't have. Ordered dithering holds a fixed pattern and survives re-encoding more predictably.
What's the fix if I need a dithered look on the web?
Export dithered images as PNG or lossless WebP, never JPEG. If file size matters, drop to a smaller Bayer matrix or reduce the dither's tonal levels before generating it — a coarser regular pattern compresses better than a fine error-diffusion one, and it never has to survive a DCT pass at all.
The Takeaway
Dithering and mainstream compression work against each other by design. One manufactures high-frequency signal; the other exists to discard high-frequency signal. Force them into the same pipeline in the wrong order and you get either a wrecked pattern or a file five thousand percent bigger than you expected. The fix isn't avoiding dithering — it's ordering the pipeline correctly and picking a matrix size that matches what you're willing to pay for. Test a matrix size and threshold against your own source in kott — no export needed to see where it breaks.
02/ OUT
Every setting described above is a real control. Open your own image and sweep it.
All journal entries